如何保证消息队列的高可用(HA)
NSQ 本身就是一个分布式消息队列,且支持水平扩展,无单点故障,能在无中断的情况下无缝添加集群结点。
nsq用到了集群去保证整个服务的高可用,但并不能保证单个topic的高可用,不过你可以用特定方案间接去保证。
【注】producer 指定在某台nsqd节点发送生产 topic-channel 数据, 也就只有那一台nsqd有这个数据了,其它节点是没有任何感知的,这里的重点就是,这台nsqd一旦挂了,未持久化或持久化失败的消息就可就真丢了,这跟你部署N台nsqd节点都没关系,因为并没有各节点相互备份。
有赞设计
- 增加多副本机制,每个Topic 有Leader 和 Follower, 进行相互备份。
- Leader 和 Flower 之间增加选主机制(借鉴Kafka)
- 加入 Etcd 组件
- 消息的持久化
- 客户端(Smart Client)的负载均衡
如何保证消息不被重复消费
NSQ 不能保证消息的幂等性,需要应用层进行处理,比如搞唯一约束。
如何保证消息的可靠传输
-
消息在生产者到NSQD 的传输过程中丢失
如果NSQD收到一条生产者消息,会返回一个
OK
的标识符,应用可以根据该标识进行重发处理。 -
NSQD丢失了数据
开启持久化数据选项,当NSQD重启之后,自动从硬盘加载数据,进行恢复,但
可能导致少量数据丢失
,此处可以跟OK
标识符结合起来,只有消息被持久化到磁盘之后,才会给客户端返回OK
标识,所以哪怕NSQD在数据持久化之前挂了,数据丢了,由于生产者未收到OK
标识符,也是可以进行重发的。 -
消费者丢失了数据
NSQD使用了
FIN
标识符,当NSQD把消息PUSH给消费者的同时,也会将消息放入inFlight队列
中,当消费者成功处理了消息之后,会给NSQD返回FIN
标识符,NSQD将inFlight队列
中响应消息删除,否则将会重新入队,再次进行投递。
如何保证消息的顺序性
官方NSQ 不能保证消息的顺序消费,但是有赞重新设计的NSQ添加了此项特性,主要是生产者将同一类别的消息投递到同一个 partion 中,NSQD每次都只PUSH一条消息,从而保证数据的顺序性消费。
如何处理消息的过期失效问题
官方NSQ使用
defer队列
来存放延迟消息,目前最大支持一天的延迟,具体采用小根堆
的数据结构来存储,其优先级为剩余时间,放在堆顶的消息是最先到期,需要投递的消息,有一个goroutine 定期对inFlight队列
和defer队列
进行扫描,对符合要求的进行投递。
参考资料:
https://github.com/youzan/nsq/blob/master/doc/NSQ-redesigned-details.pdf