Kafka可靠性保证

kafka默认的保证

  • kafka的同一个生产者写入同一个分区的消息,B在A之后写入,Kafka可以确保B的偏移量B比A大,且消费者会先消费A后消费B
  • 消息被所有副本(L和ISR)接受(不一定是写入磁盘)才被认为是已经被提交。
    note:生产者可以选择不同类型的消息确认:
    完全提交确认
    写入首领确认
    发送到网络确认
  • 只要有一个副本活跃,提交的消息就不会丢失
  • 消费者只能读取已经提交的消息。

复制机制增加的保证

复制机制和分区的多副本架构是Kafka可靠性保证的核心。

把消息写入多个副本,保证单个broker崩溃,还能购保持消息的持久性。

首领副本是同步副本,其他副本被认为是ISR的基本条件:

  • 同Zookeeper有活跃session-6s正常发送一次心跳
  • 10s内从L处同步过最新消息
  • 10s内获取的是L的最新消息。

非ISR的副本可以在跟上同步副本的时候重新变成同步副本。

note:平凡的出现非同步副本到同步副本的切换,可能是Java的垃圾回收导致,长时间的STW。

滞后的ISR(同步慢)会影响P和C的性能:可能影响P,一定影响C,C消费的消息必须是确认后的消息。

滞后的非ISR,不会影响性能,但是会导致系统低可用,备份的机器减少。

broker配置增加的保证

## odd number is the best
## least brokers is the defined number
defalut.replication.factor:副本数目
default:3
scope:topic
## odd number is the best
replication.factor:副本数目
default:3
scope:broker
## broker最好网络隔离,电源隔离,机架隔离
broker.rack:机架的名字
unclean.leader.election:不完全选举
default:true

desc:L挂掉,非ISR可以成为首领。

不完全选举的例子

场景1:

L和两个非ISR的F

  • 首先F1和F2死掉,只有L可用
  • M发往L,L接受成功并且确认
  • L死掉,F1和F2重启,F1当选首领
  • 此时丢失M。
    例子:L(两个跟随F1,F2,两个副本已经变成不同步副本了只有数据1100)写入100200,C集群已经消费了100150;L宕机,F1重启,F1变成L,此时F1新接受数据从100200(和前面的数据不同),此时C集群将会十分混乱,消费旧的(100-150)消费新的(100-200),这个时L又复活了,变成了F,他会把旧的100-200的消息全部删掉,旧的150-200就被丢掉了。

场景2:

L和两个非ISR的F

网络抖动,复制延迟,这个时候L死掉,丢失部分消息。

简单的多,允许不完全选举,就可能丢失消息;如果不允许不完全选举,降低可用性。

##最少同步副本(lsr)
min.insync.replicas:配置最少同步副本的数量

desc:
如果小于这个值,生产者会收到NotEnoughreplicasException异常,消费者还是可用从broker获取数据的。

生产者对可靠性的保证

生产者丢失消息的场景:

场景1:

  • 集群有三个broker,acks=1
  • L收到M,P认为MX成功;
  • 消息没有同步ISR,L挂掉;
  • 选举L,丢失M。

场景2:

  • replica有三个,acks=all;
  • L挂掉,P使用异步发送机制且没有注册监听器,重试消息丢失。

生产端开发者的注意点:

  • 根据可靠性要求配置acks的值
  • 在参数配置和代码里面正确处理错误。

生产者的主要配置参数

acks
重试

重试可能产生重复数据,Kafka没法保证消息只被添加一次。

我们认为失败,实际接收成功了。这样的话可能需要消费者自行处理。

额外需要处理的错误

具体包括

  • 不可重试的broker错误,如果消息太大,认证错误等。
  • 组装消息的时候发生的错误,如果序列化错误。
  • 生产者重试达到上限,消息占用的内存太多等。

建议处理方案:

  • 丢弃
  • 记录错误
  • 保存消息到本地硬盘
  • 回调处理

消费者对可靠性的保证

  • 消费者得到的M,一定具备一致性。
  • 消费者总是按顺序获取数据。

消费者丢失消息,重复消费消息的主要原因

  • 先提交,后消费,崩溃-----丢失消息
  • 先消费,崩溃,再次消费------重复消费

消费者可靠性的配置

group.id
auto..offset.reset
enable.auto.commit
auto.commit.interval.ms

显示提交的注意点:

  • 总是在处理完事件后在提交偏移量轮询内,
  • 如果不需要在轮询之间维护状态,那么可以使用自动提交,或者轮询结束时手动提交
  • 提交频度和重复消息之间寻找平衡点
  • 提交偏移量的位置一定要注意
  • 比如在事物结束后在提交偏移量。
  • 再次均衡
  • 分区主动退出前要提交偏移,并在分配新区的时候清理之前broker上记录的缓存信息。
  • 消费者失败
  • 重试:
  • 提交最后成功的偏移量,
  • 调用pause()方法不再继续处理消息,
  • 然后轮询尝试重新处理,
  • 如果轮询处理成功,或者达到最大次数,记录错误、丢弃消息,
  • 调用resume()继续消费流程。
  • 之后处理:遇到失败的消息,把该消息提交独立的topic,交给独立的CG进行处理。
  • 消费者需要维护状态
  • 例如:消费者需要计算所有消息的平均值,一批消息之前是有关系的
  • 提交偏移前计算平均值,提交一个单独的topic进行维护,
  • 然后重启就可以从上次的位置进行处理了。
  • 但是这样也有问题,可能提交了平均值,但是没有提交偏移连,计算就会错误。
  • Kafka没有提供事物机制,可以尝试使用kafkaStream类库解决问题。
  • 长时间处理
  • 有些数据处理时间长,但是轮询不能长时间暂停(否则没有心跳了)这种情况一种常见的方法是使用线程池处理数据,调用pause()方法保持轮询,单不获取数据,直到工作线程完成。
  • 仅仅一次传递
  • 将M映射到唯一的key,保存在数据库里面,消费的时候从数据库获取信息进行校验,即幂等性写入,这个是常见的模式。

验证系统可靠性

  • 配置验证
  • 程序验证
  • 监控插件监控

配置验证