业务背景
跟第三方系统做对接,双方通过ActiveMQ进行通信,消息之间是有内在关联的,也就是消息本来应该是有业务顺序的,但由于一些原因,现在收到消息是乱序的,这种情况下做业务处理就有一点小问题了
方案一:自己重排序
收到消息后,自己在内存排序,然后按顺序丢到队列中,自己控制消息的发送和接收保证收到按发送的顺序来收到消息。
如果自己排序的话就要对每个消息标记一个顺序,同时还要指定预先定义好哪些消息属于一类并且相互之间有依赖顺序。
具体实现的话,可以这样做:
1、收到一条消息,封装一下加个序号,放到Redis中,用列表或者有序集合来存储,同时用字符串类型存一下这个业务单号的当前最小序号(默认是1)
2、如果是用有序集合存的话,用序号当做分数,这样消息丢进去就已经排好序了,每次用最小分数的那个元素和当前最小序号比较,如果小于或等于,则删除这个元素,将它发送到MQ,同时最小序号加1
3、如果用列表存的话,可以lpush添加,lrange查最先放进去的那个元素,和当前最小序号比较,小于或等于,则rpop删除,发MQ,最小序号加1
大概就是这么个意思,以上是我的思路,没有实现,感觉应该是可行的
方案二:定时任务扫描
1、收到消息后,先存到数据库中,这条记录的状态为“未消费”
2、进行业务处理
(1)如果处理这条消息不需要依赖其它的消息,或者它依赖的消息已经先于它被处理了,那么直接做业务处理,完成后更新消息记录表,将这条记录的状态置为“已处理”
(2)如果这条消息依赖的消息还没有收到(通常表现为可能是某个表的数据状态不对或者没有数据,等等),则不处理
3、定时任务扫描消息记录表,找到那些状态为“未处理”的数据,调用统一的消息处理接口,依次执行,逻辑同上
举个例子,
假设某个业务场景会收到5个消息,顺序假设为1、2、3、4、5
最极端的情况,假设先收到5,存表,暂不处理
再收到4,存表,暂不处理
3,存表,暂不处理
2,存表,暂不处理
1,存表,立即处理,更新状态“已处理”
定时任务第一次扫描,2会被处理,更新状态“已处理”
第二次扫描,3会被处理,更新状态“已处理”
第三次扫描,4会被处理,更新状态“已处理”
第四次扫描,5会被处理,更新状态“已处理”
至此,所有消息都按顺序被处理完了