基于redis stream实现一个可靠的消息队列

文章介绍了如何使用Redisson库实现类似Kafka的消费者组机制,通过XREADGROUP命令获取队列中的消息,并讨论了消息确认(XACK)和未确认消息的补救(XPENDING和XCLAIM)。此外,还提到了内存管理策略,包括使用lua脚本进行流的定时清理,以及处理PEL(待确认消息列表)中的垃圾数据问题。

我们使用的库为redisson。
添加元素到队列很简单,用RStream.add方法即可。

如何从队列获取元素?由于我们打算实现kafka那样的consumer group机制,所以,读操作要用RStream.readGroup函数(XREADGROUP命令),该命令有阻塞和非阻塞版本,简单起见,我们使用非阻塞版本(不带BLOCK参数),由应用层来定时轮询。Id参数我们设置为StreamReadGroupArgs.neverDelivered(),相当于redis命令里的>,每次只取最新的消息。相关的代码样例如下:

public List<Record> poll(String groupName, String consumerName) {
   
   
    return toConsumerRecords(redisMsgQueue.readGroup(groupName, consumerName, StreamReadGroupArgs.neverDelivered()));
}

追求可靠性,则须封装XACK命令。引入ACK之后,自然要考虑对那些ACK超时的消息如何补救。为此,我们要结合XPENDING和XCLAIM两条命令,利用前者查出目前尚未ACK的消息集M(术语叫PEL,pending entry list),利用后者将M中已超时的那部分(通过min-idle-time参数过滤)分配给其它存活的consumer去做补救处理。为何XPENDING出来之后要做XCLAIM呢?主要是我们希望做补救处理的consumer只能有一位,XCLAIM命令在多consumer竞争时能保证独占性,从而避免消息的多次处理。XPENDING遍历PEL也是有技巧的,一是要分批获取,二是由于XPENDING的startId和endId是闭区间, 需将用于遍历的cursor Id转成开区间(参考redis的streamId说明,具体做法是将streamId的sequence部分加1)。参考实现如下:

public List<Record> fetchNotAck(String groupName, String consumerName, long ackTimeout
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值