1 kafka消息压缩
kafka关于消息压缩的定义(来源于官网):
此为 Kafka 中端到端的块压缩功能。如果启用,数据将由 producer 压缩,以压缩格式写入服务器,并由 consumer 解压缩。压缩将提高 consumer 的吞吐量,但需付出一定的解压成本。
压缩就是用时间换空间,其基本理念是基于重复,将重复的片段编码为字典,字典的 key 为重复片段,value 为更短的代码,比如序列号,然后将原始内容中的片段用代码表示,达到缩短内容的效果,压缩后的内容则由字典和代码序列两部分组成。解压时根据字典和代码序列可无损地还原为原始内容。通常来讲,重复越多,压缩效果越好。比如 JSON 是 Kafka 消息中常用的序列化格式,单条消息内可能并没有多少重复片段,但如果是批量消息,则会有大量重复的字段名,批量中消息越多,则重复越多,这也是为什么 Kafka 更偏向块压缩,而不是单条消息压缩。
2 kafka的消息压缩类型对比
目前 Kafka 共支持四种主要的压缩类型:Gzip、Snappy、Lz4 和 Zstd。关于这几种压缩的特性。
压缩类型 | 压缩率 | CPU 使用率 | 压缩速度 | 带宽使用率 |
---|---|---|---|---|
Gzip | Highest | Highest | Slowest | Lowest |
Snappy | Medium | Moderate | Moderate | Medium |
Lz4 | Low | Lowest | Fastest | Highest |
Zstd | Medium | Moderate | Moderate | Medium |
从上表可知,Snappy 在 CPU 使用率、压缩比、压缩速度和网络带宽使用率之间实现良好的平衡,我们最终也是采用的该类型进行压缩试点。这里值得一提的是,Zstd 是 Facebook 于 2016 年开源的新压缩算法,压缩率和压缩性能都不错,具有与 Snappy(Google 杰作)相似的特性,直到 Kafka 的 2.1.0 版本才引入支持。
3 何时需要压缩
压缩是需要额外的 CPU 代价的,并且会带来一定的消息分发延迟,因而在压缩前要慎重考虑是否有必要。
- 压缩带来的磁盘空间和带宽节省远大于额外的 CPU 代价,这样的压缩是值得的。
- 数据量足够大且具重复性。消息压缩是批量的,低频的数据流可能都无法填满一个批量,会影响压缩比。数据重复性越高,往往压缩效果越好,例如 JSON、XML 等结构化数据;但若数据不具重复性,例如文本都是唯一的 md5 或 UUID 之类,违背了压缩的重复性前提,压缩效果可能不会理想。
- 系统对消息分发的延迟没有严苛要求,可容忍轻微的延迟增长。
4 如何开启压缩
Kafka 通过配置属性 compression.type 控制是否压缩。该属性在 producer 端和 broker 端各自都有一份,也就是说,我们可以选择在 producer 或 broker 端开启压缩,对应的应用场景各有不同。目前没有尝试在broker段开启压缩。
4.1 在broker端开启解压缩
Broker 端的 compression.type 属性默认值为 producer,即直接继承 producer 端所发来消息的压缩方式,无论消息采用何种压缩或者不压缩,broker 都原样存储。、
4.1.1 broker 和 topic 两个级别
在 broker 端的压缩配置分为两个级别:全局的 broker 级别 和 局部的 topic 级别。顾名思义,如果配置的是 broker 级别,则对于该 Kafka 集群中所有的 topic 都是生效的。但如果 topic 级别配置了自己的压缩类型,则会覆盖 broker 全局的配置,以 topic 自己配置的为准。
broker级别:要配置 broker 级别的压缩类型,可通过 configs 命令修改 compression.type 配置项取值。此处要使修改生效,是否需要重启 broker 取决于 Kafak 的版本,在 1.1.0 之前,任何配置项的改动都需要重启 broker 才生效,而从 1.1.0 版本开始,Kafka 引入了动态 broker 参数,将配置项分为三类:read-only、per-broker 和 cluster-wide,第一类跟原来一样需重启才生效,而后面两类都是动态生效的,只是影响范围不同,关于 Kafka 动态参数,以后单开博文介绍。从 官网 可以看到,compression.type 是属于 cluster-wide 的,如果是 1.1.0 及之后的版本,则无需重启 broker。
topic级别:topic 的配置分为两部分,一部分是 topic 特有的,如 partitions 等,另一部分则是默认采用 broker 配置,但也可以覆盖。如果要定义 topic 级别的压缩,可以在 topic 创建时通过 --config 选项覆盖配置项 compression.type 的取值,命令如下:
sh bin/kafka-topics.sh \ --create \ --topic my-topic \ --replication-factor 1 \ --partitions 1 \ --config compression.type=snappy
也可以通过 configs 命令修改 topic 的 compression.type 取值,命令如下:
bin/kafka-configs.sh \ --entity-type topics \ --entity-name my-topic \ --alter \ --add-config compression.type=snappy
4.2 在 Producer 端压缩
跟 broker 端一样,producer 端的压缩配置属性依然是 compression.type,只不过默认值和可选值有所不同。默认值为 none,表示不压缩。直接在代码层面更改 producer 的 config。但需要注意的是,改完 config 之后,需要重启 producer 端的应用程序,压缩才会生效。
代码示例如下:
public class KafkaProducerTest { public static void main(String[] args) { String brokerList = "127.0.0.1:9092"; Properties properties = new Properties(); properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, brokerList); properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); properties.put(ProducerConfig.MAX_REQUEST_SIZE_CONFIG,"2097245"); properties.put(ProducerConfig.COMPRESSION_TYPE_CONFIG,"gzip"); KafkaProducer
producer = new KafkaProducer<>(properties); String topic = "mytestTopic1"; int sizeInMb = 2; // 设置字符串大小为2MB int sizeInBytes = sizeInMb * 1024 * 1024; // 转换为字节数 StringBuilder largeString = new StringBuilder(sizeInBytes); largeString.append(":"); for (int i = 0; i < sizeInBytes; i++) { largeString.append("A"); // 使用大写字母"A"来构建字符串 } String msg = largeString.toString(); try { for (int i = 0; i < 100; i++) { String msg1 = i+msg; producer.send(new ProducerRecord<>(topic, msg1)); Thread.sleep(500); } }catch (Exception e){ e.printStackTrace(); } } } 上面示例特意制造了一个大字符串作为消息,测试压缩,需要注意的是,配置压缩的时候同时也需要配置消息的最大值。即:max.request.size。
5 解压缩
可能发生解压的地方依然是两处:consumer 端和 broker 端。
consumer端:consumer 端发生解压的唯一条件就是从 broker 端拉取到的消息是带压缩的。此时,consumer 会根据 recordBatch 中 compressionType 来对消息进行解压。
broker端:broker 端是否发生解压取决于 producer 发过来的批量消息 recordBatch 是否是压缩的:如果 producer 开启了压缩,则会发生解压,否则不会。原因简单说下,在 broker 端持久化消息前,会对消息做各种验证,此时必然会迭代 recordBatch,而在迭代的过程中,会直接采用 recordBatch 上的 compressionType 对消息字节流进行处理,是否解压取决于 compressionType 是否是压缩类型。关于这点,可以在 LogValidator 的 validateMessagesAndAssignOffsets 方法实现中可以看到,在 convertAndAssignOffsetsNonCompressed、assignOffsetsNonCompressed 和 validateMessagesAndAssignOffsetsCompressed 三个不同的分支中,都会看到 records.batches.forEach {...} 的身影,而在后面的源码分析中会发现,在 recordBatch 的迭代器逻辑中,直接采用的 compressionType 的解压逻辑对消息字节流读取的。也就是说,如果 recordBatch 是压缩的 ,只要对其进行了迭代访问,则会自动触发解压逻辑。
通俗一点讲:producer端配置了压缩,consumer自动解压缩。
猜你喜欢
- 18小时前欧多桑(欧多桑火锅)
- 16小时前即日是什么意思(即日是词语吗)
- 16小时前柏多音字组词(柏多音字组词是什么)
- 14小时前出世与入世(中国古代文人的出世与入世)
- 13小时前查征信去哪个银行(查征信去哪个银行位置)
- 6小时前上是翘舌音节吗(翘舌音上颚)
- 5小时前北海景点介绍(北海景点介绍北海旅游景点)
- 3小时前女t是什么意思(女生t p分别代表什么)
- 2小时前会议纪要格式(会议纪要模板 word模板)
- 1小时前包含87兔男88龙女断头婚的词条
网友评论
- 搜索
- 最新文章
- 热门文章