几张图理解kafka的设计原理(三)——消息投递可靠性

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

消息投递可靠性

承接上文# 几张图理解kafka的设计原理(二) 本文继续针对kafka的持久化、消息投递这些术语和它们的作用简单的用图来解释一下。

kafka投递成功模式

一个消息如何算投递成功,Kafka提供了三种模式:

  • 第一种是发送出去就算成功,这种情况当然不能保证消息成功投递到broker

  • 第二种是Master-Slave模型,只有当Master和所有Slave都接收到消息时,才算投递成功,这种模型提供了最高的投递可靠性,但是损伤了性能;

ack-p-m.png

  • 第三种模型,即只要Master确认收到消息就算投递成功;实际使用时,根据应用特性选择,绝大多数情况下都会中和可靠性和性能选择第三种模型

partition ack说明

  • ack=1,表示producer写partition leader成功后,broker就返回成功,无论其他的partition follower是否写成功。
  • ack=2,表示producer写partition leader和其他一个follower成功的时候,broker就返回成功,无论其他的partition follower是否写成功。
  • ack=-1[parition的数量]的时候,表示只有producer全部写成功的时候,才算成功,kafka broker才返回成功信息。这里需要注意的是,如果ack=1的时候,一旦有个broker宕机导致partitionfollowerleader切换,会导致丢数据。

消息状态:在Kafka中,消息的状态被保存在zookeeper中,broker不会关心哪个消息被消费了被谁消费了,只记录一个offset值(指向partition中下一个要被消费的消息位置),这就意味着如果consumer处理不好的话,broker上的一个消息可能会被消费多次。

消息的持久化

消息在broker上的可靠性,因为消息会持久化到磁盘上,所以如果正常stop一个broker,其上的数据不会丢失;但是如果不正常stop,可能会使存在页面缓存来不及写入磁盘的消息丢失,这可以通过配置flush页面缓存的周期、阈值缓解,但是同样会频繁的写磁盘会影响性能,又是一个选择题,根据实际情况配置。

为了保证消息消费的可靠性,kafka提供的是“At least once”模型,因为消息的读取进度由offset提供,offset可以由消费者自己维护也可以维护在zookeeper里。

topic_send.png
但是当消息消费后consumer挂掉,offset没有即时写回,就有可能发生重复读的情况,这种情况同样可以通过调整commit offset周期、阈值缓解,甚至消费者自己把消费和commit offset做成一个事务解决,但是如果你的应用不在乎重复消费,那就干脆不要解决,以换取最大的性能。

  • 消息持久化

Kafka中会把消息持久化到本地文件系统中,并且保持O(1)极高的效率。我们众所周知IO读取是非常耗资源的性能也是最慢的,这就是为了数据库的瓶颈经常在IO上,需要换SSD硬盘的原因。但是Kafka作为吞吐量极高的MQ,却可以非常高效的消息持久化到文件。这是因为Kafka是顺序写入O(1)的时间复杂度,速度非常快。也是高吞吐量的原因。由于消息的写入持久化是顺序写入的,因此消息在被消费的时候也是按顺序被消费的,保证partition的消息是顺序消费的。一般的机器,单机每秒100k条数据。
Kafka由于对可拓展的数据持久化的支持,它也非常适合向ES或者数据仓库中进行数据装载。

持久化.png

  • 消息有效期

Kafka会长久保留其中的消息,以便consumer可以多次消费,当然其中很多细节是可配置的。

参考

《深入理解kafka》