问题
一直以来,维护kafka的团队都以kafka io过高为由要求我们换SSD,那么kafka是否需要SSD呢?
SSD VS HDD
磁盘的两大指标:iops(读写次数),吞吐量
SSD和HDD的性能对比:
顺序写吞吐量大概是3~4倍
| Sequential Read/Write Speeds | |
|---|---|
| Solid State Drives | 300 to 500 MB/s |
| Hard Disk Drives | 100 to 160 MB/s |
随机写 iops相比hdd好太多
| Random Read/Write Speeds | |
|---|---|
| Solid State Drives | 20,000 to 100,000 IOPS |
| Hard Disk Drives | 75 to 100 IOPS |
分析
在对 Kafka 集群进行磁盘规划时经常面对的问题是,我应该选择普通的机械磁盘还是固态硬盘?前者成本低且容量大,但易损坏;后者性能优势大,不过单价高。
大量使用磁盘不假,可它使用的方式多是顺序读写操作,一定程度上规避了机械磁盘最大的劣势,即随机读写操作慢。从这一点上来说,使用 SSD 似乎并没有太大的性能优势,毕竟从性价比上来说,机械磁盘物美价廉,而它因易损坏而造成的可靠性差等缺陷,又由 Kafka 在软件层面提供机制来保证,故使用普通机械磁盘是很划算的。 but如果数据量很大,io负载比较高,还是可以换SSD,加上每台机器可能是多分区写入,多个partition或者多个topic的话,会有随机写入。还是要看实际的生产环境。
关于磁盘选择另一个经常讨论的话题就是到底是否应该使用磁盘阵列(RAID)。
使用 RAID 的两个主要优势在于:提供冗余的磁盘存储空间提供负载均衡以上两个优势对于任何一个分布式系统都很有吸引力。
不过就 Kafka 而言,一方面 Kafka 自己实现了冗余机制来提供高可靠性;另一方面通过分区的概念,Kafka 也能在软件层面自行实现负载均衡。如此说来 RAID 的优势就没有那么明显了。当然,我并不是说 RAID 不好,实际上依然有很多大厂确实是把 Kafka 底层的存储交由 RAID 的,只是目前 Kafka 在存储这方面提供了越来越便捷的高可靠性方案,因此在线上环境使用 RAID 似乎变得不是那么重要了。
综合以上的考量:追求性价比的公司可以不搭建 RAID,使用普通磁盘组成存储空间即可。使用机械磁盘完全能够胜任 Kafka 线上环境。
美团技术分享
对于Produce请求:Server端的I/O线程统一将请求中的数据写入到操作系统的PageCache后立即返回,当消息条数到达一定阈值后,Kafka应用本身或操作系统内核会触发强制刷盘操作(如上图左侧流程图所示)。
对于Consume请求:主要利用了操作系统的ZeroCopy机制,当Kafka Broker接收到读数据请求时,会向操作系统发送sendfile系统调用,操作系统接收后,首先试图从PageCache中获取数据(如中间流程图所示);如果数据不存在,会触发缺页异常中断将数据从磁盘读入到临时缓冲区中(如右侧流程图所示),随后通过DMA操作直接将数据拷贝到网卡缓冲区中等待后续的TCP传输。
综上所述,Kafka对于单一读写请求均拥有很好的吞吐和延迟。处理写请求时,数据写入PageCache后立即返回,数据通过异步方式批量刷入磁盘,既保证了多数写请求都能有较低的延迟,同时批量顺序刷盘对磁盘更加友好。处理读请求时,实时消费的作业可以直接从PageCache读取到数据,请求延迟较小,同时ZeroCopy机制能够减少数据传输过程中用户态与内核态的切换,大幅提升了数据传输的效率。
但当同一个Broker上同时存在多个Consumer时,就可能会由于多个Consumer竞争PageCache资源导致它们同时产生延迟。下面我们以两个Consumer为例详细说明:
如上图所示,Producer将数据发送到Broker,PageCache会缓存这部分数据。当所有Consumer的消费能力充足时,所有的数据都会从PageCache读取,全部Consumer实例的延迟都较低。此时如果其中一个Consumer出现消费延迟(图中的Consumer Process2),根据读请求处理流程可知,此时会触发磁盘读取,在从磁盘读取数据的同时会预读部分数据到PageCache中。当PageCache空间不足时,会按照LRU策略开始淘汰数据,此时延迟消费的Consumer读取到的数据会替换PageCache中实时的缓存数据。后续当实时消费请求到达时,由于PageCache中的数据已被替换掉,会产生预期外的磁盘读取。这样会导致两个后果:
- 消费能力充足的Consumer消费时会失去PageCache的性能红利。
- 多个Consumer相互影响,预期外的磁盘读增多,HDD负载升高。
美团SSD新缓存架构
Kafka的数据按照时间维度存储在不同设备上,对于近实时数据直接放在SSD上,针对较为久远的数据直接放在HDD上,然后Leader直接根据Offset从对应设备读取数据。这种方案的优势是它的缓存策略充分考虑了Kafka的读写特性,确保近实时的数据消费请求全部落在SSD上,保证这部分请求处理的低延迟,同时从HDD读取的数据不回刷到SSD防止缓存污染,同时由于每个日志段都有唯一明确的状态,因此每次请求目的明确,不存在因Cache Miss带来的额外性能开销。
- 首先新的缓存架构会将Log内的多个Segment按时间维度存储在不同的存储设备上,如图2-14中的红圈1,新缓存架构数据会有三种典型状态,一种叫Only Cache,指的是数据刚写进SSD,还未同步到HDD上;第2个是Cached,指数据既同步到了HDD也有一部分缓存在SSD上;第三种类型叫WithoutCache,指的是同步到了HDD但是SSD中已经没有缓存了。
- 然后后台异步线程持续地将SSD数据同步到HDD上。
- 随着SSD的持续写入,当存储空间达到阈值后,会按时间顺序删除距当前时间最久的数据,因为SSD的数据空间有限。
- 副本可根据可用性要求灵活开启是否写入SSD。
- 从HDD读取的数据是不会回刷到SSD上的,防止缓存污染。
总结
- PageCache污染。Kafka利用内核层提供的ZeroCopy技术提升性能,但是内核层无法区分实时读写请求和回溯读请求,导致磁盘读可能污染PageCache,影响实时读写。
- HDD在随机读写负载下性能差。HDD对于顺序读写友好,但是面对混合负载场景下的随机读写,性能显著下降。
对于以上出现的情况,可以换SSD。
或者本身io负载很高,要不考虑扩容,要不考虑换SSD。