大厂的MQ组件实现思路和架构设计方案
集群之间通过Federation插件进行数据同步。
MQ组件主要实现功能点:
1.支持消息高性能的序列化转换,异步化发送消息
2.支持消息生产实例与消费实例的链路池化缓存化,提升性能
3.支持可靠性投递,保障消息的100%不丢失
4.支持消费端的幂等操作,避免消费端重复消费的问题
5.支持迅速消息发送机制,在一些日志收集/统计分析等需求下可以保证高性能,超高吞吐量
6.支持延迟消息模式,消息可以延迟发哦是那个,指定延迟时间,用于某些延迟检查,服务限流场景
7.支持事务消息,且100%保障可靠性投递,在金额行业单笔大金额操作时会有此类需求
8.支持顺序消息,保证消息送达消费端的前后顺序,例如下订单等复合性操作
9.支持消息补偿,重试,以及快速定位异常/失败消息
10.支持i集群消息负载均衡,保障消息落到具体SET集群的负载均衡
11.支持消息路由策略,指定某些消息路由到指定的SET集群
基础组件封装设计-迅速消息发送
迅速消息指消息不进行落库存储,不做可靠性的保障,在一些非核心消息,日志数据,或者统计分析等场景下比较合适,迅速消息的优点就是性能最高,吞吐量最大。
基础组件封装设计-确认消息发送
基础组件封装设计-批量消息发送
批量消息指把消息放到一个集合里面统一进行提交,这种方案设计思路是期望消息在一个会话里,比如投掷到threadlocal里的集合,然后拥有相同会话ID,并且带有这次提交消息的SIZE等相关属性,最重要的一点是要把这一批消息进行合并。对于Channel而言,就是发送一次消息。这种方式也是希望消费端在消费的时候,可以进行批量化的消费,针对于某一个原子业务的操作去处理,但是不保障可靠性,需要进行补偿机制。
基础组件封装设计-延迟消息发送
延迟消息相对简单,就是在Message封装的时候添加delayTime属性即可,使得消息可以进行延迟发送,根据具体的业务场景也可以很好的使用得到。
场景举例:
在电商平台买商品签收后,不点击确认支付,那么系统自动会在7天去进行支付操作。
自动超时作废的场景,优惠卷/红包有使用时间限制,也可以用延迟消息机制。
基础组件封装设计-顺序消息发送
顺序消息比较类似于批量消息的实现机制。我们需要保障一下几点:
1.发送的顺序消息,必须保障消息投递到同一个队列,且这个消费者只能有一个(独占模式)。
2.需要统一提交,并且所有的会话ID一致。
3.添加消息属性:顺序标记的序号,和本次顺序消息的SIZE属性,进行落库操作。
4.并行进行发送给自身的延迟消息(注意带上关键属性:会话ID,SIZE)进行后续处理消费。
5.当收到延迟消息后,根据会话ID,SIZE抽取数据库数据进行处理即可。
6.定时轮询补偿机制,对于异常情况。
备注:比如生产端消息没有完全投递成功,或者消费端数据落库异常导致消费端落库后缺少消息条目的情况
基础组件封装设计-事务消息发送
事务消息相对使用较少,比如单笔转账超过一个上限的时候,我们就希望这个消息优先级最高,并且可靠性要求达到100%,所以才会有一些补偿机制,主动发起银行端查询指令机制等。如果使用传统的RabbitMQ事务和Spring集成的机制会非常消耗系统资源且出现阻塞等情况,在高峰期也是一定程度上影响MQ集群的性能。
解决方案:采用类似可靠性投递的机制,也就是补偿机制,在保证数据源一致,业务库和消息库使用统一数据源,然后利用重写Spring DataSourceTransactionManager,在本地事务提交的时候进行发送消息,但是也有可能事务提交成功但是消息发送失败,这个时候就要进行补偿了。
DataSourceTransactionManager核心代码:
消息幂等性保障-消息路由规则架构设计
可能导致消息出现非幂等的原因:
1.可靠性消息投递机制:消费端返回confirm时候发生闪断,生产端没有收到ACK,会发送2次消息
2.MQ Broker服务与消费端传输消息的过程中的网络抖动:消费端给Broker服务消息过程中闪断
3.消费端故障或异常
消息幂等性的设计: