基础概念
kafka是一个消息队列系统,不同的生产者和消费者,可以向kafka写入自己的数据,实现数据的流动;kafka解耦了生产者和消费者,它的ack机制保证了消息传递的可靠性,借助zookeeper等实现了分布式的消息队列。
生产者可以根据需要向不同的主题写入数据,为了减少累计的网络IO时间,可以把多个消息积累到一个批次中统一发送。
消费者可以组成消费者组的概念,消费者组可以订阅主题,kafka的offset机制保证了不同消费者组可以独立消费自己的消息,同时也保证了消息可以高效传递。消息也可以分批次读取。
客户端从kafka集群获取元信息,然后从元信息中解析出有关信息,关于元信息的内容,参考这篇博客:
https://zhmin.github.io/2019/03/08/kafka-metadata/
基本概念:
- broker:一台kafka的主机
- topic:主题,一类消息存放到一个主题中,topic可以视为一个数据流,一个topic中可以有多个partition,topic可以跨服务器
- partition:分区,topic的基础组成组件,partition是FIFO的数据,一个partition内部可以保证元素有序。但是一个topic内如果有多个partition,则topic整体不能保证FIFO
消费者读取消息
生产者
生产者特点:
- 一个消息只能写入一个分区
消息的结构:- 键:一般用于分区器分区,决定写入那个分区
- 值:实际存储的数据
- partition:分区消息,包含了分区的内容
- topic:主题
- 一次可以发送一个批次的消息,减少网络IO时间
生产者内部包含有分区器,可以自定义分区的策略,分区一般是基于键值的。如果不写键值,则默认使用轮询分区的方式。消息发送成功后,会收到一个ack认证。
生产者写入消息
写入消息的流程:
综上可知,消息发送的流程是:
圆角举行步骤是可选的。
当创建有新的分区时,会给生产者发送对应的消息。生产者获取分区消息后,会重新设置发送时分区的选项。
消费者
消费者
- 一个分区只能由一个消费者进行消费
- 一个消费者可以消费多个分区
- 消费者一般以消费者组的形势出现
- 消费者读取消息时,利用的是偏移量offset,
- 一个消费者组使用一组offset,不同组的offset互不影响,kafka不会立刻删除数据,而是用自己的删除策略,比如定期删除或者定量删除
- 消费者收到消息后,需要给kafka一个ack认证,这是消息可靠的前提
- 如果一个消费者组的消费者数量大于订阅的topic中partition的数量,那么多余的消费者会出现空闲
再均衡和群组协调器:
当有消费者下线后,会触发再均衡,此时整个消费者组暂时不可读取数据。每个群组都有自己的群组协调器broker,不同群组可以有不同的群组协调器。群组协调器的三个核心任务:
- 发现死亡的client
- 停止对死亡client的服务,之后暂停读的服务
- 重新分配partition给其它的消费者
轮询主题和提交偏移量
消费者通过轮询的方式读取kafka主题的消息,同时需要提交偏移量到_consumer_offset_分区。该分区的作用是,当某个消费者群组发生再均衡时,每个消费者可能会获取不同的分区,则消费者需要知道对应分区的偏移量,以获取正确的数据,因此分区需要保留每个消费者消费的数据的偏移量。
上述可知,消费者需要在消费数据后,需要向_consumer_offset_分区提交自己的偏移量。提交偏移量,一般有几个方式:
- 自动提交:每间隔一定时间,提交最近一次的偏移量,比如每500ms提交一次,这种方式不精确
- 手动提交,分为三种方式:
- 同步提交:消费完立刻提交,不成功就阻塞,直到成功为止
- 异步提交:消费完把偏移量等数据放到一个异步调用的函数中,失败会捕获异常并输出日志。
- 同步异步结合方式:失败捕获异常并输出日志,如果异常不是网络的问题,是发生了再均衡,此时需要同步提交,直到最后完成上传数据。
提交量偏低,导致重复读:
提交量偏高,导致少读数据:
对于独立的消费者,我们可以单独读取对应的消息,但是无法获取分区的信息,因此需要定时轮询以确认是否有新的分区。
参考文章
- https://coralogix.com/log-analytics-blog/a-complete-introduction-to-apache-kafka/