分区
Kafka 的消息组织方 式实际上是三级结构:主题 - 分区 - 消息
问题一:为什么 Kafka 要做这样的设计?为什么使用分区的概念而不是直接使用多个主题呢?
- 分区的目的是:提供负载均衡,实现系统的高伸缩性【Scalability】
- 每条消息 只会 保存在某一个分区中。
- 不同的分区可以放在不同机器上;
- 数据的读写都是基于 分区 这个粒度;
生产者 分区策略
分区策略是决 定生产者将消息发送到哪个分区的算法
轮询策略
Round-robin 策略,即顺序分配,kafka默认分区策略。
随机策略
Randomness 策略, 随机的将消息放置到任意一个分区上。
按消息键保序策略
根据业务指定合适的key进行分区。
生产者 压缩
Producer 发送压缩消 息到 Broker 后,Broker 照单全收并原样保存起来。当 Consumer 程序请求这部分消息 时,Broker 依然原样发送出去,当消息到达 Consumer 端后,由 Consumer 自行解压缩 还原成之前的消息。
Producer 端压缩、Broker 端保持、Consumer 端解压缩。
问题一:Producer、Broker压缩算法不一致
- Producer压缩一遍
- Broker解压,再压缩一遍。
但如果配置一致,则broker保持就好了。
问题二:版本不同,Broker端发生消息格式转化
消息格式转换主要是为了兼容老版本的消费者程序
- Broker解压,再压缩一遍, 从而支持老版本
- 丧失Zero Copy的特性,
当数据在磁盘和网 络进行传输时避免昂贵的内核态数据拷贝,从而实现快速的数据传输
压缩算法
压缩算法的指标
- 压缩比,原先占 100 份空 间的东西经压缩之后变成了占 20 份空间,那么压缩比就是 5,显然压缩比越高越好
- 压缩 / 解压缩吞吐量,比如每秒能压缩或解压缩多少 MB 的数据。同样地,吞 吐量也是越高越好。
在 Kafka 2.1.0 版本之前,Kafka 支持 3 种压缩算法:GZIP、Snappy 和 LZ4。从 2.1.0 开 始,Kafka 正式支持 Zstandard 算法(简写为 zstd)。它是 Facebook 开源的一个压缩算 法,能够提供超高的压缩比(compression ratio)。
最佳实践
CPU允许的情况下,开启压缩zstd,进而也可以节省带宽。
避免消息丢失
如何配置 Kafka 无消息丢失?
对一个问题的回答,先要确认问题是什么,概念的边界
Kafka 的世界里什么 才算是消息丢失,或者说 Kafka 在什么情况下能保证消息不丢失。这点非常关键,因为很多时候我们容易混淆责任的边界,如果搞不清楚事情由谁负责,自然也就不知道由谁来出解决方案了。
Kafka 只对“已提交”的消息(committed message)做有限度的持久化 保证。
- 已提交:只有broker确认收到才算是已提交;
- 有限度:凡事有例外,如果broker全部出现问题等。
生产者
问题: 生产者发送了消息,但是Kafka没有收到
回答问题可以: 概念+原因,概念是为了做铺垫,让原因更直白
- Kafka Producer 是异步发送消息的,也就是说如果你调用的是 producer.send(msg) 这个 API,那么它通常会立即返回,但此时你不能认为消息发送已成功完成。。 “fire and forget”,翻译一下就是“发射后不管“;
- 造成丢失的原因不限于:网络抖动、格式不符合broker<消息过大>等;
- 采用 回调+重试的方式,producer.send(msg, callback)
消费者
问题:消费者程序丢失数据
- 问题定位:消费者要消费的数据不见了。
- 涉及的概念:Consumer 程序有 个“位移”的概念,表示的是这个 Consumer 当前消费到的 Topic 分区的位置。
位移可以类比读书的书签,正常来说,你这次读到100页,下次继续读完全没有问题,问题是:你本计划读到100页,就把书签放到100的位置,实际上读到90页就跑出去完了,下次直接从100页开始,其中就少读了10页。
解决的方法类似与生产者,维持先消费消息(阅读),再更新位移(书签)的顺序
最佳实践
Producer参数
- 使用 producer.send(msg, callback)。
- 设置 acks = all。表明所有副本 Broker 都要接收到消息,该消息才算是“已提交”。 这是最高等级的“已提交”定义。可能对某些业务有点浪费
- retries 为一个较大的值。重试次数;
Broker 端的参数
- unclean.leader.election.enable = false: 控制的是哪 些 Broker 有资格竞选分区的 Leader。如果一个 Broker 落后原先的 Leader 太多,那么 它一旦成为新的 Leader,必然会造成消息的丢失。故一般都要将该参数设置成 false, 即不允许这种情况的发生。
- replication.factor >= 3: 最好将 消息多保存几份,毕竟目前防止消息丢失的主要机制就是冗余。
- min.insync.replicas > 1: 控制的是消息至少要被写入到多少个副本才算是“已提交”。设置成大于 1 可以提升消息持久性。在实际环境中千万不要使用默认值 1。
确保 replication.factor > min.insync.replicas;
推荐设置成 replication.factor = min.insync.replicas + 1。
如果两者相等,那么只要有一个副本挂 机,整个分区就无法正常工作了。我们不仅要改善消息的持久性,防止数据丢失,还要 在不降低可用性的基础上完成
参考
极客时间—Kafka核心技术与实战
胡夕 - 博客园 –《Apache Kafka实战》
注意:本文归作者所有,未经作者允许,不得转载