消息队列是如何保证高可用的?
可靠性保证
已RocketMQ为例:
集群为多master模式
多master多slave异步复制模式
多master多slave同步复制模式
NameServer类似于kafka的zk,起到master和slave的注册和发现。 Producer和NameServer集群的随机一点建立长链接,定期从NameServer获取Topic路由信息,并向Topic服务的Broker Master建立长链接,且定时向Broker发送心跳。
Producer发送消息到Broker master,Consumer可以从Topic的Master和Slave的broker订阅消息。
对比看下kafka的架构图:
通过zk管理集群配置,选举leader及对consumer group进行rebalance。 consumer可以采用pull和push方式订阅消息。
RabbitMq可以通过普通集群和镜像模式进行可用性保证。
消息重复消费
不同的MQ有不同的消费机制,ack之后消息会从消息队列中删除。 造成重复消费的原因可能有以下几点:
网络传输故障
消息确认没有返回队列服务端
业务上的解决:
如果数据库消费,可以建立唯一约束,避免脏数据
引入redis做幂等查询
消息的可靠性传输
可靠性从以下几个调度考虑:
生产者丢数据
消息队列丢数据
消费者丢数据
RabbitMq的transaction机制,在发送消息之前,开启事务,然后发送消息,如果出现异常进行回滚,发送成功执行commit。
信道发出去的消息会被指派一个唯一ID,消息路由到队列后,队列会返回Ack信息其中包含唯一ID,打到确认目的,如果没能处理此消息,会返回NAck,之后进行重试操作。
队列为防止丢数据,一般开启磁盘持久化,可以在confirm持久化磁盘后返回ack,这样保证了消息的持久化。
queue设置为durable为true,表示持久化队列
发送消息时将deliveryMode = 2
消费者可以采用自动确认模式,确认后立即删除,为解决丢失数据后,重复消费,可以关闭自动确认,采用手动确认。
producer发送消息到partition后,通过zk找到partition的leader,leader写入本地log,follower主动从leader来pull数据。
可以配置produder的acks=all,这样需要follower同步后才确认消息发送成功。 producer设置retries=MAX,写入失败后会进入无限重试。
kafka消费主要依赖于offset,每个消费组消费的消息都有唯一的offset下标,消费者消费后提交offset。
消息顺序性
业务上一般没有这类需求,一般可以采用将消息放到一个信道里面,kafka的partiton,rabbitMq的queue,然后控制消费者顺序消费。
领取专属 10元无门槛券
私享最新 技术干货