小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
消息投递可靠性
承接上文# 几张图理解kafka的设计原理(二) 本文继续针对kafka的持久化、消息投递这些术语和它们的作用简单的用图来解释一下。
kafka投递成功模式
一个消息如何算投递成功,Kafka
提供了三种模式:
-
第一种是发送出去就算成功,这种情况当然不能保证消息成功投递到
broker
; -
第二种是
Master-Slave
模型,只有当Master
和所有Slave
都接收到消息时,才算投递成功,这种模型提供了最高的投递可靠性,但是损伤了性能; -
第三种模型,即只要
Master
确认收到消息就算投递成功;实际使用时,根据应用特性选择,绝大多数情况下都会中和可靠性和性能选择第三种模型
partition ack说明
- acks="1" (默认),表示
producer
写partition leader成功后,broker
就返回成功,无论其他的partition follower是否写成功。 - acks="0",表示
producer
发送消息之后不需要等待任何服务端的响应。最大吞吐 - acks="-1/all"[parition的数量]的时候,表示只有
producer
全部写成功的时候,才算成功,kafka broker
才返回成功信息。这里需要注意的是,如果acks=-1的时候,一旦有个broker
宕机导致partition
的follower
和leader
切换,会导致丢数据。
消息状态:在
Kafka
中,消息的状态被保存在zookeeper
中,broker
不会关心哪个消息被消费了被谁消费了,只记录一个offset
值(指向partition
中下一个要被消费的消息位置),这就意味着如果consumer
处理不好的话,broker
上的一个消息可能会被消费多次。
消息的持久化
消息在broker
上的可靠性,因为消息会持久化到磁盘上,所以如果正常stop一个broker
,其上的数据不会丢失;但是如果不正常stop,可能会使存在页面缓存来不及写入磁盘的消息丢失,这可以通过配置flush
页面缓存的周期、阈值缓解,但是同样会频繁的写磁盘会影响性能,又是一个选择题,根据实际情况配置。
为了保证消息消费的可靠性,kafka
提供的是“At least once”模型,因为消息的读取进度由offset
提供,offset
可以由消费者自己维护也可以维护在zookeeper
里。
但是当消息消费后
consumer
挂掉,offset
没有即时写回,就有可能发生重复读的情况,这种情况同样可以通过调整commit offset周期、阈值缓解,甚至消费者自己把消费和commit offset做成一个事务解决,但是如果你的应用不在乎重复消费,那就干脆不要解决,以换取最大的性能。
- 消息持久化
Kafka
中会把消息持久化到本地文件系统中,并且保持O(1)极高的效率。我们众所周知IO读取是非常耗资源的性能也是最慢的,这就是为了数据库的瓶颈经常在IO上,需要换SSD硬盘的原因。但是Kafka
作为吞吐量极高的MQ,却可以非常高效的消息持久化到文件。这是因为Kafka
是顺序写入O(1)的时间复杂度,速度非常快。也是高吞吐量的原因。由于消息的写入持久化是顺序写入的,因此消息在被消费的时候也是按顺序被消费的,保证partition
的消息是顺序消费的。一般的机器,单机每秒100k条数据。Kafka
由于对可拓展的数据持久化的支持,它也非常适合向ES
或者数据仓库中进行数据装载。
- 消息有效期
Kafka
会长久保留其中的消息,以便consumer
可以多次消费,当然其中很多细节是可配置的。
参考
《深入理解kafka》