Kafka设计剖析

79 阅读3分钟

如何保证高可用

基于Controller的选举⽅式

如何保证消息可靠性

所谓可靠性,我们可以从三个角度取分析mq系统的可靠性:

  • 从生产者角度,需要考虑发送的消息去向问题
  • 从消息中间件角度,需要考虑的消息持久化、热备的问题
  • 从消费者角度,需要考虑重复消费等问题

生产者端

kafka支持3种方式发送消息,这也是消息队列普遍支持的方式:

  • 发送并忘记:不管结果,虽然可以开启自动重试,但是肯定会有消息丢失的可能
  • 同步发送:同步发送返回Future对象,我们可以知道发送结果,然后进行处理
  • 异步发送:发送消息,同时指定一个回调函数,根据结果进行相应的处理

一般我们都会使用异步发送带有回调的方式进行发送消息,再设置参数为发送消息失败不停地重试。
通过设置kafka写请求处理方式acks=all(0|1|all)可以使写入消息时能在kafka有多个备份。

acks=0:生产者写入消息不管服务器的响应,可能消息还在网络缓冲区,服务器根本没有收到消息
acks=1:只要Leader Replica收到消息就认为成功
acks=all:Partition的所有ISR都受到消息才认定成功(类似raft协议)

kafka端

kafka因为消息写入是通过PageCache异步写入磁盘的,因此仍然存在丢失消息的可能。
因此针对kafka自身丢失的可能设置参数:

  • replication.factor=N,设置一个比较大的值,保证至少有2个或者以上的副本。
  • min.insync.replicas=N,代表消息如何才能被认为是写入成功,设置大于1的数,保证至少写入1个或者以上的副本才算写入消息成功。
  • unclean.leader.election.enable=false,这个设置意味着没有完全同步的分区副本不能成为Leader副本,如果是true的话,那些没有完全同步Leader的副本成为Leader之后,就会有消息丢失的风险。

消费者端

消费者端需要考虑以下几个参数设置:
初始化
auto.offset.reset=earliest,这个参数代表没有偏移量可以提交或者broker上不存在偏移量的时候,消费者如何处理。earliest代表从分区的开始位置读取,可能会重复读取消息,但是不会丢失,消费方一般我们肯定要自己保证幂等,而lates表示从分区末尾读取,那就会有概率丢失消息。
自动提交
因为重平衡发生的时候,消费者会去读取上一次提交的偏移量,自动提交默认是每5秒一次,这会导致重复消费或者丢失消息。
通常建议取消自动提交,改为业务处理成功手动提交,即enable.auto.commit=false
去重
Kafka 只支持“At Most Once”和“At Least Once”,消息去重需在具体的业务中实现。

At Most Once:消息可能会丢,但绝不会重复传输
At Least Once:消息绝不会丢,但可能会重复传输
Exactly once:每条消息肯定会被传输一次且仅传输一次