共计 2094 个字符,预计需要花费 6 分钟才能阅读完成。
音讯队列会失落音讯吗?
答案是必定的,所以对于业务谨严的数据,咱们要确保其在音讯队列中的平安,不能丢。
要想解决不丢的问题,首先要弄清楚 音讯是怎么丢的呢?
丢音讯的关键点有 3 个:
- Producer 发送音讯的过程
- 音讯队列的音讯存储
- Consumer 生产音讯的过程
上面挨个看看都是怎么丢的,以及解决方案。
会以 RabbitMQ 和 Kafka 这两个罕用的音讯零碎来阐明。
1. Producer 弄丢音讯
Producer 向 MQ 发消息,很简略,发过来就完事儿了。
然而,在发送图中是存在危险的,例如网络问题等等,导致 MQ 没有失常收到。
怎么解决呢? 思路很简略,让 MQ 发一个 承受确认申明(ack) 就行了,就像快递须要签收一样。
例如 RabbitMQ,有两种形式能够确保发送音讯的平安。
1)事务音讯
Producer 发送音讯之前,先开启事务,而后再发送。
如果 RabbitMQ 没有失常收到音讯,Producer 会收到异样信息,回滚事务。
如果失常接管了,Producer 就提交事务。
很牢靠,但效率低,因为这个事务模式是同步的,会产生阻塞。
2)confirm 确认模式
Producer 开启 confirm 模式,发送音讯的时候,RabbitMQ 会给这个音讯调配一个惟一的 ID。
胜利写入队列之后,RabbitMQ 会向 Producer 发送一个 ack 音讯,阐明此 ID 的音讯曾经胜利发送。
confirm 模式还有一个回调机制,Producer 能够筹备一个失败的接口,供 RabbitMQ 在接管失败时调用。
Producer 收到失败告诉,或者超时了,能够执行相应的解决逻辑,例如重发。
confirm 模式是异步的,比事务音讯更高效,应用更为宽泛。
Kafka 也是应用的 ack 形式,应用形式很简略,只有配置:
ack=all
确保 Kafka 在齐全接管胜利后才发送确认告诉,这样就肯定不会发丢了。
2. MQ 在存储期间弄丢音讯
MQ 胜利接管音讯之后,须要保存起来,等着 Consumer 生产。
在这个保留期间,也能够能失落音讯。
这通常是由 MQ 故障 引起的。
RabbitMQ 想要保障音讯不丢,须要开启 长久化,音讯就会写入磁盘。
即便 RabbitMQ 宕机了,只有磁盘没事儿,重启之后还能够从新把音讯加载进来。
如果想进一步的保障音讯平安,就须要配置 RabbitMQ 的镜像集群了,来确保高可用。
Kafka 是人造的分布式系统,Topic 分为多个 Partition,每个 Partition 又有多个正本。
Partition 的多个正本,分为 Leader 和 Follower。
Leader 负责解决音讯的读写,Follower 负责备份。
后面说的 Kafka 配置 ack=all
,就是通知 Kafka,Leader 和所有 Follower 全都接管到了,才算发送 ack 确认,只有 Leader 本人接管胜利是不算的。
否则的话,如果 Leader 接管实现就通知 Producer OK 了,在 Leader 同步给 Follower 之前,Leader 宕机了,Kafka 会从 Follower 中选举出新的 Leader。那么,老 Leader 在临终前没有同步的音讯就失落了。
为了保障音讯的平安,这 4 个参数要设置好:
replication.factor
用于指定 Partition 正本的数量,必须大于 1,就是至多要有 2 个正本,一个 Leader 一个 Follower。
min.insync.replicas
用于指定几个正本胜利写入才 提交音讯,只有提交之后的音讯能力被 Consumer 生产。
此值至多大于 1,这样就保障 Leader 之外至多有一个正本同步到了这条音讯,不怕 Leader 宕掉了。
acks=all
用于指定几个正本接管到音讯之后向 Producer 发送 ack。例如值为 1,示意 Leader 收到就能够了,“all”示意“所有正本”,也能够写“-1”,等同于“all”。
retries=999
用于指定 Producer 发送失败后的重试次数,能够设为一个很大的数,示意失败了就重试,晋升发送胜利几率。
3. Consumer 弄丢音讯
例如 Consumer 胜利接管到了音讯“123”,MQ 就会移除这条音讯。
但在 Consumer 解决完这条音讯之前,宕机了。
Consumer 重启之后持续从 MQ 拿音讯,这次拿到的就是下一条音讯“124”,那么“123”就丢了。
所以,Consumer 只是接管到音讯是不够的,胜利解决实现 才行。
这就和 MQ 的生产确认机制无关了。
RabbitMQ 默认是 Consumer 胜利接管音讯之后就发送 ack 确认,RabbitMQ 就认为生产胜利了。
敞开主动的 Consumer ack 就行,改为手动发送确认告诉。
Kafka 的 Consumer 发送的不是 ack 确认,而是 offset,通知 Kafka 曾经生产到哪个地位了。
默认是 Consumer 接管后主动提交 offset,所以也须要敞开,改为手动提交。
小结一下,要想音讯不丢,须要发消息的时候确认发送胜利了,MQ 存储的时候要是高牢靠的,Consumer 生产的时候,不能接管之后就确认,真正解决实现才行。
举荐浏览
OAuth2 图解
轻松了解 Kubernetes 的外围概念
开发者必须要理解的架构技术趋势:Service Mesh