一、你们使用什么MQ?基于什么做的选型?
我们主要调研了几个主流的mq,kafka,rabbitmq,rocketmq,activemq,选型我们只要基于以下几个点去考虑:
(1)由于我们系统的qps压力比较大,所以性能首要考虑的要素
(2)开发语言,由于我们的开发语言java,主要是为了方便二次开发
(3)对于高并发的业务场景是必须的,所以需要支持分布式架构的设计
(4)功能全面,由于不同的业务场景,可能会用到顺序消息、事务消息等
基于以上几个考虑,我们最终选择了RocketMQ。
| Kafka | RocketMQ | RabbitMQ | ActiveMQ |
单机吞吐量 | 10万级 | 10万级 | 万级 | 万级 |
开发语言 | Scala | Java | Erlang | Java |
高可用 | 分布式架构 | 分布式架构 | 主从架构 | 主从架构 |
性能 | ms级 | ms级 | us级 | ms级 |
功能 | 只支持主要的MQ功能 | 顺序消息、事务消息等功能完善 | 并发强、性能好、延时低 | 成熟的社区产品、文档丰富 |
二、消息丢失有哪些场景?消息可靠性怎么保证
消息丢失可能发生在生产者发送消息、MQ本身丢失消息、消费者丢失消息3个方面。
(1)生产者丢失
生产者丢失消息的可能点在于程序发送失败抛异常了没有重试处理,或者发送的过程成功但是过程中网络闪断MQ没收到,消息就丢失了。
由于同步发送的一般不会出现这样使用方式,所以我们就不考虑同步发送的问题,我们基于异步发送的场景来说。
异步发送分为两个方式:异步有回调和异步无回调,无回调的方式,生产者发送完后不管结果可能就会造成消息丢失,而通过异步发送+回调通知+本地消息表的形式我们就可以做出一个解决方案。以下单的场景举例:
1)下单后先保存本地数据和MQ消息表,这时候消息的状态是发送中,如果本地事务失败,那么下单失败,事务回滚。
2)下单成功,直接返回客户端成功,异步发送MQ消息
3)MQ回调通知消息发送结果,对应更新数据库MQ发送状态
4)JOB轮询超过一定时间(时间根据业务配置)还未发送成功的消息去重试
5)在监控平台配置或者JOB程序处理超过一定次数一直发送不成功的消息,告警,人工介入。
(2)MQ丢失
如果生产者保证消息发送到MQ,而MQ收到消息后还在内存中,这时候宕机了又没来得及同步给从节点,就有可能导致消息丢失。
RockerMQ分为同步刷盘和异步刷盘两种方式,默认的是异步刷盘,就有可能导致消息还未刷到硬盘上就丢失了,就可以通过设置为同步刷盘的方式来保证消息可靠性,这样即使MQ挂了,恢复的时候也可以从磁盘中去恢复消息。
(3)消费者丢失
消费者丢失消息的场景:消费者刚收到消息,此时服务器宕机,MQ认为消费者已经消费,不会重复发送消息,消息丢失。
RocketMQ默认是需要消费者回复ack确认。消费方不返回ack确认,重发的机制根据MQ类型的不同发送时间间隔、次数都不尽相同,如果重试超过次数之后会进入死信队列,需要手工来处理了。
三、消息挤压怎么处理
因为考虑到消费者消费一直出错的问题,那么我们可以从以下几个角度来考虑:
(1)消费者出错,肯定是程序或者其他问题导致的,如果容易修复,先把问题修复,让consumer恢复正常消费
(2)如果时间来不及处理很麻烦,做转发处理,写一个临时的consumer消费方案,先把消息消费,然后再转发到一个新的topic和MQ资源,这个新的topic的机器资源单独申请,要能承载住当前挤压的消息
(3)处理完挤压数据后,修复consumer,去消费新的MQ和现有的MQ数据,新MQ消费完成后恢复原状
四、RocketMQ实现原理
RocketMQ由NameServer注册中心集群、Producer生产者集群、Consumer消费者集群和若干Broker(RocketMQ进程)组成,它的架构原理是这样的:
(1)Broker在启动的时候去向所有的NameServer注册,并保持长连接,每30s发送一次心跳
(2)Producer在发送消息的时候从NameServer获取Broker服务器地址,根据负载均衡算法选择一台服务器来发送消息
(3)Consumer消费消息的时候同样从NameServer获取Broker地址,然后主动拉取消息来消费