Kafka学习记录
简介
Kafka 是一个分布式的( distributed )、多分区的( partitioned )、多副本的( plicated )、提交日志( commitlog )的消息流服务。
“分布式”是所有分布式系统的特性 ;
“分区”指消息会按照分区分布在集群的所有节点上;
“副本”指每个分区都会有多个副本存储在不同的节点上;
“提交日志”指新的消息总是以追加的方式进行存储。
而Kafka直接使用提交日志作为最终的存储格式。
一、基本概念
节点:Broker,一个 kafka 实例,称为一个节点。
集群:Cluster,由一组 kafka 节点组成的节点群。
分区:Partition,消息的存储空间,每个 topic 将被分成多个(区)。(用于扩展,和 并行处理)
副本:Replication,partition 的备份。(用于容错)
片段:Segment,partition 物理上由多个 segment 组成,每个 segment 存着 index 信息和 message 信息。
消息:Message,在消费者和生产者之间传递的数据流。
主题 :Topic,通过对消息指定主题可以将消息分类,消费者可以只关注自己需要的 topic 中的消息。
生产者:Producer,向 kafka 集群发送消息,在发送消息之前,会对消息进行分类,即 topic。
消费者:Consumer,消费者通过与 kafka 集群建立长连接的方式,不断地从集群中拉取消息,然后可以对这些消息进行处理。
分组:Consumer Group,在 kafka 的设计中,可以有多个不同的消费者分组来同时消费同一个 topic 下的消息。
提交日志:Commit log,.log 文件,消息数据存储,存在于segment中。
索引:.index 文件,消息索引,存在于segment中。
偏移量:Offset,在 partition 内的每一条消息都有一个有序的id号,这个id号被称为 offset,它可以唯一确定消息在 partition 中的位置,即 offset 表示 partition 中的第多少条消息。
分区的每个副本存储在不同的broker节点上,每个副本都对应一个日志 在将分区存储到底层 文件系统上时,每个分区对应一个目录,
分区目录下有多个日志分段( LogSegment), 同一个目录下, 所有的日志分段都属于 一个分区。
每个日志分段在物理上 由一个数据文件和 一个索引文件组成 ,数据文件存储的是消息的真正内容,
索引文件存储的是数据文件的索引信息 为数据文件建立索引文件的目的是更快地访问数据文件。
二、架构
三、Zookeeper 在 kafka 的作用
元数据管理:Broker 注册、Topic 注册、Producer 和 Consumer 负载均衡、维护 Partition 与 Consumer 的关系、记录消息消费的进度以及 Consumer 注册等。
leader选举:
集群容错:
四、运行原理
Kafka 的大致工作模式:
1、启动 ZooKeeper 的 server
2、启动 Kafka 的 server,即 Broker
3、Producer 生产数据,然后通过 ZooKeeper 找到 Broker,再将数据 push 到 Broker 保存
4、Consumer 通过 ZooKeeper 找到 Broker,然后再主动 pull 数据
五、核心机制
broker controller选举:
broker 启动或者旧的 controller 故障后,最先写成功 Zookeeper 中 /controller临时节点 数据的 broker 即成为新的 controller。
- 从Zookeeper中读取当前分区的所有ISR(in-sync replicas)集合
- 调用配置的分区选择算法选择分区的leader
分区分配策略;
分区的 leader 选举:
controller会将leader的改变直接通过RPC的方式(比ZooKeeper Queue的方式更高效)通知需为此作为响应的Broker。不使用 zookeeper,避免 脑裂,羊群效应,zookeeper watch负载过高问题。
分区leader选择算法:
- NoOpLeaderSelector–偏爱分区(SR中的第一个),并将leader发送给为此做出改变的broker,
- OfflinePartitionLeader–也是选择偏爱分区作为leader
- ReassignedPartitionLeader
- PreferredReplicaPartitionLeader
- ControlledShutdownLeader
副本同步机制:LEO,HW
ISR机制:IN-SYNC Replication。ISR(同步副本集合), 维护了与 leader 信息一致的 follower 副本的信息,当 leader 挂掉的时候 就从这个 ISR 中选举新的 leader 。
文件存储机制:.log文件, .index 文件,稀疏索引,二分法
分片算法:hash取余 ?
限流机制:Quota 参数设置
consumer 心跳机制:
Kafka是通过心跳机制来控制超时,心跳机制对于消费者客户端来说是无感的,它是一个异步线程,当我们启动一个消费者实例时,心跳线程就开始工作了。
在org.apache.kafka.clients.consumer.internals.AbstractCoordinator中会启动一个HeartbeatThread线程来定时发送心跳和检测消费者的状态。
每个消费者都有个org.apache.kafka.clients.consumer.internals.ConsumerCoordinator,
而每个ConsumerCoordinator都会启动一个HeartbeatThread线程来维护心跳,心跳信息存放在org.apache.kafka.clients.consumer.internals.Heartbeat中。
幂等性:ProducerID和SequenceNumber
ProducerID:在每个新的Producer初始化时,会被分配一个唯一的ProducerID,这个ProducerID对客户端使用者是不可见的。
SequenceNumber:对于每个ProducerID,Producer发送数据的每个Topic和Partition都对应一个从0开始单调递增的SequenceNumber值。
事务:
Kafka中的事务与数据库的事务类似,Kafka中的事务属性是指一系列的Producer生产消息和消费消息提交Offsets的操作在一个事务中,即原子性操作。对应的结果是同时成功或者同时失败。
对Kafka来说,操作事务是指一系列的生产和消费等原子性操作。
控制器 - Controller
控制器,负责集群管理和协调,分区状态管理,副本状态管理。
更新集群元数据信息。
创建 topic。
删除 topic。
分区重分配。
preferred leader 副本选举。
topic 分区扩展。
broker 加入集群。
broker 崩溃。
受控关闭。
controller leader选举。
分区及副本分配
目标
- 在brokers之间均分replicas
- partition与它的其他replicas不再同一个broker上
- 如果broker有rack信息,则partition的replicas尽量分配在不同rack上面
算法
- 一种是rack unware
- 一种是rack-ware
分区分配
1、producer -> 分区
2、broker -〉分区
3、consumer -> 分区
- RangeAssignor分配策略;
- RoundRobinAssignor分配策略;
- StickyAssignor分配策略
Leader 选举
副本同步机制
所谓同步,必须满足如下两个条件:
- 副本节点必须能与zookeeper保持会话(心跳机制)
- 副本能复制leader上的所有写操作,并且不能落后太多。(卡住或滞后的副本控制是由 replica.lag.time.max.ms 配置)
ISR机制
Kafka的复制机制既不是完全的同步复制,也不是单纯的异步复制。
事实上,同步复制要求所有能工作的follower都复制完,这条消息才会被commit,这种复制方式极大的影响了吞吐率。
而异步复制方式下,follower异步的从leader复制数据,数据只要被leader写入log就被认为已经commit,这种情况下如果follower都还没有复制完,落后于leader时,突然leader宕机,则会丢失数据。
而Kafka的这种使用ISR的方式则很好的均衡了确保数据不丢失以及吞吐率。
副本不同步的异常情况:
- 慢副本:在一定周期时间内follower不能追赶上leader。最常见的原因之一是I / O瓶颈导致follower追加复制消息速度慢于从leader拉取速度。
- 卡住副本:在一定周期时间内follower停止从leader拉取请求。follower replica卡住了是由于GC暂停或follower失效或死亡。
- 新启动副本:当用户给主题增加副本因子时,新的follower不在同步副本列表中,直到他们完全赶上了leader日志。
文件存储机制
稀疏索引、二分法
通过offset查找message
1、使用offset 通过二分法定位对应的.index文件和.log 文件。
2、通过 .log文件顺序查找到对应的offset偏移对应的消息。
数据可靠性和一致性保证
ISR机制;
request.required.acks 参数;
min.insync.replicas 参数。
类似 PacificA 算法。
kafka消息传递语义
消息传递保障
- At most once: 消息可能会丢,但绝不会重复传输
- At least once:消息绝不会丢,但可能会重复传输
- Exactly once:每条消息肯定会被传输一次且仅传输一次
消息去重
- 业务端去重
六、高性能
顺序读写、
page cache、
零拷贝:senfile。
page cache
用作缓存磁盘文件的内存就叫做page cache。
CPU如果要访问外部磁盘上的文件,需要首先将这些文件的内容拷贝到内存中,由于硬件的限制,从磁盘到内存的数据传输速度是很慢的,
如果现在物理内存有空余,可以用这些空闲内存来缓存一些磁盘的文件内容,这部分用作缓存磁盘文件的内存就叫做page cache。
用户进程启动read()系统调用后,内核会首先查看page cache里有没有用户要读取的文件内容,如果有(cache hit),那就直接读取,
没有的话(cache miss)再启动I/O操作从磁盘上读取,然后放到page cache中,下次再访问这部分内容的时候,就又可以cache hit,不用忍受磁盘的龟速了(相比内存慢几个数量级)。
和CPU里的硬件cache是不是很像?两者其实都是利用的局部性原理,只不过硬件cache是CPU缓存内存的数据,而page cache是内存缓存磁盘的数据,这也体现了memory hierarchy分级的思想。
相对于磁盘,内存的容量还是很有限的,所以没必要缓存整个文件,只需要当文件的某部分内容真正被访问到时,再将这部分内容调入内存缓存起来就可以了,
这种方式叫做demand paging(按需调页),把对需求的满足延迟到最后一刻,很懒很实用。
七、消息可靠性保障(消息数据不丢失)
1、生产端:重试机制 + ACK(acknowledge)
2、服务端:多副本
3、消费端:手动提交
ACKS
配置生产端 ACK
当 producer 向 leader 发送数据时,可以通过 request.required.acks 参数以及 min.insync.replicas 设置数据可靠性的级别。
- 当 acks = 1时(默认值),生产者在 ISR 中的 leader 已成功收到数据可以继续发送下一条数据。如果 leader 宕机,由于数据可能还未来得及同步给其 follower,则会丢失数据。
- 当 acks = 0时,生产者不等待来自 broker 的确认就发送下一条消息。这种情况下数据传输效率最高,但数据可靠性确最低。
- 当 acks = -1或者 all 时,生产者需要等待 ISR 中的所有 follower 都确认接收到消息后才能发送下一条消息,可靠性最高。
即使按照上述配置 ACK,也不能保证数据不丢,例如,当 ISR 中只有 leader 时(ISR 中的成员由于某些情况会增加也会减少,最少时只剩一个 leader),
此时会变成 acks = 1的情况。所以需要同时在配合 min.insync.replicas 参数(此参数可以在消息队列 CKafka 控制台 Topic 配置开启高级配置中进行配置),
min.insync.replicas 表示在 ISR 中最小副本的个数,默认值是1,当且仅当 acks = -1或者 all 时生效。
建议配置的参数值
此参数值仅供参考,实际数值需要依业务实际情况而定。
- 重试机制:
message.send.max.retries=3;retry.backoff.ms=10000;
- 高可靠的保证:
request.required.acks=-1;min.insync.replicas=2;
- 高性能的保证:
request.required.acks=0;
- 可靠性+性能:
request.required.acks=1;
八、消息分发模型 - Kafka 发布消息时如何选择 Partition
Kafka 默认(当 key 为 null) 时采用 Round-robin 策略。
但我们实际应用中为保持相关消息按序到,就必须送到指定的 Partition,方法可以有:
- 指定 Partition 编号
- 指定 Key
- 自定义 Partitioner - 实现 org.apache.kafka.clients.producer.Partitioner, 并通过属性注册
消息发送模式:
发后即忘、同步、异步。
九、再均衡的发生过程
一句话:为消费者分配分区
Kafka中消费者以消费组的形式存在,消费组来消费每个主题中分区的数据,因为主题中的分区数和消费者数量并不一一对应,
这时候就涉及到如何为每个消费者分配分区,而当有消费者在中途退出时,就会触发再均衡的发生,再重新为剩余的消费者分配分区。
每个消费组在服务端对应一个GroupCoordinator对其进行管理,而消费者客户端中的ConsumerCoordinator组件负责与GroupCoordinator进行交互,
它们负责执行分区的分配,以及消费者再均衡的操作。
目前在以下几种情况会触发再均衡操作。
- 有新的消费者加入消费组。
- 消费者宕机下线。消费者并不一定需要真正下线,例如遇到长时间的GC、网络延迟等情况,导致消费者长时间未向GroupCoordinator 发送心跳,GroupCoordinator认为消费者已经下线。
- 有消费者主动退出消费组。
- 消费组所对应的GroupCoorinator 节点发生了变更。
- 消费组内所订阅的任一主题或者主题的分区数量发生变化。
再均衡时 cousumer 停止工作。
十、kafka扩容
1、新增节点
2、生成重新分配topic的方案
3、执行分配方案
4、查看分配进度、状态
注意:需要手动执行
十一、高级应用
注意:以下大部分功能原生不支持,需要定制开发。
过期时间(TTL)
延时队列
死信队列
重试队列
消息路由
消息轨迹
消息审计
消息代理(proxy)
十二、其他
副本同步
ISR(in-sync replicas):同步副本集合,只有 ISR 里的成员才有被选为 Leader 的可能。
OSR(Outof-sync replicas):
AR(Assigned Replicas):所有副本的总和。
AR = ISR + OSR
HW(HighWatermark):高水位。一个partition中的ISR列表中,leader的HW是所有ISR列表里副本中最小的那个的LEO。代表partition中已提交可消费的最大offset。
LEO(log end offset):日志末端位移,代表日志文件中下一条待写入消息的offset,这个offset上实际是没有消息的。
重要参数
request.required.acks:消息发送成功确认方式。
min.insync.replicas:设定ISR中的最小副本数是多少,默认值为1,当且仅当request.required.acks参数设置为-1时,此参数才生效。可以在broker或者topic层面进行设置。
offsets.topic.replication.factor:副本因子,最小写入副本数的个数,partition 副本数。数据冗余备份数。
unclean.leader.election.enable:ISR 副本同步列表 参与选举参数。
producer.type=sync:消息生产模式,同步模式,异步模式。
安装部署
kafka需要java运行环境,以前的kafka还需要zookeeper,新版的kafka已经内置了一个zookeeper环境,所以我们可以直接使用。
监控工具
Kafka Eagle
刷盘落盘
刷盘:pagecache -》硬盘
落盘:刷盘成功,数据成功写入硬盘