RocketMQ-订阅一致及解决方案

背景

这里借用Rocketmq官方的一句话来描述订阅关系一致: 

订阅关系一致指的是同一个消费者分组Group ID下,所有Consumer实例所订阅的Topic和Tag必须完全一致。如果订阅关系不一致,可能导致消息消费逻辑混乱,消息被重复消费或遗漏。

具体的问题和实例请看阿里云关于Rocketmq订阅关系一致的说明 ,里面写的非常详细,这边主要是讨论一下关于经典的会出现的一个订阅不一致问题。

当前问题

我司由于历史问题,java侧服务mq使用泛滥,每多一个topic订阅就伴随着新建一个group,导致维护成本越来越高,所以我们在2.0 sdk第一版即支持 【一个消费group消费多个topic】,也就是如下面这张图的预期:
在这里插入图片描述
看起来没有问题,RocketMQ官方也支持多topic的订阅逻辑,我们也是这么去推动大家升级的。但是随着对MQ的深入了解,逐渐发现一个很可怕的问题: 如果一个正在使用的group我希望去对它进行订阅关系的变更(添加/删除topic订阅),这个是绝对没有办法走灰度发布的!因为它会直接出现

RocketMQ领域经典的订阅不一致问题,详情见下图(模拟了一个使用中的group变更订阅关系时的灰度发布过程)
在这里插入图片描述
由图中可知,当前sdk虽然支持了一个group监听多个topic,但是这仅限于新业务,一个全新的group才可以在一开始用这种方式去升级,但却没有办法支持后续的订阅关系变更,看起来之前的sdk升级没什么用,可扩展性太差。如果消息的收发都是新业务还好一点,假如是订阅一个发送量非常大的现有topic,一发版就会喜提告警,严重的会存在消息丢失的风险,并且无法回放。

解决方案

其实问题的关键在于: 每个客户端虽然知道其他客户端的存在,但是并不知道大家的订阅关系,就导致了在实际平衡的时候产生【我觉得他应该去消费这些队列】的错觉,所以解决问题的关键就是我们只要让每个客户端都知道整个group集群中所有客户端的订阅关系就行了。参考之前发表的rocketmq灰度方案,可以利用ClientId的特性,将当前客户端的订阅关系加密追加在ID后面。

public String buildMQClientId() {
   
   
        StringBuilder sb = new StringBuilder();
        sb.append(this.getClientIP());
 
        sb.append("@");
        sb.append(this.getInstanceName());
        if (!UtilAll.isBlank(this.unitName)) {
   
   
            sb.append("@");
            sb.append(this.unitName);
        }
 
        if (enableStreamRequestType) {
   
   
            sb.append("@");
            sb.append(RequestType.STREAM);
        }
        # 关键在于下面这几行代码
        MessageInstance instance = MessageStorage.getInstance(this.getInstanceName());
            if (instance != null) {
   
   
                sb.append("#");
                sb.append(MessageStorage.generateInstanceSubInfoEncode(instance));
            } else {
   
   
                sb.append("#[]");
            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值