作者:10灬月 | 来源:互联网 | 2023-10-14 18:34
大家好,这是一个为了梦想而保持学习的博客。这个专题会记录我对于KAFKA的学习和实战经验,希望对大家有所帮助,目录形式依旧为问答的方式,相当于是模拟面试。一、概述在对kafka有了
大家好,这是一个为了梦想而保持学习的博客。这个专题会记录我对于 KAFKA 的学习和实战经验,希望对大家有所帮助,目录形式依旧为问答的方式,相当于是模拟面试。
一、概述
在对 kafka 有了基础的认知之后,回过头来看看,当前 kafka 的 存储架构 还存在哪些问题呢?
很多地方有提到 kafka 无法承载大量的分区这个问题,但是都只给了个结论,没有说明其中缘由,这里我们就来梳理一下。
二、磁盘顺序写特性被破坏,导致写入吞吐量下降
我们从前面的【十一】小节知道,kafka 有如此高的写入吞吐量,主要是得益于追加写的性能极高,但是如果这个特性被破坏,那么写入吞吐量就会有明显的下降,那么什么时候会破坏这个特性呢?我们先从基本的磁盘 IO 说起。
机械硬盘的 IO 过程可以简单的理解为两个阶段:寻址 + 数据写入 其中寻址是个物理动作,就是需要通过旋转加上磁臂去找到对应的扇区,这个过程的耗时是毫秒级的,相对于其他计算机类的操作,高出了好几个数量级。 而数据写入呢,就是将我们的数据写入物理载体中,相对来说也是很快的。
从这个大概的过程中,我们知道,机械硬盘的 IO 过程慢就慢在寻址这个操作上,那我们有没有什么办法能优化掉这个过程呢?其中一个优化点就是追加写。
试想你一直只对一个文件进行写入,那么磁臂就根本就不需要再寻址了呀,接着往下写就好啦,所以就省去了寻址的这个开销,让写磁盘的性能能接近写内存。
也正是由于追加写的这个特性,在 Linux 的 IO 调度层面,有 4 种不同的调度策略,都尝试将随机的 IO 请求尽可能的合并成顺序写或者临近读,从而优化 IO 性能,在这里我简单的提一下,大家有兴趣可以进行查阅相关资料:
- NOOP:大致上就是所有进程共用一个先进先出队列,做了简单的相邻请求合并。
- CFQ(默认):特点是按照 I/O 请求的地址进行排序,而不是按照先进先出的顺序响应的,并且会为每个进程都创建一个这样特点的队列。但是存在 “饿死” 的场景,也就是我一个很小的读请求要读取很后面的地址,但是因为排序之后,被前面的很大的 I/O 请求给卡住了,导致无法被执行。
- DEADLINE:针对 CFQ 算法进行了优化,为每个请求设置了超时时间,如果达到了这么个时间一定要被调度执行,读等待时间为 500ms,写等待时间为 5s。
- ANTICIPATORY:为每个 I/O 都设置 6ms 的等待时间窗口,如果 6ms 内收到了相邻的 I/O 请求,那么就进行合并,通过增加时间的方式来获取更高的性能,尽可能的将随机读写转换为顺序读写。
进入正题,为什么 kafka 的分区数多了知道会破坏追加写的特性呢?
分区底层对应的是底层一个个 segment 文件,如果一个 broker 上,有上万个分区,那么对应的就需要去写上万个 segment,那么从磁盘的角度来说就是我刚写完 A 文件,又要重新寻址去写 B 文件,以此类推,当文件一多,就相当于是随机 IO 了,追加写的特性就由此被破坏,写入吞吐量就受到了非常大的影响。另外提一句,RocketMQ 就是基于这个原因将所有分区数据都写到一个 commitLog 中来规避这个问题。
最后再提一句,我们在说随机 I/O 和追加写的时候,是站在磁盘的角度去说的,跟上层持不持有 file 的引用或者用什么流去写入没有什么关系,这也是我之前认知的一个误区。
另外就是,这个问题只会存在于机械硬盘,云盘和 SSD 都不会存在,因为云盘走的是带宽,而 SSD 是元器件也不需要物理旋转寻址。
三、集群故障转移受影响,导致故障转移耗时增加
另外一个影响点就是我们日常运维会遇到的问题,故障转移和集群状态恢复时间受到影响。
其中的影响点主要是由于 kafka 故障转移时主要依靠 controller+zk 去实现的,而整个过程的是单线程顺序去执行的,整个过程大概分为:计算新的 leader + 更新 zk 数据 + 通知其他节点将 follower 变为 leader + 更新元数据。而在这个过着执行完之前,对应受影响的分区都是没有 leader 可以去提供读写服务的,所以对业务的影响是很大的。
试想我们集群有几十万的分区数,那么这个过程将非常耗时,达到分钟级别甚至小时级别。但是 kafka 在 1.1.0 版本优化了这个问题,主要优化点三个:zk 批量异步写 / 批量计算通知 / 日志优化。
具体参见胡夕大佬的翻译文章:【译】Apache Kafka 支持单集群 20 万分区
四、元数据太过庞大,导致更新元数据操作变重
这个问题就是显而易见的了,当分区数很多的时候,整个集群的元数据将会变得庞大,一旦集群状态变化,整个集群都会更新元数据,但是由于元数据太过庞大会让这个更新操作变得非常沉重。
五、日志清理受影响
kafka 的日志文件操作,是 broker 有个后台清理线程去定时检查执行的,一旦一台 broker 上的文件过多,会导致线程处理不过来,无法及时清理掉对应的磁盘文件,从而导致磁盘被打满等异常情况。