Kafka 数据可靠性如何保证?
对于 kafka 来说,以下几个方面来保障消息分发的可靠性:
1.消息发送的可靠性保障(producer)
2.消息消费的可靠性保障(consumer)
3.Kafka 集群的可靠性保障(Broker)
生产者
目前生产者发送消息(acks)有三种方式。
acks=0
producer 不等待 broker 的 acks。发送的消息可能丢失,但永远不会重发。
acks=1
leader 不等待其他 follower 同步完毕,leader 直接写 log,然后发送 acks 给 producer。这种
情况下会有数据重发现象,可靠性比 only once 好点,但是仍然会丢消息。例如 leader 挂了,
但是其他 replication 还没完成同步。
acks=all
leader 等待所有 follower 同步完成才返回 acks。消息可靠不丢失(丢了会重发),没收到
ack 会重发。
消费者
如果将 consumer 设置为 autocommit,consumer 一旦读到数据立即自动 commit。如果
只讨论这一读取消息的过程,那 Kafka 确保了 Exactly once。
但实际使用中应用程序并非在 consumer 读取完数据就结束了,而是要进行进一步处理,
而数据处理与 commit 的顺序在很大程度上决定了 consumer delivery guarantee:
At most once:读完消息先 commit,再处理消息。
如果 consumer 在 commit 后还没来得及处理消息就 crash 了,下次重新开始工作后就无
法读到刚刚已提交而未处理的消息,因为此时 offset 已经改变了。
At least once(默认):读完消息先处理再 commit。
如果在处理完消息之后 commit 之前, consumer crash 了,下次重新开始工作时还
会处理刚刚未 commit 的消息,实际上该消息已经被处理过。但即使数据可能重复,这个
在应用上需要可以容忍的。
Exactly once(避免重复消费):保存 offset 和处理消息这两个环节采用 two-phase
commit(2PC)。
传统方式:把消息处理和提交 offset 做成原子操作。offset 提交失败,消息处理也要回滚。
kafka 推荐方式:消息处理结果和 offset 的存储放在一起存储。比如将 offset 和处理结果一
起写到 HDFS,那就可以保证数据的输出和 offset 的更新要么都完成,要么都不完成,间
接实现 Exactly once
Kafka 集群
对于 broker,落盘的数据,有 replica 机制保证数据不丢失。
对于内存(没有 flush 磁盘)数据,broker 重启会丢失。可以通过 log.flush.interval.messages
和 log.flush.interval.ms 来配置 flush 间隔,如果 interval 设置过大丢的数据多些,设置过小
会影响性能