kafka中,压缩,说白了就是,以较少的CPU开销去换更少的磁盘占用或更少的网络I/O传输。
- 怎么压缩
kafka的消息格式分为两种,社区分别成为V1版本和V2版本,V2版本是在0.11.0.0中正式引入。不论哪个版本,kafka消息层次都分为两层:消息集合(message set)以及消息(message)。一个消息集合包含若干日志项,而日志项才是真正封装消息的地方。kafka底层的消息日志由一系列消息集合日志项组成。kafka通常不会直接操作具体的一条消息,总是在消息集合层面进行写入操作。
V2版本主要是针对V1版本的一些弊端作了修正,一个是,就是把消息的公共部分抽取出来放到外层消息集合里面,这样就不用每条消息都保存这些信息了。比如,关于CRC校验,V1版本中,每条消息都需要执行CRC校验,但有些情况的CRC校验是会发生变化的:
broker端可能会对消息时间戳字段更新,重新计算后的CRC会更新;
broker端执行消息格式转化(兼容老版本)时,也会带来CRC值的变化。
鉴于这些情况,再对每条消息执行CRC校验就没必要了,不进浪费空间还浪费CPU时间,因此,V2版本的CRC校验就被移到消息集合这一层。先在message set层面校验,如果校验不成功,再做解压缩操作,挨个校验message,找出损坏的那些。
另外一个改进,就是保存压缩消息的方法发生变化,V1版本保存消息的方法是把多条消息进行压缩然后保存到外层消息的消息体字段中,V2版本则是对整个消息集合进行压缩,显然V2版本有更好压缩效果。
- 何时压缩
kafka中压缩可能发生在两个地方:生产者端和Broker端。
生产者端启用指定类型的压缩算法,这样生产的每个消息集合都是经GZIP压缩过的,故而很好滴节省网络传输带宽以及broker端的磁盘占用。然后在大部分情况下,broker端从Producer端接收消息后仅仅是原封不动地保存而不会对齐进行任何修改,但是也有例外情况,可能会让broker端重新压缩消息。
情况一:broker端指定了和producer端不同的压缩算法。打开官网会发现broker端会有一个参数叫compression.type,默认值是producer,但是如果指定了不同的值,那么就可能会发生预料之外的压缩/解压缩,使broker端CPU使用率飙升。
情况二:broker端发生消息格式转化。在一个kafka集群中同时保存多种版本的消息格式,broker端会执行新版本消息向老版本格式的转换。这个过程会涉及解压缩和重新压缩,一般情况,这种消息格式转换对性能有很大影响,还让kafka丧失Zero Copy特性。
- 何时解压缩
通常的解压缩发生在消费者程序中,也就是说producer发送消息到broker端,broker照单全收并原样保存。当consumer程序请求这部分消息时,broker端依然原样发出去,由consumer自行解压缩还原成之前的消息。那么consumer怎么知道消息用何种压缩算法,kafka会将启用的压缩算法封装进消息集合中,consumer读取消息集合时,自然就知道消息使用哪种压缩算法。
另外,broker端也会发生解压缩,这和前面说的消息格式转换时的解压缩不是一个场景。每个压缩过的消息集合在broker端写入时都要发生解压缩操作,目的就是对消息执行各种验证,比如CRC校验和compact类型主题检查可以是否存在,这个对broker段的性能是有影响的,特别是CPU使用率。最近,京东的伙伴们刚刚向社区提交了bugfix,建议去掉因为做消息校验引入的解压缩。据他们称,去掉解压缩,broker端CPU使用率至少降低50%。目前,社区已经修复这方面问题,即在2.4版本中移除了因校验而引入的解压缩操作。
- 各种压缩算法对比
在kafka2.1.0版本之前,支持3种压缩算法:GZIP、Snappy、LZ4。在2.1.0版本开始,引入zstd(Zstandard,Facebook开源的压缩算法),提供超高的压缩比。看一个压缩算法的优劣,有两个重要指标:压缩比,原先100份的空间经压缩之后变成占20份空间,那么压缩比就是5。另一个指标就是压缩/解压缩吞吐量,即每秒能压缩或解压缩多少MB数据。下面这张表是Facebook官方提供的一份压缩算法benchmark比较结果:
在实际使用中,GZIP、Snappy、LZ4甚至zstd的表现各有千秋。对于kafka而言,他们的性能测试结果却出奇的一致,即吞吐量方面:LZ4>Snappy>zstd和GZIP,而在压缩比方面:zstd>LZ4>GZIP>Snappy。具体到物理资源,Snappy占用网络带宽最多,ztsd最少,毕竟zstd能提供超高压缩比;在CPU方面,各个算法表现差不多,只是在压缩时,Snappy占用CPU较多,而在解压缩时GZIP算法占用CPU较多。
- 最佳实践
首先说压缩,何时启用?producer端权游压缩条件,就是运行机器上的CPU资源要很充足,如果机器本身CPU资源消耗殆尽,那么启用消息压缩无疑雪上加霜。如果CPU资源充足的情况下,环境中带宽资源有限,也建议开启压缩。如果客户端机器CPU资源很富余,强烈建议开启zstd压缩,会极大节省网络资源消耗。
其次说说解压缩。有压缩就有解压缩,对不可抗拒的解压缩无能为力,但是能规避掉意料之外的解压缩,比如因为要兼容老版本而引入的解压缩就属于这类。有条件的还是尽量保证不要出现消息格式转换。
标注:这个系列文章是本人在极客时间专栏---kafka核心技术与实战中的学习笔记
https://time.geekbang.org/column/article/101171