几个关于kafka的知识点
认识kafka
Kafka
是分布式消息系统, Apache
的子项目。标语也变了"分布式流平台",
与传统的消息系统不同点在于
- 分布式的,易于扩展
- 为发布和订阅提供了高吞吐
- 支持多订阅者,在失败的时候能自动平衡消费者
- 消息的持久化
kafka
的架构
几点?
Kafka
的Topic
和Partition
内部如何存储?- 与传统的消息系统相比,
Kafka
消费模型有啥优点? Kafka
是如何实现分布式数据存储和数据的读取?
Kafka
架构
一个 Kafka
集群,多个 Producer
,多个 Consumer
,多个 Broker
, 选举 Leader
以及在 Consumer Group
发生变化时进行 reblance
。
Broker
消息中间件的处理节点,一个Kafka
节点就是一个Broker
, 一个或者多个Broker
组成Kafka
集群Topic
Kafka
根据Topic
对Message
进行归类,发布到Kafka
的每条Message
都要指定Topic
Producer
向Broker
发生message
Consumer
从Broker
读取message
Consumer Group
每个 Consumer 属于特定的 Group,一个 Message 可以发送给不同的Consumer Group
,但是同一个Group
下的只有一个Consumer
能消费该Message
Partition
物理概念,一个Topic
下可以分为多个Partition
, 每个Partition
下是有序的。
下面来讲述 上面为问题啊
Kafka
的 Topic
和 Partition
内部如何存储?
Kafka
为每个 Topic
维护了分区( Partition
)的日志文件,每个 Partition
在 kafka
存储层为 Append Log
。任何发布到此 Partition
的消息都会被追加到 Log
文件尾部。
在每个 Partition
每个消息是按照 Timeline
分配到一个单调递增的顺序编号的,就是我们说的 Offset
, Offset
是一个 long
型的数字,也是我们可以通过这个 Offset
确定一条在该 Partition
下的唯一消息。
这样就有个特性: Partition
下有序, Topic
下无法保证有序。
那么,问题来了?这些 Message
如何发送到各个 Partition
的呢?如何指定的呢?
- 发送至哪个
Partition
是由 生产者决定的。 - 如果没有
Key
值,则轮询发送 - 如果有
key
值,对key
值进行Hash
,然后对分区数量取余,保证同一个Key
值的会路由到同一个Partition
。如果想队列强顺序一致,可以让所有的消息设置为同一个Key
。
与传统的消息系统相比, Kafka
消费模型有啥优点?
Kafka Consumer
消费模型
消息由 producer
发送到 Kafka
集群后,被 Consumer
消费,一般来说我们的消费模型有两种: Push
推送模型 和 Pull
拉取模型
Push
推送模型:
消息
Broker
记录消费状态。消息Broker
将消息推送给消费者后,记录这条消息已经被消费,但是这种方式无法很好的保证消费处理的语义。 消息推送完成后,消费者挂掉或者线程 Hang 住 ,或者网络原因未收到,但是 消息Broker
将其标记为已消费,这个消息将永远丢失了。 也就是说,采用Push
,消息消费完全依赖 消息Broker
控制,一旦Consumer
发生阻塞,会出现问题。
Pull
拉取模型:
由
Consumer
控制Speed
,以及消费Offset
,Consumer
可以按照任意的偏移量进行Consumer
Consumer
可以回放已经消费过的消息,进行重新处理或者消费最近的消息
Kafka
的网络模型
Kafka Client
单线程 Selector
并发链接数目小,逻辑简单,数据量小。在
Kafka Consumer
和Kafka Producer
都是采用的 单线程模型。
kafka Server
多线程 Selector
Acceptor
运行于一个单独的线程,对于读取操作的线程池中线程都是在selector
注册Op_Read
事件,负责服务端读取请求。 成功读取后,将请求放入Message Queue
共享队列中,然后在 写操作的线程池中,取出这个请求,对其进行逻辑处理。 即使某个线程阻塞了,后面还有后续的线程从Message Queue
共享队列里面获取请求进行处理。 写线程处理完逻辑后,由于注册了Op_Write
事件,还需要发送响应。
Kafka
是如何实现分布式数据存储和数据的读取?
Kafka
高可靠的分布式存储模型
主要依靠 副本 机制,有了副本机制,机器宕机,也会恢复。
Kafka
高性能日志存储
Kafka
的一个 Topic
下的所有的 Message
都是以 Partition
的方式,分布式存储在多个节点上。
同时在 kafka 机器上,每个 Partition
都会对应一个日志目录,在目录下面会对应对歌 日志分段(LogSegment
)。
LogSegment 组成 “.index” 与 “.log” , 分别表示 segment
索引文件 和 数据文件。
两个文件的命名规则: partition
全局的第一个 segment
从 0 开始,后续的每个 Segment
文件名为上一个 Segment
文件最后一条消息的 offset
值。
数值为 64 位, 20 位数字字符长度,没有数字用 0 填充。
假如有 1000 条消息,每个 LogSegment
的大小为 100,那么展现 900-1000 的索引 和 Log:
kafka
消息数据量打,采用的是 稀疏索引
的方式,加快偏查询速度。
如何读取数据? 如果我们要读取第 911 条数据
- 先找到它属于哪个段? 二分法查找属于文件,找到 0000900.index 和 0000900.log 之后
- 去索引文件 0000900.index 查找 (911-900)=11 这个索引 或者 小于11 最近的索引
- 后面通过 二分法我们找到索引 [10,1367]
- 然后通过这条索引的物理位置 1367,开始往后找,知道找到 第 911 条数据
为什么分区?只有一个分区不行么?分区是为了干啥?那么日志为什么要分段呢?
Kafka
的副本机制
Kafka
副本机制为 多个节点对其他服务端节点的主题分区的日志进行复制。当集群某个节点出现问题,访问该故障节点的请求可以被转移到其他正常的节点(过程脚 reblance
)
kafka
的每个 Topic
的每个 Partition
都有一个 主副本以及 0-n
个副本,副本保持与主副本的数据同步,当 主副本 出现故障时会被替代。
在 kafka
中,并不是所有的副本都被拿来代替主副本的,所以在 kafka
的 leader
节点中维护者一个 ISR(In Sync Replicas)
集合
ISR (In Sync Replicas)
副本 follower
同步队列, 维护着有资格的 follower
的节点
- 副本的所有节点必须和
ZK
保持链接 - 在同步过程中,这个副本不能落后主副本太多(即副本最后一条消息的
offset
和leader
副本的最好一条消息的offset
之间的差值不能超过阈值) (replica.lag.max.messages
)
AR(Assigned Replicas)
标记副本的全集 ,OSR
表示落后被剔除的副本集合
ISR = leader + 没有落后太多的副本 AR = OSR + ISR
HW & LEO
Follower
副本同步过程中,两个概念 HW
HighWatermark
和 LEO
Log End Offset
,与 ISR
紧密相关。
HW
是一个特殊的 Offset
,当 Consumer
处理消息的时候,只能 Pull
到 HW
之前的消息, HW
之后的消息对 Consumer
不可见。
也就是说 Partition
对应的 ISR 中最小的 LEO
作为 HW
, Consumer
最多只能消费到 HW
所在的位置,每个 Replica
都有 HW
,
leader
和 follower
各自维护更新自己的 HW
的状态,对于 Leader
新写入的消息, Consumer
不能立刻消费, Leader
会等待
该消息被所有的 ISR
中的 Replicas
同步更新 HW
,此时消息才能被 Consumer
消费,这样保证了如果 Leader
副本损坏,
该消息仍然可以从新选举的 Leader
获取。
LEO
是所有副都会有的一个 offset
标记,它指向追加到当前副本的最后一个消息的 offset
,当生产者向 Leader
副本追加消息时候, Leader
副本的 LEO
标记就会递增;
当 follower
副本成功从 leader
副本 pull
消息并更新到本地的时候, follower
副本也会增肌
producer
向leader
发送消息,可以通过request.required.acks
参数来设置数据可靠性级别:
- 1 默认,
producer
在ISR
中的leader
已成功收到数据并得到确认后发送下一条Message
。如果Leader
宕机,会丢失数据- 0
producer
无需等待,继续发送下一批消息,效率高,但是数据可靠性低- -1
producer
需要等待ISR
中所以的follower
都确认接收到数据才算发送完成。可靠性高,但是没有也不能保证数据不丢失,比如ISR
里只有leader
(其他节点和ZK
断链,或者没有追上),这样就变成了acks=1
的情况
kafka
到底会不会丢消息
一个消息的流转
Producer
发送给Kafka Broker
kafka Broker
消息同步和持久化Kafka Brokder
将消息传递给消费者
如何优雅的使用 Kafka Consumer
注意点等等…..
kafka Producer
流程详细