相同点: 高可用,消息不丢。
差异:
ActiveMQ:单机吞吐量 每秒万级,偶尔丢消息,社区不活跃。RabbitMQ:吞吐量万级,管理界面很好,低时延,社区活跃,基于erLang开发,不易维护。适合中小型公司。RocketMQ:吞吐量十万,性能很好,分布式扩展性好。适合大型公司。Kafka:吞吐量十万,实时计算,日志采集,易于扩展。适合大数据计算。RabbitMQ:镜像复制,每个节点存储所有的元数据与消息 Kafka:多broker、多分区(leader,follower、选举机制)保证
消费者消费完某条消息后宕机,此时未上报偏移量。消费者重启后再次拉取消息,即拉取了之前的消息,此时需要消费者自身保证幂等性。
1、消息给予唯一标识id,处理(如入库)前,需要先判断之前处理的消息key的缓存中是否包含该key,即之前是否处理过该消息,处理过则不重复处理。 2、根据业务灵活选用其他方案。如入库场景,可以使用主键的唯一性维护等。
详细参考: RabbitMQ之消息确认机制(事务+Confirm)
以下从三个角度考虑该问题
网络故障、MQ故障无法接收数据
需要生产者感知消息是否被MQ接收到,失败则重试。两种方式:
生产者同步发送消息,失败则重试(简单易行,但是吞吐量会降低)生产者异步发送消息,Confirm机制保证事务,MQ接收到消息后,通知生产者,生产者根据具体消息做出相应网络故障、MQ故障无法接收数据、分区进行主备切换(leader收到消息后挂了,数据未同步到follower,选举leader后新的leader丢失了数据)
每个分区有多个副本,消息在写入所有分区后才认为写入成功,写入失败就一直重试。 需要设置4个参数:
给这个topic设置replication.factor参数,这个值必须大于1,要求每个分区(partition)至少有2个副本在Kafka服务端设置min.insync.replicas参数:这个值必须大于1,这个要求一个leader必须有至少感知到有一个follower还跟自己联系,没掉队,这样才能保证leader挂了还有一个follower在producer端设置acks=all:这个是要求每条数据,必须是写入replica之后,才能认为是写成功了。在producer端设置retries=MAX:要求一旦写入失败,就无限重试,卡在这里了。消息在内存中,或消息过期被丢弃
消息永久不过期,消息持久化到磁盘中。具体步骤大概是:
创建queue的时候将其设置为持久化的,这样可以保证RabbitMQ持久化queue中的元数据,但是不会持久化queue里面的数据发送消息时将消息的deliveryMode设置为2,将消息设置为持久化,此时RabbitMQ就会把消息持久化到磁盘,这样RabbitMQ挂了,重启后也能从磁盘恢复queue的数据详细参考: RabbitMQ消息持久化
消息在内存中,或消息过期被丢弃
消息永久不过期,消息持久化到磁盘。每个分区有多个副本,保证高可用。
消费者未真正消费完消息,就把消费记录上报给MQ,这样消费者挂掉后重启,会从后面的消息偏移量开始消息,则未真正消费的数据就丢失了。
关闭autoACK,不进行消息的偏移量自动提交,真正消费完消息才提交消费偏移量
一个queue,多个consumer,明显会乱序
生成消息指定key,保证需要保证有序的消息被分配到同一个分区,Kafka的一个分区对应一个消费者消费,所以能保证有序。但是,一个消费者往往内部有多线程处理消息,这样就乱序了。
消费者中使用多个内存队列,一个线程对应一个内存队列进行消费。保证需要有序的的消息维护在同一个内存队列,这样就能保证消费的有序性。
需要临时紧急扩容,具体步骤:
先恢复consumer的问题,确保其恢复消费速度,然后将现有consumer都停掉新建一个topic,partition数量扩展为原来的10倍,临时建立好原来10倍或20倍的queue数量然后写一个临时的分发数据的consumer程序,这个程序部署上去消费积压的数据,消费之后不做耗时的业务处理,直接均匀轮询写入临时建立好的10倍数量的queue接着使用10倍的机器来部署consumer,每一批consumer消费一个临时queue的数据这种做法相当于临时将queue和consumer资源扩大10倍,以正常10倍速度消费积压数据如果当前磁盘已经快爆掉,也可以临时丢弃数据,使用工具收集丢弃的数据,等凌晨再补上数据了相关: 中华石杉-高性能专题(MQ、Redis、ES)
