消息中间件系列第3讲:使用消息队列需要考虑的几个问题
一般情况下,我们使用消息队列需要考虑下面几个问题:
- 如何保证消息的幂等性(消息重复)?
- 如何保证消息的顺序性(消息有序)?
- 如何保证消息的可靠性(消息丢失)?
消息幂等性
幂等性其实是一个数学与计算机概念,其意思是:
在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。
放在消息队列中,消息幂等性的意思是:一条完全一样的消息,它消息一次和消费无数次的结果是一样的。
所以说消息幂等性要解决什么问题呢?消息幂等性要解决的就是消息队列中的消息重复问题。
举个例子:我们发送短信时,生产者将要发送的消息放入消息队列中,消费者从队列取出消息在将消息发送给用户。
因为消息队列可能存在重复消息,所以如果我们没有对消息队列做幂等性处理,那么可能用户就会收到多条短信,对用户造成骚扰。
对于消息中间件的幂等性问题,一般通用的处理方案是给消息一个唯一的ID,每次做业务处理之前判断是否消费过。如果消费过,那么直接抛弃该消息,否则进行业务处理。
消息顺序性
顺序性指的是在一些具体的业务中,前后的业务操作必须有顺序,否则会导致业务处理错误。例如在电商系统中,订单和支付通常是两个不同的业务逻辑,我们通常会将其分拆开来处理。这两个业务逻辑之间存在非常清晰的依赖关系:需要先生成订单,然后才能支付订单。对于这种情况,我们就说订单消息和支付消息是有顺序性的。
对于消息中间件的消息顺序性问题,一般通用的处理方案是保证局部的消息有序。例如对于 Kafka 来说,我们会保证 Partition 区域的消息有序性。对于上面所说的订单消息、支付消息的例子,我们一般会将订单消息和支付消息里的用户ID作为key,将其分配到同一个 partition 中,这样它们就是有序的。
消息可靠性
消息可靠性其实说的就是消息丢失,我们如何去防止消息发生丢失,或者说消息丢失之后,我们应该如何补救?
对于 Kafka 来说,可能发生消息丢失的几个节点分别是:
- 生产者丢失消息
生产者有一个参数request.required.acks
,可以设置生产者的数据一致性级别。
当其值为0时,表示生产者不需要等待 broker 的回复,直接发送下一条消息。这种情况下如果 broker 宕机,而生产者还是一直发送消息,那么这些数据就会全部丢失。
当其值为1时,表示生产者需要等待 broker 的 ack 响应后,才发送下一条消息。在这种情况下,broker 接收到消息,写入内存后便会发送 ack 响应,但并不会立刻写入内存。这时候如果在写入磁盘前 broker 发生宕机,那么这条消息就丢失了。
当其值为-1时,表示生产者需要等待所有 broker(副本)写入内存后,发发送下一条消息。这种情况下,其实还是有可能发生宕机,因为数据还是没有写入磁盘,没有持久化。生产者接收到 ack 响应,只能表明数据写入所有主、备broker的内存中而已。不过对比起上一种,这种丢失数据的可能性降低了一些。
- broker丢失消息
当生产者将消息发送到 broker 之后,其实只是将消息缓存到内存中,再由一个线程定时刷入磁盘。这时候如果 broker 宕机,那么这部分存在内存中的数据就丢失了。要杜绝这种情况的发生,我们可以设置log.flush.interval.messages
参数为1,这样每有一条消息,broker 就会立刻将消息刷入磁盘,这样就不会发生消息丢失。但是这种方式非常消耗磁盘性能,如果这么做了,那么基本上 Kafka 就没有任何吞吐量优势了。
- 消费者丢失消息
消费者从 broker 获取到消息后,offset 如果设置为自动提交,那么 offset 就会提交到 zk 中。此时如果 consumer 线程被 kill 掉,那么这条消息就丢失了。
参考:http://www.voidcn.com/article/p-rwskpkmq-bpz.html
那么如何解决数据丢失的问题呢?目前来说有两种方式,一种是在消息中间件层面解决,另一方面是在业务层面通过消息补偿解决。
消息中间件层面。选择不会丢失的消息中间件,例如 RocketMQ 对于消息的确认机制比较严格,可以保证消息不丢失(TODO 为什么 RocketMQ 能保证消息不丢失,而 Kafka 不行呢?)。而 Kafka 则无法保证消息不丢失。
业务层面(消息补偿)。意思是允许中间件出现消息丢失,但是通过业务层面来做消息补偿。不同的业务场景,消息补偿的形式不一样,需要具体情况具体分析。
总结
消息的幂等性、顺序性、可靠性可以说是消息中间件需要考虑的三个基本问题,在应用到具体系统之前都必须考虑清楚它们造成的影响,以及解决方案。
![扫描关注微信公众号](https://images.cnblogs.com/cnblogs_com/chanshuyi/1943043/o_220725133529_%E5%BE%AE%E4%BF%A1%E6%90%9C%E4%B8%80%E6%90%9C-%E6%A0%91%E5%93%A5%E8%81%8A%E7%BC%96%E7%A8%8B.png)