文章首发于公众号【大数据学徒】,感兴趣请搜索 dashujuxuetu 或者文末扫码关注。
在实际的应用中,我们对 Kafka 的可靠性需求各不相同,怎么才能确保 Kafka 可以达到我们想要的可靠性呢?在本文中我们来学习了解相关的内容。
内容提要:
- 可靠性概述
- broker 的配置
- producer 的配置&注意点
- consumer 的配置&注意点
- 待续
1. 可靠性概述
可靠性是一个数据存储系统的重要指标,Kafka 在设计之初就已经将这个问题考虑在内,因此Kafka 可以提供不同级别的可靠性,但是可靠性要求越高,Kafka 管理员、Kafka 用户和 与 Kafka 连接的外部系统需要配置和调整的东西也更多,同时可靠性也需要和可用性、吞吐量、延时和硬件资源做权衡,灵活是需要付出代价的。
Kafka 提供以下可靠性保证:
- 在单个分区内,保证消息不乱序,先生产的消息的 offset 保证小于后生产的消息的 offset。
- 生产的消息写入所有 ISR 中的分区副本才被看做“已提交”,但生产者自身可以通过设置
acks来选择如何确认消息是否生产成功。 - 只要至少有一个副本存活,已提交的消息就不会丢失。
- 消费者只能读取到已提交的消息。
2. broker 的配置
broker 有三个重要的与可靠性有关的配置项,在最新的版本中(2.3.0)这三个配置项也可以在 topic 级别配置,topic 的配置覆盖 broker 的配置,低版本的需要确认 topic 级别是否存在该配置项,这三个配置分别是:
| broker 配置 | topic 配置 | 含义 |
|---|---|---|
| default.replication.factor | replication.factor | 每个分区的副本个数 |
| unclean.leader.election.enable | unclean.leader.election.enable | 是否允许非 ISR 中的副本成为 leader |
| min.insync.replicas | min.insync.replicas | ISR 中最小副本数 |
分别讨论这三个配置:
- 分区副本个数越大,可靠性越高。只要有一个副本所在的 broker 还存活,这个副本就可用,代价是消耗更多的磁盘空间,一般来说设置成 3 比较合适,也可以更大。此外,配置 broker 的
broker.rack参数可以提供更高的可靠性。 - ISR 包含了 leader 以及能够及时从 leader 同步消息的 follower,如果 leader 挂了,ISR 中的一个 follower 会成为新的 leader,这称为 leader 选举,“unclean leader election”指的是 ISR 中只有 leader,如果 leader 挂了,是否允许 ISR 以外的 broker 成为 leader。如果允许,因为新 leader 原来不在 ISR 中,它所拥有的消息是不全的,通过旧 leader 和新 leader 消费的两个消费者消费到的数据不一致;如果不允许,这时候这个分区将无法选举出 leader,用户无法生产和消费这个分区,分区不可用。所以这是一个抉择的问题,如果数据一致性重要(比如银行系统),那么就不允许,否则就允许。
- 为了缓解 ISR 中只有 leader 这个问题,可以将 ISR 的最小副本数设置成大于 1 的值,这样只有消息写入两个副本以上才算提交成功。比如一个分区有三个副本,
min.insync.replicas设置成 2,当生产数据时,ISR 中至少有两个 broker 会拥有已提交的数据,如果一个 follower 挂了且另外一个 follower 在 ISR 中,这个分区的生产和消费都正常,但如果两个 broker 挂了(不管是 leader 还是 follower),因为只剩下一个副本,如果它是 leader 或可以成为 leader,这个分区将只允许消费,不允许生产,只有 ISR 中的副本数变成 2 才可以恢复生产。
3. producer 的配置&注意点
为了实现高可靠性,producer 有两点要注意:
acks参数的设置:设置为 0,1,all 的可靠性依次递增,0 表示消息发送出去就认为成功,1 表示 leader 写入成功并返回确认消息即可,all 表示所有 ISR 中的 broker都写入这条消息 leader 才可以返回确认消息。- 错误的处理和重试:producer 有两类错误,一类是可重试的错误,比如
LEADER_NOT_AVAILABLE,遇到这一类错误时,producer 的 API 会自动重试;一类是不可重试的错误,比如INVALID_CONFIG,这必须由用户来修复,producer 有一个参数控制着重试次数,叫做retires,默认值为2147483647,如果对于可靠性要求不高,可以将这个值设的小一点,注意:重试有可能造成同一条消息被生产两次或多次,比如由于网络问题导致生产者没有收到 ack,但其实消息已经写入成功,因此,在这种情况下,Kafka 只能保证每条消息不丢失,但不能不重复,即所谓的at elast once。更强的可靠性需要利用幂等和事务机制,后续的文章会着重介绍。对于不可重试的错误,比如消息大小不合法、权限错误、序列化错误、内存耗尽或者重试次数用完,开发者也必须小心处理,是直接扔掉,还是打个日志,还是进行别的操作,需要仔细考量。
4. consumer 的配置&注意点
消费者消费数据的可靠性的关键在于管理自己的 offset,在之前这篇 TODO 文章中,我们介绍了消费者应当怎么提交 offset,所有这里会相对简略一点,和自动提交 offset 有关的配置有:
group.idauto.offset.resetenable.auto.commitauto.commit.interval.ms
如果是手动提交的话有以下几点:
- 提交 offset 前确保数据都已经处理过,即在每个
poll循环的最后提交 offset。 - 提交频率取决于性能和当故障发生时重复的消息数的权衡,越频繁,重复的越少,反之,重复的越多。
- 正确处理 rebalance,丢失分区前提交 offset,获得新分区前清理状态。
- 消费者如果维护状态的话,可以选择从特定的 offset 开始消费,另外 Kafka Stream 也是一个选择。
- 消费者的处理逻辑耗时如果很长的话,需要调整心跳时间,避免 rebalance。
- Exactly-once 的需求,通常有两个解决办法,第一种是将消费处理完的数据写入一个 key-value 的系统,通过生成唯一的 key 来去重,比如 Elasticsearch、Hbase;第二种是写入支持事务的系统,比如 MySQL,在同一个事务中将消息和它们的 offset 写入,如果发生故障重启,从外部系统中读取 offset,然后继续消费。
5. 待续
这一部分应当是关于如何验证系统的可靠性,内容有点多,单独成文,敬请期待。
欢迎交流讨论,吐槽建议,分享收藏。
勤学似春起之苗,不见其增,日有所长 辍学如磨刀之石,不见其损,日有所亏 关注【大数据学徒】,用技术干货助你日有所长