Kafka.08 - 消息交付可靠性保障
![Kafka.08 - 消息交付可靠性保障](https://static001.geekbang.org/infoq/e6/e6c837cd54935b442608c971add7644c.png)
可靠性保障
Kafka 消息交付可靠性保障,也称为数据传输的事务的定义通常有以下三种级别:
最多一次: 消息不会被重复发送,最多被传输一次,但也有可能一次不传输。
最少一次: 消息不会被漏发送,最少被传输一次,但也有可能被重复传输.
精确的一次(Exactly once): 不会漏传输也不会重复传输,每个消息都传输被一次而且仅仅被传输一次,这是大家所期望的。
大多数消息系统声称可以做到“精确的一次”,但是仔细阅读它们的的文档可以看到里面存在误导,比如没有说明当 consumer 或 producer 失败时怎么样,或者当有多个 consumer 并行时怎么样,或写入硬盘的数据丢失时又会怎么样。
Producer 的可靠性保障实现
kafka 的做法要更先进一些。目前,Kafka 默认提供的交付可靠性保障是第二种,即至少一次。当发布消息时,Kafka 有一个“committed”的概念,一旦消息被提交了,只要消息被写入的分区的所在的副本 broker 是活动的,数据就不会丢失。
如果 producer 传递消息给 Broker 时发生了网络错误,但又不确定是在提交之前发生的还是提交之后发生的,因此,它只能选择重试,也就是再次发送相同的消息。这就是 Kafka 默认提供至少一次可靠性保障的原因,不过这会导致消息重复发送。
并不是所有的情况都需要“精确的一次”这样高的级别,Kafka 允许 producer 灵活的指定级别。比如 producer 可以指定必须等待消息被提交的通知,或者完全的异步发送消息而不等待任何通知,或者仅仅等待 leader 声明它拿到了消息(followers 没有必要),以及禁止 Producer 的重试,这样就只提供至多一次的保障。
Consumer 的可靠性保障实现
现在从 consumer 的方面考虑这个问题,所有的副本都有相同的日志文件和相同的 offset,consumer 维护自己消费的消息的 offset,如果 consumer 不会崩溃当然可以在内存中保存这个值,当然谁也不能保证这点。如果 consumer 崩溃了,会有另外一个 consumer 接着消费消息,它需要从一个合适的 offset 继续处理。这种情况下可以有以下选择:
consumer 可以先读取消息,然后将 offset 写入日志文件中,然后再处理消息。这存在一种可能就是在存储 offset 后还没处理消息就 crash 了,新的 consumer 继续从这个 offset 处理,那么就会有些消息永远不会被处理,这就是上面说的“最多一次”。
consumer 可以先读取消息,处理消息,最后记录 offset,当然如果在记录 offset 之前就 crash 了,新的 consumer 会重复的消费一些消息,这就是上面说的“最少一次”。
“精确一次”可以通过将提交分为两个阶段来解决:保存了 offset 后提交一次,消息处理成功之后再提交一次。但是还有个更简单的做法:将消息的 offset 和消息被处理后的结果保存在一起。比如用 Hadoop ETL 处理消息时,将处理后的结果和 offset 同时保存在 HDFS 中,这样就能保证消息和 offser 同时被处理了。
评论