订阅一致性的可能情况以及处理方案
订阅关系一致指的是同一个消费者 Group ID 下所有 Consumer 实例的处理逻辑必须完全一致。一旦订阅关系不一致,消息消费的逻辑就会混乱,甚至导致消息丢失
保持订阅关系一致意味着同一个消费者 Group ID 下所有的实例需在以下两方面均保持一致
订阅的 Topic 必须一致
订阅的 Topic 中的 Tag 必须一致
错误情况:
- 同一个 Group ID 下的两个实例订阅的 Topic 不一致
- 同一个 Group ID 下订阅 Topic 的 Tag 不一致。Consumer 实例 1 订阅了 TagA,而 Consumer 实例 2 未指定 Tag
- 同一个 Group ID 下订阅 Topic 个数不一致/同一个 Group ID 下订阅 Topic 的 Tag 不一致
我的错误:同一个Group和同一个Topic, 由于tag不同。 所以采取了两个消费者实例去分别消费消息,然后控制台会出现
/**
* 错误处理方式
*/
/**
* tag消息订阅
* @param merchantPersonalService
* @return
*/
@Bean(initMethod = "start",destroyMethod = "shutdown")
public ConsumerBean getMerchantBindingBankCardConsumer(MerchantPersonalService merchantPersonalService){
ConsumerBean consumerBean = new ConsumerBean();
Properties properties = new Properties();
properties.put(PropertyKeyConst.GROUP_ID, merchantBankCardGroupId);
// AccessKey 阿里云身份验证,在阿里云服务器管理控制台创建
properties.put(PropertyKeyConst.AccessKey, accessKey);
// SecretKey 阿里云身份验证,在阿里云服务器管理控制台创建
properties.put(PropertyKeyConst.SecretKey, secretKey);
// 设置 TCP 接入域名,进入控制台的实例管理页面的“获取接入点信息”区域查看
properties.put(PropertyKeyConst.NAMESRV_ADDR, namesrvAddr);
consumerBean.setProperties(properties);
//组装订阅者消息
Map<Subscription, MessageListener> map = new HashMap<Subscription, MessageListener>();
Subscription subscription = new Subscription();
//绑定商户银行卡信息mq的topic和tag
subscription.setTopic(merchantBankCardTopic);
subscription.setExpression(merchantBankCardBindTag);
map.put(subscription, new AddBindingBankCardConsumerListener());
consumerBean.setSubscriptionTable(map);
return consumerBean;
}
/**
* tag2消息订阅
* @param merchantPersonalService
* @return
*/
@Bean(initMethod = "start",destroyMethod = "shutdown")
public ConsumerBean getMerchantBankUntyingConsumer(MerchantPersonalService merchantPersonalService){
ConsumerBean consumerBean = new ConsumerBean();
Properties properties = new Properties();
properties.put(PropertyKeyConst.GROUP_ID, merchantBankCardGroupId);
// AccessKey 阿里云身份验证,在阿里云服务器管理控制台创建
properties.put(PropertyKeyConst.AccessKey, accessKey);
// SecretKey 阿里云身份验证,在阿里云服务器管理控制台创建
properties.put(PropertyKeyConst.SecretKey, secretKey);
// 设置 TCP 接入域名,进入控制台的实例管理页面的“获取接入点信息”区域查看
properties.put(PropertyKeyConst.NAMESRV_ADDR, namesrvAddr);
consumerBean.setProperties(properties);
//组装订阅者消息
Map<Subscription, MessageListener> map = new HashMap<Subscription, MessageListener>();
Subscription subscription = new Subscription();
//解绑商户银行卡信息mq的topic和tag
subscription.setTopic(merchantBankCardTopic);
subscription.setExpression(merchantBankCardUntyingTag);
map.put(subscription, new UntyingBankCardConsumerListener());
consumerBean.setSubscriptionTable(map);
return consumerBean;
}
/**
* 正确处理方式
*/
/**
* 同一个Group和同一个Topic, tag不同的消息订阅()
* @param
* @return
*/
@Bean(initMethod = "start",destroyMethod = "shutdown")
public ConsumerBean getMerchantBindingBankCardConsumer(){
ConsumerBean consumerBean = new ConsumerBean();
Properties properties = new Properties();
properties.put(PropertyKeyConst.GROUP_ID, merchantBankCardGroupId);
// AccessKey 阿里云身份验证,在阿里云服务器管理控制台创建
properties.put(PropertyKeyConst.AccessKey, accessKey);
// SecretKey 阿里云身份验证,在阿里云服务器管理控制台创建
properties.put(PropertyKeyConst.SecretKey, secretKey);
// 设置 TCP 接入域名,进入控制台的实例管理页面的“获取接入点信息”区域查看
properties.put(PropertyKeyConst.NAMESRV_ADDR, namesrvAddr);
consumerBean.setProperties(properties);
//组装订阅者消息
Map<Subscription, MessageListener> map = new HashMap<>();
Subscription subscription = new Subscription();
//绑定商户银行卡信息mq的topic和tag
subscription.setTopic(merchantBankCardTopic);
subscription.setExpression(merchantBankCardBindTag+ "||" + merchantBankCardUntyingTag);
map.put(subscription, addBindingBankCardConsumerListener);
consumerBean.setSubscriptionTable(map);
return consumerBean;
}