Kafka到底会不会丢消息

目录

1、kafka是什么

一种高吞吐量的分布式、发布订阅消息系统,它可以处理消费者规模的,网站中的所有动作流数据,具有高性能、持久化、多副本备份、横向扩展能力……

  • 以时间复杂度为 O(1) 的方式提供消息持久化能力,即使对 TB 级以上数据也能保证常数时间复杂度的访问性能。
  • 高吞吐率。即使在非常廉价的商用机器上也能做到单机支持每秒 100K 条以上消息的传输。
  • 支持 Kafka Server 间的消息分区,及分布式消费,同时保证每个 Partition 内的消息顺序传输。
  • 同时支持离线数据处理和实时数据处理。
  • Scale out:支持在线水平扩展。
image.png

2、消息从生产到消费

2.1、发送数据

永远找leader!消息写入leader后,follower是主动的去leader进行同步的!producer采用push模式将数据发布到broker,每条消息追加到分区中,顺序写入磁盘,所以保证同一分区内的数据是有序的!

  • partition在写入的时候可以指定需要写入的partition,如果有指定,则写入对应的partition。
  • 如果没有指定partition,但是设置了数据的key,则会根据key的值hash出一个partition。
  • 如果既没指定partition,又没有设置key,则会轮询选出一个partition。
image.png

发送数据可靠性保证:ACK机制!

0:代表producer往集群发送数据不需要等到集群的返回,不确保消息发送成功。安全性最低但是效率最高。
1:代表producer往集群发送数据只要leader应答就可以发送下一条,只确保leader发送成功。
all:代表producer往集群发送数据需要所有的follower都完成从leader的同步才会发送下一条,确保leader发送成功和所有的副本都完成备份。安全性最高,但是效率最低。

敲黑板:所以这里可能是会丢消息的哟!

0:发丢了,生产端不知道,就是丢了。
1:保证leader不丢,但是如果leader挂了,恰好选了一个没有ACK的follower,那也丢了。
all:保证leader和follower不丢,但是如果网络拥塞,没有收到ACK,会有重复发的问题。

2.2、保存数据

你以为是这样的:

image.png

其实是这样的:

image.png

操作系统本身有一层缓存,叫做 Page Cache,是在内存里的缓存,我们也可以称之为 OS Cache,意思就是操作系统自己管理的缓存。你在写入磁盘文件的时候,可以直接写入这个 OS Cache 里,也就是仅仅写入内存中,接下来由操作系统自己决定什么时候把 OS Cache 里的数据真的刷入磁盘文件中。

Kafka提供了一个参数——producer.type来控制是不是主动flush,如果Kafka写入到mmap之后就立即flush然后再返回Producer叫 同步 (sync);写入mmap之后立即返回Producer不调用flush叫异步 (async)。

敲黑板:所以这里也可能是会丢消息的哟!

假如已经写在了OS cache中但是还没来得及刷入磁盘,此时突然机器宕机,或者broker重启,那就丢了。

2.3、消费数据

消费者通过pull模式主动的去kafka集群拉取消息,与producer相同的是,消费者在拉取消息的时候也是找leader去拉取。

多个消费者可以组成一个消费者组(consumer group),每个消费者组都有一个组id!同一个消费组者的消费者可以消费同一topic下不同分区的数据,但是不会组内多个消费者消费同一分区的数据。

image.png

在早期的版本中,消费者将消费到的offset维护zookeeper中,consumer每间隔一段时间上报一次,这里容易导致重复消费,且性能不好!在新的版本中消费者消费到的offset已经直接维护在kafka集群的__consumer_offsets这个topic中!

消费消息的时候可以大致分为两个阶段:1、标示该消息已被消费(commit记录一下);2、处理消息。

敲黑板:所以这里也可能是会丢消息的哟!

先commit,但是在处理消息的异常了,此时这条消息就丢了。
先处理,再commit,不丢。

3、消息可靠性保证

  • At most once 消息可能会丢,但绝不会重复传输
  • At least once 消息绝不会丢,但可能会重复传输
  • Exactly once 每条消息肯定会被传输一次且仅传输一次,很多时候这是用户所想要的

从 Producer 向 broker 发送消息时,通过ACK机制保证不丢消息,但是不可靠,依赖kafka的参数配置:

  • 0:发丢了,生产端不知道,就是丢了,对应At most once。
  • 1:保证leader不丢,但是如果leader挂了,恰好选了一个没有ACK的follower,那也丢了,对应At most once。
  • all:保证leader和follower不丢,但是如果网络拥塞,没有收到ACK,会有重复发的问题,对应At least once。

在broker存储消息时,通过主动flush来保证可靠性,但是如果没设置强制flush,那就有可能丢了。

从 broker 到 Consumer 消费消息时,数据处理与 commit 的顺序在很大程度上决定了消息从 broker 和 consumer 的可靠性:

  • 读完消息先 commit 再处理消息。这种模式下,如果 Consumer 在 commit 后还没来得及处理消息就 crash 了,下次重新开始工作后就无法读到刚刚已提交而未处理的消息,这就对应于 At most once
  • 读完消息先处理再 commit。这种模式下,如果在处理完消息之后 commit 之前 Consumer crash 了,下次重新开始工作时还会处理刚刚未 commit 的消息,实际上该消息已经被处理过了。这就对应于 At least once。在很多使用场景下,消息的处理往往具有幂等性,即多次处理这一条消息跟只处理一次是等效的,那就可以认为是 Exactly once。
  • 如果一定要做到 Exactly once,就需要协调 offset 和实际操作的输出。精典的做法是引入两阶段提交。如果能让 offset 和操作输入存在同一个地方,会更简洁和通用。这种方式可能更好,因为许多输出系统可能不支持两阶段提交。比如,Consumer 拿到数据后可能把数据放到 HDFS,如果把最新的 offset 和数据本身一起写到 HDFS,那就可以保证数据的输出和 offset 的更新要么都完成,要么都不完成,间接实现 Exactly once。

你可能感兴趣的:(Kafka到底会不会丢消息)