乐趣区

关于kafka:Kafka消息存储机制

Kafka 音讯以 Partition 作为存储单元,那么在 Partition 那音讯是以什么样的格局存储的呢,如何解决 Partition 中的音讯,又有哪些安全策略来保障音讯不会失落呢,这一篇咱们一起看看这些问题。

Partition 文件存储形式 #
每个 Topic 的音讯被一个或者多个 Partition 进行治理,Partition 是一个有序的,不变的音讯队列,音讯总是被追加到尾部。一个 Partition 不能被切分成多个散落在多个 broker 上或者多个磁盘上。

它作为音讯治理名义上最大的管家内里其实是由很多的 Segment 文件组成。如果一个 Partition 是一个单个十分长的文件的话,那么这个查找操作会十分慢并且容易出错。为解决这个问题,Partition 又被划分成多个 Segment 来组织数据。Segment 并不是终极存储,在它的上面还有两个组成部分:

索引文件:以 .index 后缀结尾,存储以后数据文件的索引;
数据文件:以 .log 后缀结尾,存储以后索引文件名对应的数据文件。

Segment 文件的命名规定是:某个 Partition 全局的第一个 Segment 从 0 开始,后续每个 Segment 文件名以以后 Partition 的最大 offset(音讯偏移量)为基准, 文件名长度为 64 位 long 类型,19 位数字字符长度,有余局部用 0 填充。

如何通过 offset 找到 某一条音讯呢?
首先会依据 offset 值去查找 Segment 中的 index 文件,因为 index 文件是以上个文件的最大 offset 偏移命名的所以能够通过二分法疾速定位到索引文件。
找到索引文件后,索引文件中保留的是 offset 和对应的音讯行在 log 日志中的存储型号,因为 Kafka 采纳稠密矩阵的形式来存储索引信息,并不是每一条索引都存储,所以这里只是查到文件中合乎以后 offset 范畴的索引。
拿到 以后查到的范畴索引对应的行号之后再去对应的 log 文件中从 以后 Position 地位开始查找 offset 对应的音讯,直到找到该 offset 为止。
每一条音讯的组成内容有如下字段:

Copyoffset: 4964(逻辑偏移量)
position: 75088(物理偏移量)
CreateTime: 1545203239308(创立工夫)
isvalid: true(是否无效)
keysize: -1(键大小)
valuesize: 9(值大小)
magic: 2
compresscodec: NONE(压缩编码)
producerId: -1
producerEpoch: -1(epoch 号)
sequence: -1(序号)
isTransactional: false(是否事务)
headerKeys: []
payload: message_0(音讯的具体内容)

为什么要设计 Partition 和 Segment 的存储机制

Partition 是对外名义上的数据存储,用户了解数据都是顺序存储到 Partition 中。那么理论在 Partition 内又多了一套不对用户可见的 Segment 机制是为什么呢?起因有两个:

一个就是下面提到的如果应用单个 Partition 来治理数据,程序往 Partition 中累加写势必会造成单个 Partition 文件过大,查找和保护数据就变得十分艰难。
另一个起因是 Kafka 音讯记录不是始终堆堆堆,默认是有日志革除策略的。要么是日志超过设定的保留工夫触发清理逻辑,要么就是 Topic 日志文件超过阈值触发革除逻辑,如果是一个大文件删除是要锁文件的这时候写操作就不能进行。因而设置分段存储对于革除策略来说也会变得更加简略,只需删除较早的日志块即可。
Partition 高可用机制 #
提起高可用咱们大略猜到要做正本机制,多弄几个备份必定好。Kafka 也不例外提供了正本的概念(Replica),通过正本机制来实现冗余备份。每个 Partition 能够设置多个正本,在正本汇合中会存在一个 leader 的概念,所有的读写申请都是由 leader 来进行解决。残余正本都作为 follower,follower 会从 leader 同步消息日志。

罕用的节点选举算法有 Raft、Paxos、Bully 等,依据业务的特点 Kafka 并没有齐全套用这些算法,首先有如下概念:

AR:分区中的所有正本统称为 AR (Assigned Replicas)。
ISR:in-sync replics,ISR 中存在的正本都是与 Leader 同步的正本,即 AR 中的正本不肯定全副都在 ISR 中。ISR 中必定蕴含以后 leader 正本。
OSR:Outof-sync Replicas,既然 ISR 不蕴含未与 leader 正本同步的正本,那么这些同步有提早的正本放在哪里呢?Kafka 提供了 OSR 的概念,同步有问题的正本以及新退出到 follower 的正本都会放在 OSR 中。AR = ISR + OSR。
Hight Watermark:正本水位值,示意分区中最新一条已提交 (Committed) 的音讯的 Offset。
LEO:Log End Offset,Leader 中最新消息的 Offset。
Committed Message:已提交音讯,曾经被所有 ISR 同步的音讯。
Lagging Message:没有达到所有 ISR 同步的音讯。
每个 Partition 都有惟一一个预写日志(write-ahead log),Producer 写入的音讯会先存入这里。每一条音讯都有惟一一个偏移量 offset,如果这条音讯带有 key,就会依据 key hash 值进行路由到对应的 Partition,如果没有指定 key 则依据随机算法路由到一个 Partition。

Partition leader 选举 #
一个 Topic 的某个 Partition 如果有多正本机制存在,失常状况下只能有一个 正本是对外提供读写服务的,其余正本从它这里同步数据。那么这个对外提供服务的 leader 是如何选举进去的呢?这个问题要分为两种状况,一种是 Kafka 首次启动的选举,另一种是启动后遇到故障或者增删正本之后的选举。

首次启动的选举
当 broker 启动后所有的 broker 都会去 zk 注册,这时候第一个在 zk 注册胜利的 broker 会成为 leader,其余的都是 follower,这个 broker leader 后续去执行 Partition leader 的选举。

首先会从 zk 中读取 Topic 每个分区的 ISR;
而后调用配置的分区抉择算法来抉择分区 leader,这些算法有不同的应用场景,broker 启动,znode 发生变化,新产生节点,产生 rebalance 的时候等等。通过算法选定一个分区作为 leader 就确定了首次启动选举。
后续变动选举
比方分区产生重调配的时候也会执行 leader 的选举操作。这种状况会从重调配的 AR 列表中找到第一个存活的正本,且这个正本在目前的 ISR 列表中。

如果某个节点被优雅地敞开(也就是执行 ControlledShutdown)时,位于这个节点上的 leader 正本都会下线,所以与此对应的分区须要执行 leader 的选举。这里的具体操作为:从 AR 列表中找到第一个存活的正本,且这个正本在目前的 ISR 列表中,与此同时还要确保这个正本不处于正在被敞开的节点上。

Partition 正本同步机制 #
一旦 Partition 的 leader 确定后续的写音讯都会向这个正本申请操作,其余正本都会同步它的数据。下面咱们提到过几个概念:AR、ISR、OSR,在正本同步的过程中会利用到这几个队列。

首先 ISR 队列必定蕴含以后的 leader 正本,也可能只有 leader 正本。什么状况下其余正本可能进入到 ISR 队列呢?

Kafka 提供了一个参数设置:rerplica.lag.time.max.ms=10000,这个参数示意 leader 正本可能落后 flower 正本的最长工夫距离,以后默认值是 10 秒。就是说如果 leader 发现 flower 超过 10 并没有向它发动 fetch 申请,那么 leader 就认为这个 flower 出了问题。如果 fetch 失常 leader 就认为该 Follower 正本与 Leader 是同步的,即便此时 Follower 正本中保留的音讯显著少于 Leader 正本中的音讯。

例如上图中的两个 follower 显著慢于 leader,然而如果落后的工夫在 10 秒内,那么这三个正本都会在 ISR 中存在,否则,落后的正本会被剔除并退出到 OSR。

当然如果前面 follower 逐步追上了 leader 的进度,那么该 follower 还是会被退出到 ISR,所以 ISR 并不是一个固定不变的汇合,它是会动静调整的。

leader 和 follower 之间的数据同步过程大略如下:

初始状态下 leader 和 follower 的 HW 和 LEO 都是 0,follower 会一直地向 leader 发送申请 fetch 数据。然而因为没有数据,这个申请会被 leader 强制拖住,直到达到咱们配置的 replica.fetch.wait.max.ms 工夫之后才会被开释。同时如果在这段时间内有数据产生则间接返回数据。

Producer 提交 commit 确认机制 #
Producer 向某个 Topic 推过来一条音讯,以后 Topic 的 leader Partition 进行相应,那么如果其余 follower 没有同步胜利音讯会怎么样呢?这个问题 Kafka 交给用户来决定。

producer 提供了如下配置:

Copyrequest.required.asks=0

0:全异步,无需 leader 确认胜利立即返回,发送即胜利。
1:leader 接管到音讯之后才发送 ack,无需 ISR 列表其余 follower 确认。
-1:leader 和 ISR 列表中其余 follower 都确认接管之后才返回 ack,根本不会失落音讯 (除非你的 ISR 外面只有 leader 一个正本)。
能够看到以上确认机制配置逐级严格,生产环境综合思考个别抉择配置 = 1,如果你的业务对数据完整性要求比拟高且能够接收数据处理速度稍慢那么抉择 = 2。

offset 保留 #
某个生产组生产 partition 须要保留 offset 记录以后生产地位,0.10 之前的版本是把 offset 保留到 zk 中,然而 zk 的写性能不是很好,Kafka 采纳的计划是 consumer 每分钟上报一次,这样就造成了反复生产的可能。

0.10 版本之后 Kafka 就 offset 的保留从 zk 剥离,保留到一个名为 consumer_offsets 的 Topic 中。音讯的 key 由 [groupid、topic、partition] 组成,value 是偏移量 offset。Topic 配置的清理策略是 compact。总是保留最新的 key,其余删掉。个别状况下,每个 key 的 offset 都是缓存在内存中,查问的时候不必遍历 Partition,如果没有缓存第一次就会遍历 Partition 建设缓存而后查问返回。

关键词:大数据培训

退出移动版