Kafka 在数据传递可靠性方面具有很大的灵活性,是高度可配置的,通过使用客户端 API 可以满足不同程度的可靠性需求。
Kafka 有一些基本的保证:1. Kafka 可以保证分区内消息的顺序;2. 消息被写入到分区的所有同步副本才算是已经提交的消息;3. 只要有一个副本活跃,已经提交的消息就不会丢失;4. 消费者只能读取已经提交的消息。
以上的基本保证用于构建可靠的系统,开发者在配置参数上作出权衡(可靠性、一致性的重要程度与可用性、高吞吐量、低延迟和硬件成本重要程度之间的权衡),从而获得想要达到的可靠性。
配置 broker
broker 有 3 个配置会影响消息存储的可靠性,应用在 broker 级别时控制所有主题的行为,应用在主题级别时控制个别主题的行为。
复制系数
复制系数即数据数据副本的个数,复制系数 N 需要至少 N 个 broker,在 N - 1 个 broker 失效的情况下仍然可用,默认为 3。主题级别的配置是 replication.factor,而 broker 级别通过 default.replication.factor 来配合自动创建主题的复制系数。
更高的复制系数会带来更高的可用性和更少的故障,不过会占用 N 倍的磁盘空间,一般要在可用性和存储硬件之间作出权衡。
如果重启等导致主题不可用是可以接受的,那么复制系数设为 1 就可以,不过在节省硬件成本的同时也降低了可用性。复制系数为 2 可以容忍 1 个 broker 失效,不过有时候 1 个broker 失效会导致集群不稳定(通常是旧版 Kafka)。建议在要求可用性的场景把复制系数设置为 3,在大多数情况下足够安全。
同时注意副本的分布也很重要,Kafka 会保证分区的每个副本在不同的 broker 上,如果把 broker 分布在不同机架上,并使用 broker.rack 配置机架信息,可以获得更高的可用性。
不完全首领选举
当分区首领不可用时,一个同步副本会被选为新首领。但如果首领不可用时其他副本都是不同步的,就要做出一个艰难的选择。
如果将不同步副本提升为新首领,则副本不同步后写入旧首领的消息丢失,导致数据不一致,否则分区在旧首领(最后一个同步副本)恢复之前不可用。
默认情况下 unclean.leader.election.enable 的值为 true,即允许【不完全的选举】。
最少同步副本
尽管可以将复制系数设为 3,可还是会出现只有一个同步副本的情况,如果唯一的同步副本不可用,就必须在可用性和一致性间做选择。如果要确保已提交的消息被写入到不止一个副本,就需要把最小同步副本的值设置大一点。
最小同步副本在主题和 broker 级别均为 min.insync.replicas,如果设置为 2,则至少存在两个同步副本才能向分区写入数据。如果可用副本不足,生产者会受到 NotEnoughReplicasException。此配置配合生产者的 acks(需要接收到多少个同步副本的响应才算写入成功)配置能使消息的可靠性更好。
配置生产者
即使我们尽可能地把 broker 配置的很可靠,但如果没有对生产者进行可靠性方面的配置,系统仍然可能出现突发的数据丢失。
比如 broker 配置为 3 个副本,禁用不完全选举,如果生产者 acks 为 1,首领副本接到消息后崩溃,虽然有两个同步副本,但还没有来得及同步消息,其中一个副本称为新首领,从生产者的角度就丢失了一个消息。
再比如 acks 设为 all,但发送消息时首领崩溃,生产者收到【首领不可用】的错误相应,如果没有处理错误,也会丢失消息。
所以,生产者首先需要将 acks 配置为合适的值,其次需要处理 broker 返回的错误。
broker 返回的错误如果是可以通过重试解决的,生产者会自动处理错误,比如 LEADER_NOT_AVAILABLE 错误,可以通过配置 retries 来指定最大重试次数。需要注意的是,重试会带来一些风险,比如生产者因为网络问题没有收到 broker 的确认。
如果需要【只保存一次】,可以在消息中假如唯一标识符,或者使消息【幂等】,即出现了重复消息也不会有负面影响。【这个账号里有 10 美元】是幂等的,【给这个账号加 10 美元】不是幂等的。
另一种不可通过重试解决的错误,比如消息过大、重试达上限等,需要开发者根据业务逻辑处理错误。
配置消费者
只有被写入到所有同步副本的消息才会被消费者读取,消息已经具备一致性,所以消费者要做的就是记住哪些消息已经被读取过,哪些还没有读取。
从分区读取数据时,消费者会获取一批事件,检查事件中最大的偏移量,然后从最大偏移量开始读取下一批事件。而如果消费者退出,其他消费者需要知道之前的消费者读取的进度,这也就是提交偏移量的作用。
消费者需要注意以下配置:1. group.id,具有相同 group.id 的消费者会共同读取订阅的主题。2. auto.offset.reset 指定在没有记录偏移量时从何处开始读取,earliest 表示从分区开始位置读取,latest 表示从末尾开始读取。3. enable.auto.commit 配置是否开启自动提交偏移量。4. auto.commit.interval.ms 自动提交偏移量的时间间隔。
手动提交偏移量会更准确,关于手动提交偏移量需要注意以下几点:
- 要在消息事件处理完后再提交偏移量
- 在提交频率和重复消息数量之前作权衡
- 注意再均衡,在失去控制前提交偏移量
- 注意消息事件处理失败的逻辑
- 数据处理要花费很长时间时注意保持心跳
- 需要【仅一次】传递时可以借助支持唯一键、事务的系统
验证系统可靠性
在确认了可靠性需求,并且配置 broker 和客户端后,最好还是先对系统可靠性做些验证。建议在 3 个层面做验证:配置验证、应用程序验证及生产环境的应用程序监控。
配置验证
Kafka 提供了两个用于验证配置的重要工具:org.apache.kafka.tools 包内的 VerifiableProducer 和 VerifiableConsumer 两个类,可以从命令行运行两个类或嵌入自动化测试框架。
使用和生产者、消费者相同的方式来配置 VerifiableProducer 和 VerifiableComsumer,VerifiableProducer 生成一系列消息,通过 VerifiableComsumer 检查每个消息。可以在首领选举、控制器选举、依次重启、不完全首领选举测试等场景测试系统的可靠性。
应用程序验证
确保 broker 和客户端配置满足需求后,可以再从应用程序方面检查,包括错误处理、提交偏移量、再均衡监听等,建议基于如下故障条件测试应用程序:客户端从服务器断开连接、首领选举、依次重启 broker、依次重启生产者和依次重启消费者。
生产环境监控
测试无法替代生产环境的持续监控,监控的目的是确保数据按期望的方式流动,可以按照业务需求对重要的数据指标进行持续地监控。