owenqing 联系🪐

关于 kafka 的一些经验

1. kafka 高性能原因

  1. PageCache + 顺序写磁盘 (读与写)
    1. producer 请求:Server端的I/O线程统一将请求写到操作系统的 PageCache 后立即返回,当消息达到一定阈值后, Kafka 应用本身会操作系统内核会触发强制刷盘
    2. comsumer 请求: 主要利用了 zero copy 技术,当 broker 接收到读取数据的请求时,会向操作系统发送 sendfile 系统调用,操作系统接收后,首先试图从 PageCache 中获取数据。如果不存在,则发生缺页中断将数据读取到 kernel buffer, 随后通过 DMA 直接将数据拷贝到网卡。
  2. Zero Copy 零拷贝技术 (跳过用户态缓冲区)
  3. 分区技术
  4. 批量发送
  5. 数据压缩

【阅读】基于SSD的Kafka应用层缓存架构设计与实现

2 kafka 消息丢失问题

MQ 消息丢失一般可以从三个阶段讨论:producer, broker, comsumer

2.1 生产者阶段

为了提高效率,kafka 在生产者端会攒批发送(达到一定的量或超过时间阈值就会发送)如果程序崩溃,buffer 中的数据会丢失
解决方案:

  1. 异步发送改同步发送
  2. 消息先写入日志,在通过 filebeat 等工具发送(提供更大的缓冲池)

2.2 Broker 阶段

这是个同步刷盘和异步刷盘的问题,异步刷盘就有丢失数据的风险。Linux 刷盘触发条件:

  • 主动调用sync或fsync函数
  • 可用内存低于阀值
  • dirty data时间达到阀值。dirty是pagecache的一个标识位,当有数据写入到pageCache时,pagecache被标注为dirty,数据刷盘以后,dirty标志清除

Kafka 没有提供同步刷盘的机制,也就是说靠单个 broker 是无法保证消息的完整性的。 kafka 通过 producer 与 kbroer 协调来尽可能的保证消息不丢失。

kafka通过producer和broker协同处理单个broker丢失参数的情况。一旦producer发现broker消息丢失,即可自动进行retry。除非retry次数超过阀值(可配置),消息才会丢失。此时需要生产者客户端手动处理该情况。那么producer是如何检测到数据丢失的呢?是通过ack机制,类似于http的三次握手的方式

ack 参数:

0 producer不等待broker的响应,效率最高,但是消息很可能会丢
1 leader broker收到消息后,不等待其他follower的响应,即返回ack (数据写入 leader 的 PageCache 就会返回 ack。数据刷盘成功后才会开启复制。follower 没有拉取完整数据 leader 挂了,则消息丢失)
-1(all) 写入 leader, 等待所有的 ISR( in sync replicas 可配置) follwer 都确认了,在返回 ack。(leader 挂掉,重新选举。如果这时 follwer 全部挂了(掉电),消息就丢失了,非常极端)

【阅读】kafka 消息问题

3. Kafka 数据清理

  1. delete 模式
  2. compact 模式
  3. compact & delete 模式

设置模式 log.cleanup.policy = compact。可以设置到 topic 级别

3.1 删除策略

# delete 模式
cleanup.policy     => delete
segment.bytes      => 1.07G                             
segment.ms         => 7 days      (与上一参数共同控制 segment 滚动逻辑)
retention.ms       => 7 day				(消息保留时间)
retention.bytes    => Infinite    (保留大小)

# compact 模式
cleanup.policy            => compact
segment.bytes             => 1.07G                             
segment.ms                => 180 days  (与上一参数共同控制 segment 滚动逻辑)
min.cleanable.dirty.ratio => 0.5%      (默认 0.5 重复)   

min.cleanable.dirty.ratio脏数据比例:未清理的数据和已清理数据的比例 0.5% 没什么问题
compcat 模式起初导入数据时可以调整 segment.ms为 1-2 min,快速生成 segment 文件,进行 compat。观察到 topic 存储大小降下来稳定后,设置为 180days。
注意:segment.ms 时间多小会导致非常多的小文件。

delete.retention.ms墓碑消息保留时间。时间过短会有问题, 设置 1 day 就好
消息序列 => [+1, + 2, +3, -1, -2, -3] 。消费者读取到+3就挂了,压缩后墓碑消息被删除。就丢失了 -1, -2, -3 的数据信息。为了避免出错,消费者不能停止太久

4. kafka partiton 数量对集群性能的影响

partition 数量越多会提升吞吐,过多也会有问题
过多 partition 数量的危害:

  1. 文件句柄开销。每个 partiton 都有很多 segment 文件(xx.log xx.index)分区越多文件越多,可能突破 ulimit -n 的限制,从而抛出 open too many file 的异常
  2. 降低系统可用性。parttion 数量越多的 topic 选举耗时越久
  3. 客户端与服务端内存开销大。(socket 建立与客户端 batch 缓存)

注:经验策略,峰值 1000/s, 平均 300/s 可设置一个 partition

5. 如何解决消息消费不过来

  1. 消费者并发消费(顺序无法保障)
  2. 扩充 partiton (顺序无法保障)

消费者消费不动原因排查:
max.poll.records 默认 500
max.poll.interval.ms 默认 300s。两次 poll 之间的间隔,超过这个时间会触发 rebalance
如果消费时间频繁超过 max.poll.interval.ms会表现为消费不动。

如果出现上述现象可以考虑:

  1. 降低 poll 的数量,每次少消费一点
  2. 提高消费能力

6. Kafka 文件存储机制

foo topic 4 个分区

|--foo-0
|--foo-1
|--foo-2
|--foo-3

每个 partition 中有很多 segment 文件。
segment 由 xxx.index xxx.log 索引文件和数据文件组成。

image.png
image.png

kafka 高效文件存储设计特点:

  • 将 partition 数据拆分成多个 segment,利于过期清除与压缩,减少磁盘占用
  • 通过索引信息可以快速定位message和确定response的最大大小
  • 通过索引文件稀疏存储,可以大幅降低index文件元数据占用空间大小
  • 通过index元数据全部映射到memory(mmap),可以避免segment file的IO磁盘操作

【阅读】kafka 文件存储那些事儿

7. 消费者分区分配策略

kafka partion 与 消费组成员数量对应关系发生变化时会触发 rebalance。这时会重新分配对应关系。

  • range
    • 首先对同一个Topic里面的分区按照序号进行排序,并对消费者按照字母顺序进行排序。然后用Partitions分区的个数除以消费者线程的总数来决定每个消费者线程消费几个分区。如果除不尽,那么前面几个消费者线程将会多消费一个分区
  • round-robin
    • partition按照字典序排序,然后通过轮询方式逐个将分区以此分配给每个消费者
  • sticky
    1. 分区的分配要尽可能的均匀,分配给消费者者的主题分区数最多相差一个
    2. 分区的分配尽可能的与上次分配的保持相同
    3. 当两者发生冲突时,第一个目标优先于第二个目标

【阅读】Kafka 消费组的三种分区分配策略

8. kafka 副本相关问题

8.1 AR ISR OSR

AR (Assigned Replicas) 分区中所有的副本
ISR (In Sync Replicas) 与 leader 保持一定程度同步的副本
OSR (Out of Sync Replicas) 与 leader 同步之后过多的副本
\(AR = ISR + OSR\)

leader副本负责维护和跟踪ISR集合中所有follower副本的滞后状态,当follower副本落后太多或失效时,leader副本会把它从ISR集合中剔除。如果OSR集合中有follower副本“追上”了leader副本,那么leader副本会把它从OSR集合转移至ISR集合。默认情况下,当leader副本发生故障时,只有在ISR集合中的副本才有资格被选举为新的leader,而在OSR集合中的副本则没有任何机会(不过这个原则也可以通过修改相应的参数配置来改变)

8.2 HW 与 LEO

HW (High Watermark) 一个特定的偏移量,消费者只能读取到这个 offset 之前的消息
LEO (Log End Offset),标识下一条带写入消息的 offset。分区 ISR 集合中的每个副本都会维护自己的 LEO, 集合中最小的 LEO 极为分区的 HW, 对于消费者而言只能消费 HW 之前的消息

注:副本同步完成了才能被消费。LEO 与 HW 的差值标识了数据复制的差距
【阅读】什么是AR、OSR、ISR、HW和LEO以及之间的关系

8.3 如何判断副本失效

replica.lag.time.max.ms超过这个配置的时间认为副本失效。副本会被踢出 ISR
导致副本失效的原因:

  1. follwer 副本进程卡住,无法进行同步,如 Full GC
  2. I/O 开销大,无法追赶上 leader 副本
posted @ 2023-03-29 19:51  owenqing  阅读(187)  评论(0)    收藏  举报