Kafka的可靠性
- 各种各样的可靠性及其在Kafka场景中的含义;
- Kafka的复制功能,以及它是如何提高系统可靠性的;
- 如何配置Kafka的broker和主题来满足不同的使用场景需求,以及生产者和消费者如何在各种可靠性场景里使用它们;
- 如何验证系统的可靠性。
可靠性保证
- Kafka可以保证分区消息的顺序;
- 只有当消息被写入分区的所有同步副本时(但不一定要写入磁盘),它才被认为是"已提交"的;
- 只要还有一个副本是活跃的,则已经提交的消息就不会丢失;
- 消费者只能读取已经提交的消息。
复制
分区首领是同步副本,而对于跟随者副本来说,它需要同时满足以下条件才能被认为是同步的:
与Zookeeper之间有一个活跃的会话,即它在过去的6s(可配置)内向Zookeeper发送过心跳;
在过去10s内(可配置)从首领那里获取过消息;
在过去10s内从首领那里获取过最新的消息。光从首领那里获取消息是不够的,它还必须是几乎零延迟的。
非同步副本
若一个或多个副本在同步和非同步状态之间快速切换,说明集群内部出现了问题,通常是Java不恰当的垃圾回收配置导致的。不恰当的垃圾回收配置会造成几秒的停顿,从而让broker与Zookeeper之间断开连接,最后编程不同步的,进而发生状态切换。
broker配置
broker有3个配置参数会影响Kafka消息存储的可靠性。
复制系数
topic级别的配置参数是replication.factor,而在broker级别则可以通过default.replication.factor来配置自动创建的主题。
不完全的首领选举
unclean.leader.election只能在broker级别(实际上是在集群范围内)进行配置,它的默认值是true。
如果把unclean.leader.election.enable设为true,就是允许不同步的副本成为首领(也就是"不完全的选举"),则我们将面临丢失消息的风险。若把这个参数设为false,就要等待原先的首领重新上线,从而降低了可用性。
对于银行系统,大部分系统宁愿选择在几分钟甚至几小时内不处理信用卡支付事务,也不会冒险处理错误的消息,因为它们对数据一致性要求较高;
对于实时点击流分析系统,一般会启用不完全的首领选举,因为它们对可用性要求较高。
最少同步副本
在topic级别和broker级别上,这个参数都叫min.insync.replicas
如果可用的同步副本数少于上述配置的值,则broker就会停止接受生产者的请求。尝试发送数据的生产者会收到NotEnoughReplicasException异常。消费者仍然可以继续读取已有的数据。
在可靠的系统里使用生产者
每个使用Kafka的开发人员都要注意两件事情:
- 根据可靠性需求配置恰当的acks值;
- 在参数配置和代码里正确处理错误;
发送确认
之前生产者介绍中有提到过的acks配置可以选择3中不同的确认模式:
acks=0 意味着只要生产者能够通过网络把消息发送出去,则认为消息已成功写入Kafka;
acks=1 意味着首领在收到消息并把它写入到分区数据文件(不一定同步到磁盘上)时会返回确认或错误响应。在这个模式下,若发生正常的首领选举,生产者会在选举时收到一个LeaderNotAvailableException异常;
acks=all 意味着首领在返回确认或错误响应之前,会等待所有同步副本都收到消息。这是最保险的做法,但这样通常会降低吞吐量;
配置生产者的重试参数
若broker返回的错误可以通过重试来解决,则生产者会自动处理这些错误。生产者向broker发送消息时,broker可以返回一个成功响应码或者一个错误响应码。错误响应码可以分为两种,一种是在重试之后可以解决的,还有一种是无法通过重试解决的。即一个可重试错误一个不可重试错误
额外的错误处理
…
在可靠的系统里使用消费者
消费者的可靠性配置
group.id: 如果你希望消费者可以看到主题的所有消息,则需要为它们设置唯一的group.id,一个消费者独占一个消费者组。
auto.offset.reset: earliest/latest,该参数指定了在没有偏移量可提交(比如消费者第1次启动时)或请求的偏移量在broker上不存在时,消费者是从分区开始位置读取数据(大量重复读)还是从分区末尾开始读取数据(错过一些消息).
enable.auto.commit: …自动提交偏移量
auto.commit.interval.ms: 自动提交偏移量的频率。
显示提交偏移量
- 总是在处理完事件后再提交偏移量;
- 提交频度是性能和重复消息数量之间的均衡;
- 确保对提交的偏移量心里有数;
- 再均衡;
- 消费者可能需要重试;
- 消费者可能需要维护状态; -> KafkaStreams类库,高级DSL API
- 长时间处理;
- 仅一次传递:实现仅一次处理最简单且最常用的办法是把结果写到一个支持唯一键的系统里,比如键值存储引擎、关系型数据库等。这种情况下,要么消息本身包含一个唯一键,要么使用主题、分区和偏移量的组合来创建唯一键。
验证系统可靠性
配置验证
Kafka提供了两个重要的工具用于验证配置: org.apache.kafka.tools包里的Verifiable Producer和VerifiableConsumer这两个类。
VerifiableProducer生成一系列消息,这些消息包含从1到你指定的某个数字,可以使用与生产者相同的方式来配置VerifiableProducer,且VerifiableProducer会把每个消息是否成功发送到broker的结果打印出来。VerifiableConsumer执行的是另一个检查——它读取事件并按顺序打印出这些事件和已提交的偏移量、再均衡的相关信息。
可以考虑运行以下一些测试:
首领选举:若停掉首领会发生什么事情?生产者和消费者重新恢复正常状态需要多长时间?
控制器选举:重启控制器后系统需要多少时间来恢复状态?
依次重启:可以依次重启broker而不丢弃任何数据吗?
不完全首领选举测试:若依次停止所有副本(确保每个副本都变为不同步的),然后启动一个不同步的broker会发生什么?要怎样恢复正常?这样做是可接受的吗?
应用程序验证
应用程序验证建议如下:
- 客户端从服务器断开连接(系统管理员可以帮忙模拟网络故障);
- 首领选举;
- 依次重启broker;
- 依次重启消费者;
- 依次重启生产者;
在生产环境监控可靠性
附录
- 参考文章
- 《Kafka权威指南》