基本概念
- Producer:消息生产者
- Comsumer:消息消费者
- topic:消息主题,代表一类相同类型的消息,可以被多个消费者消费
- partition:分区,每个topic对应多个分区,每个分区都是顺序写入,具有顺序性,提升吞吐量
- offset:位移值,消息在分区的位置
- replication:副本,kafka为了保证可用性的方式。kafka的同一分区可以在broker上存在多个副本,通常只有主副本对外提供读写服务,当主副本所在broker崩溃或者发生网络异常,controller会重新选出新的leader副本对外提供服务
- broker:kafka集群,代表kafka的服务节点
- Consumer group:消费者组,不同消费者组可以重复消费相同的topic的消息,实现发布订阅
架构
暂时无法在文档外展示此内容
Zookeeper
Kafka 将 Broker、Topic 和 Partition 的元数据信息存储在 Zookeeper 上。通过在 Zookeeper 上建立相应的数据节点,并监听节点的变化,Kafka 使用 Zookeeper 完成以下功能:
- Kafka Controller 的 Leader 选举
- Kafka 集群成员管理
- Topic 配置管理
- 分区副本管理
Controller
- 作用
Controller 是从 Broker 中选举出来的,负责分区 Leader 和 Follower 的管理。当某个分区的 leader 副本发生故障时,由 Controller 负责为该分区选举新的 leader 副本。当检测到某个分区的 ISR(In-Sync Replica)集合发生变化时,由控制器负责通知所有 broker 更新其元数据信息。当使用kafka-topics.sh脚本为某个 topic 增加分区数量时,同样还是由控制器负责分区的重新分配。
- 选举过程
Broker启动的时候,尝试去读取/controller节点的brokerId,如果brokerId的值不等于-1,则表示已有其他broker节点成为controller节点,当前broker放弃竞选。如果不存/controller节点或者brokerId值异常,则当前节点尝试创建/controller节点,其他broker也会尝试创建节点,只有一个broker节点可以创建成功,成为controller。
- 职责
Controller 被选举出来,作为整个 Broker 集群的管理者,管理所有的集群信息和元数据信息。它的职责包括下面几部分:
- 处理 Broker 节点的上线和下线,包括自然下线、宕机和网络不可达导致的集群变动,Controller 需要及时更新集群元数据,并将集群变化通知到所有的 Broker 集群节点;
- 创建 Topic 或者 Topic 扩容分区,Controller 需要负责分区副本的分配工作,并主导 Topic 分区副本的 Leader 选举。
- 管理集群中所有的副本和分区的状态机,监听状态机变化事件,并作出相应的处理。Kafka 分区和副本数据采用状态机的方式管理,分区和副本的变化都在状态机内会引起状态机状态的变更,从而触发相应的变化事件。
ISR
-
就是与leader replica保持同步的replica集合。
-
kafka为partition动态维护了一个replica集合。该集合中所有的replica保存的消息和日志都和leader replica保持同步状态。只有这个集合中的replica才能被选为leader,也只有该集合中的所有replica都接受到同一消息,kafka才会将该消息置为已提交。
-
kafka保证消息不丢失的条件:
- ISR中至少存在一个存活的replica
- 已提交的消息
-
正常情况下,partition中所有的replica都应该和leader replica保持同步,即所有replica都应该在ISR中;因为各种各样的原因,一小部分的replica开始落后于leader replica的进度,当滞后到一定程度,kafka就会把这部分replica剔除ISR;相反地,当这部分replica慢慢追上leader replica,kafka会自动将他们加到ISR,这一切都是自动的。
高吞吐量、低延迟
-
磁盘顺序读写,效率高于随机读写
-
读写基于pageCache,数据先写入系统页缓存,由系统将数据写入磁盘;读取消息,先读取页缓存数据,没有命中才会读取磁盘,同时缓存数据,供下一次读取;基于LRU
-
零拷贝
-
传统IO的流程读取文件,再用socket发送出去,传统方式实现:先读取、再发送,实际经过1~4四次copy。
- 将磁盘文件读取到操作系统的内核缓冲区
- 将内核缓冲区的数据,copy到application应用程序的buffer
- 将application应用程序buffer中的数据,copy到socket网络发送缓冲区(属于操作系统内核的缓冲区);
- 将socket buffer的数据,copy到网卡,由网卡进行网络传输。
-
Mmap (producer->broker)
- 在进程 的非堆内存开辟一块内存空间,和OS内核空间的一块内存进行映射;
- kafka数据写入、是写入这块内存空间,但实际这块内存和OS内核内存有映射,也就是相当于写在内核内存空间了,且这块内核空间、内核直接能够访问到,直接落入磁盘。
- 优点:减少数据写入时从内核缓冲区到应用程序的copy
-
sendfile (broker->consumer)
- 将读到内核空间的数据,转到 socket buffer,进行网络发送
-
Q&A
如何保证数据不丢失
-
producer参数配置
-
acks=all,producer发送完消息后,必须要等ISR中所有的follwer节点都同步完消息才能认为提交成功
-
retries:重试次数
- 可恢复的错误:如遇到在leader的选举、网络的抖动等这些异常时,如果我们在这个时候配置的retries大于0的,也就是可以进行重试操作
- 不可恢复:当重试超过最大限制次数,可将信息记录DB单独处理
-
-
broker参数配置
- unclean.leader.election.enable=false, 关闭非ISR集合里的follwer被选举为leader,非ISR集合副本一般比较滞后,会导致数据丢失
- min.insync.replicas>1,ISR副本数量大于1
Rebalance
-
含义: consumer group的rebalance本质上是一组协议,它规定了一个consumer group是如何达成一致来分配订阅topic的所有分区的。
-
旧版本consumer是依赖zk来进行rebalance;新版本consumer使用了Kafka内置的一个全新的组协调协议(group coordination protocol)。对于每个组而言,Kafka的某个broker会被选举为组协调者(group coordinator)。coordinator负责对组的状态进行管理,它的主要职责就是当新成员到达时促成组内所有成员达成新的分区分配方案,即coordinator负责对组执行rebalance操作。
-
Rebalance发生的条件
- 组员发生变更,比如新的consumer加入组,或者已有consumer离开组,再或是已有consumer发送崩溃时候(当consumer无法在指定的时间内完成消息的处理,那么coordinator就认为该consumer已经崩溃,从而引发新一轮rebalance。)
- 组订阅的topic分区发生变化
-
分配策略
- Range: 将单个topic的分区按照顺序排列,然后把这些分区划分成固定大小的分区段并一次分配给每个consumer
- round-robin策略: 将topic的每个分区轮询分配给每个分区
-
Rebalance流程
- 确定coordinator所在的broker,计算规则Math.abs(groupID.hashCode)%offsets.topic.num.parti-tions,并连接coordinator
- 组内所有consumer向coordinator发送joinGroup请求.收集全joinGroup请求后,从consumer选举一个担任gropu的leader(负责分区的分配)
- Leader consumer开始制定分配方案,一旦分配完成,leader将分配方案封装进SyncGroup中,并发送给coordinator,coordinator接收到分配方案后把属于每个consumer的方案单独抽取出来作为SyncGroup请求的response返还给各自的consumer。
-
FAQ
-
如何避免经常出现Rebalance
-
以下2种情况会导致coordinator认为comsumer已经下线
- 在session.timeout.ms 超时时间内未发送心跳
- 第二次pull拉取时间间隔超过max.poll.interval.ms
-
问题处理
- 在session.timeout.ms超时时间设置为heartbeat.interval.ms 心跳时间间隔的三倍,至少在一个周期内进行三次心跳(超时时间不能设置过长,不然会导致剔除消费者时间比较久,消费滞后,重复消费内容)
- max.poll.interval.ms 拉取间隔时间尽量大于业务处理时间
-
-