前言
本文里面涉及到较多基础概念,如果忘记了,那么可以去看下《一文带你快速入门kafka》。
对于一个消息中间件而言,可靠性是是至关重要的要素之一。不管是面试或者实际工作中,我们都不得不面对几个问题:是几个九?消息会不会丢失?如何保证幂等?如何顺序消费?这篇文章中笔者会和大家一起去看 Kafka 是如何设计的。
针对上面的几个问题,Kafka 需要考虑包括不限于以下问题:
-
可用性
- Kafka 支持分布式架构,实现了故障转移,避免单点问题
- 如何避免脑裂问题(这个要了解 Kafka 的 leader 选举机制)
- 多副本机制,支持备份容灾
- 数据一致性如何保证
- 数据同步要如何实现
- Kafka 支持分布式架构,实现了故障转移,避免单点问题
-
消息问题
-
生产者投递消息
broker回复投递成功,但是消息丢失了。出现这种情况,一般是以下几种情况:
- acks 配置成 0,生产者以为自己投递成功了,但其实并没有成功写入 leader
- 消息持久化在 leader 分区,但是没有同步给 follower 就宕机了
这个问题也好解决:生产者可以在发送消息前,先将消息持久化。至于多是用了存储空间,现在磁盘空间可以说是最不值钱的了,而且我们还可以定期归档压缩/删除处理,问题不大。
-
消费者消费消息遇到消息丢失或者消息重复处理
-
消息丢失
消息丢失一般是以下这几种情况:
- 消费者拿到消息了,但是处理过程中发生异常
- 消费者提交消费位移的设计不合理
针对这个问题,我们通常拿到消息会选择将消息持久化在本地,然后再做消息处理,处理出问题也可以重复处理。这种设计满足我们大多数场景,但是对于消息生产速度远高于我们持久化的速度的场景可能就不适用了,因为我们要考虑消息堆积问题。不管是这个问题,还是有些场景下无法找生产者重新投递消息的问题,都让我们期待着消息中间件可以支持消息回溯功能。
-
重复消费
这个可以交由使用者自己做幂等处理
-
-
消息需要有序消费
我们知道 Kafka 是分区内消息有序的。当然,需要需要有序的消息就只能使用一个分区,无疑是以 Kafka 的水平扩展能力作为代价的。如果是需要全局有序,而我们又确定使用 Kafka,而且单分区的吞吐量不能满足要求,那么我们只能自己进行额外设计来保证了。
-
1 acks配置对消息丢失的影响
1.1 acks=1
消息成功写入 leader 后,就会告诉生产者投递成功
如上图例子,一共三个分区,其中 follower1 和 follower2 均属于 ISR。假设 leader 成功写入 3 和 4 之后,ISR 还没同步,leader 就宕机了,这样就丢失了 3 和 4,如下图
1.2 acks=-1 或者 acks=all
消息不仅要成功写入 leader,还要 ISR 中的所有 follower 同步完成后,才会告知生产者投递成功。
还是 2.1.1 的例子,这里无非会有两种情况
-
leader 在同步完成后宕机
-
leader 在同步完成前宕机
这个配置对 Kafka 的性能会有较大影响,需要自己斟酌得失。
2 unclean.leader.election.enable
这个配置是用来控制 Kafka 是否可以选举非 ISR 中的副本为 leader,0.11.0.0 之后的版本默认为 false。虽然设置为 true 可以提高 Kafka 的可用性,但是会降低 Kafka 数据的可靠性。
3 总结
上面提出的问题均有指出和 Kafka 相关部分的设计是哪些,这里再总结以下:
- 如何避免脑裂问题——了解 Kafka 的 leader 选举机制
- 数据同步&数据一致性问题——了解 Kafka 的多副本设计
- 消息顺序消费问题——了解 Kafka 的日志同步机制(分区有序)