最近工作中,涉及到的一些解决方案,发现引入消息队列会更好更优雅地解决问题。
业务场景:用户新装修的店铺发布后,需要相关系统做一些对应的工作:缓存系统做数据清理,通知依赖的第三方系统...
当前解决方案:店铺发布系统异步编码实现相关逻辑;
现实问题:1、采用第三方系统提供接口供店铺系统发送通知:店铺系统需要处理通知发送成功、失败、无响应等逻辑,需要考虑通知是否一定要发送成功才能进行下一步;2、不通知,直接将第三方系统的逻辑直接编码但了店铺店铺系统:代码侵入,此段逻辑缺乏上下文,很难维护;3、每增加一个对店铺发布事件有兴趣的业务方,系统都需要增加编码逻辑,店铺系统被第三方系统侵入(非常大的问题);4、基于以上问题,很对第三方都是采用定时更新的方案,容忍一定时间段内的不一致;
新方案:引入消息队列,店铺发布后生成店铺发布事件;相关方订阅店铺发布事件主题,实现自己相关业务逻辑;
优势:1、店铺系统只和消息队列交互,简化了店铺系统的相关编码逻辑,能更快地返回;2、第三方系统的代码放到了第三方系统内部;3、新增加业务方,只需业务方订阅,编写相关逻辑即可,实现了系统解耦(非常重要的改进);4、系统不一致的时间大大缩短;
消息中间件的一些思考:
好处:系统解耦;异步,并发,加速业务流程处理;通过消息系统的高可靠性,在不增加系统编码复杂行的前提下保证消息的高可靠性:如果两个系统直接交互,发送方需要编码处理发送成功、失败、无响应等等各种情况,有消息中间件的情况下,发送方在消息发送中间件成功的情况下,消息的可达性由中间件保证;
需要解决的问题:可靠性,消息堆积不丢失,单队列风险;消息延时问题;消息重复、乱序问题;消息送达consumer方式;消息队列和producer、consumer集群发生了关联,不能对彼此 的集群扩容造成影响;系统集群内的应用都订阅事件,导致系统重复收到消息;消息如何送达consumer;
可靠性:consumer消费能力不足、宕机等情况导致消息堆积,raid磁盘整列保证单磁盘的数据安全性,冗余磁盘避免单点风险;冗余队列、异步复制避免单队列风险;集群避免单机风险;
消息延时:很多场景下,这都不是问题;如果是,那么考虑是否能在接受最终一致性的前提下,容忍一定时间段内中间状态的不一致;是否可以重新设计;
消息重复:消息发送失败或无响应,一般都会重发,从而导致重复。1、消费者幂等,此时基本不需要解决重复问题;2、消息添加全局唯一id,消费者自己去重,会增加业务流程响应时间;
消息乱序:有序消息好处:逻辑简单;问题:维护有序性是付出代价的,最简单的情况下,只能由单一的producer在发送成功消息1时再发送消息2,消息队列只能往同一个consumer按序发送消息1、消息2,极大限制了系统负载能力,即使参考tcp后的优化方案:单一producer并行发送带排序号的消息1、消息2,单一consumer方组合,仍然受单机限制;再分别通过producer和consumer内容的集中式存储,优化为多producer、多consumer,编码难度和负载能力仍然不是最理想。说了这么多,其实就是想把有序的方案,在保证最终一致性的前提下变为无序。现实中,至少80%以上是无序的。
扩容:消息队列可对集群提供分类管理,为不同的consumer、producer集群提供groupId;
集群重复收取消息:每个集群分配一个groupId,每条消息只往一个groupId发送一次;
消息送达consumer:主动推送,低延迟;consumer主动拉取,频度很难控制,太频繁浪费消息系统资源,偶尔又有高延时;consumer发起询问,如果有,发送,双倍交互次数;