如果某个broker挂了,leader副本在该broker上的分区就要重新进行leader选举。来简要描述下leader选举的过程

  • 1.4.1 KafkaController会监听ZooKeeper的/brokers/ids节点路径,一旦发现有broker挂了,执行下面的逻辑。这里暂时先不考虑KafkaController所在broker挂了的情况,KafkaController挂了,各个broker会重新leader选举出新的KafkaController
  • 1.4.2 leader副本在该broker上的分区就要重新进行leader选举,目前的选举策略是

    • 1.4.2.1 优先从isr列表中选出第一个作为leader副本
    • 1.4.2.2 如果isr列表为空,则查看该topic的unclean.leader.election.enable配置。

      unclean.leader.election.enable:为true则代表允许选用非isr列表的副本作为leader,那么此时就意味着数据可能丢失,为false的话,则表示不允许,直接抛出NoReplicaOnlineException异常,造成leader副本选举失败。
    • 1.4.2.3 如果上述配置为true,则从其他副本中选出一个作为leader副本,并且isr列表只包含该leader副本。

    一旦选举成功,则将选举后的leader和isr和其他副本信息写入到该分区的对应的zk路径上。

  • 1.4.3 KafkaController向上述相关的broker上发送LeaderAndIsr请求,将新分配的leader、isr、全部副本等信息传给他们。同时将向所有的broker发送UpdateMetadata请求,更新每个broker的缓存的metadata数据。
  • 1.4.4 如果是leader副本,更新该分区的leader、isr、所有副本等信息。如果自己之前就是leader,则现在什么操作都不用做。如果之前不是leader,则需将自己保存的所有follower副本的logEndOffsetMetadata设置为UnknownOffsetMetadata,之后等待follower的fetch,就会进行更新
  • 1.4.5 如果是follower副本,更新该分区的leader、isr、所有副本等信息

    然后将日志截断到自己保存的highWatermarkMetadata位置,即日志的logEndOffsetMetadata等于了highWatermarkMetadata

    最后创建新的fetch请求线程,向新leader不断发送fetch请求,初次fetch的offset是logEndOffsetMetadata。

上述重点就是leader副本的日志不做处理,而follower的日志则需要截断到highWatermarkMetadata位置。

至此,算是简单描述了分区的基本情况,下面就针对上述过程来讨论下kafka分区的高可用和一致性问题。

2 消息丢失

2.1 消息丢失的场景

哪些场景下会丢失消息?

  • acks= 0、1,很明显都存在消息丢失的可能。
  • 即使设置acks=-1,当isr列表为空,如果unclean.leader.election.enable为true,则会选择其他存活的副本作为新的leader,也会存在消息丢失的问题。
  • 即使设置acks=-1,当isr列表为空,如果unclean.leader.election.enable为false,则不会选择其他存活的副本作为新的leader,即牺牲了可用性来防止上述消息丢失问题。
  • 即使设置acks=-1,并且选出isr中的副本作为leader的时候,仍然是会存在丢数据的情况的:

    s1 s2 s3是isr列表,还有其他副本为非isr列表,s1是leader,一旦某个日志写入到s1 s2 s3,则s1将highWatermarkMetadata提高,并回复了客户端ok,但是s2 s3的highWatermarkMetadata可能还没被更新,此时s1挂了,s2当选leader了,s2的日志不变,但是s3就要截断日志了,这时已经回复客户端的日志是没有丢的,因为s2已经复制了。

    但是如果此时s2一旦挂了,s3当选,则s3上就不存在上述日志了(前面s2当选leader的时候s3已经将日志截断了),这时候就造成日志丢失了。

2.2 不丢消息的探讨

其实我们是希望上述最后一个场景能够做到不丢消息的,但是目前的做法还是可能会丢消息的。

丢消息最主要的原因是:

由于follower的highWatermarkMetadata相对于leader的highWatermarkMetadata是延迟更新的,当leader选举完成后,所有follower副本的截断到自己的highWatermarkMetadata位置,则可能截断了已被老leader提交了的日志,这样的话,这部分日志仅仅存在新的leader副本中,在其他副本中消失了,一旦leader副本挂了,这部分日志就彻底丢失了

这个截断到highWatermarkMetadata的操作的确太狠了,但是它的用途有一个就是:避免了日志的不一致的问题。通过每次leader选举之后的日志截断,来达到和leader之间日志的一致性,避免出现日志错乱的情况。

ZooKeeper和Raft的实现也有类似的日志复制的问题,那ZooKeeper和Raft的实现有没有这种问题呢?他们是如何解决的呢?

Raft并不进行日志的截断操作,而是会通过每次日志复制时的一致性检查来进行日志的纠正,达到和leader来保持一致的目的。不截断日志,那么对于已经提交的日志,则必然存在过半的机器上从而能够保证日志基本是不会丢失的。

ZooKeeper只有当某个follower的记录超出leader的部分才会截断,其他的不会截断的。选举出来的leader是经过过半pk的,必然是包含全部已经被提交的日志的,即使该leader挂了,再次重新选举,由于不进行日志截断,仍然是可以选出其他包含全部已提交的日志的(有过半的机器都包含全部已提交的日志)。ZooKeeper对于日志的纠正则是在leader选举完成后专门开启一个纠正过程。

kafka的截断到highWatermarkMetadata的确有点太粗暴了,如果不截断日志,则需要解决日志错乱的问题,即使不能够像ZooKeeper那样花大代价专门开启一个纠正过程,可以像Raft那样每次在fetch的时候可以进行不断的纠正。这一块还有待继续关注。

Kafka leader副本选举与消息丢失场景讨论的更多相关文章

  1. RocketMQ 消息丢失场景分析及如何解决

    生产者产生消息发送给RocketMQ RocketMQ接收到了消息之后,必然需要存到磁盘中,否则断电或宕机之后会造成数据的丢失 消费者从RocketMQ中获取消息消费,消费成功之后,整个流程结束 1. ...

  2. 实际业务处理 Kafka 消息丢失、重复消费和顺序消费的问题

    关于 Kafka 消息丢失.重复消费和顺序消费的问题 消息丢失,消息重复消费,消息顺序消费等问题是我们使用 MQ 时不得不考虑的一个问题,下面我结合实际的业务来和你分享一下解决方案. 消息丢失问题 比 ...

  3. 解决RabbitMQ消息丢失问题和保证消息可靠性(一)

    原文链接(作者一个人):https://juejin.im/post/5d468591f265da03b810427e 工作中经常用到消息中间件来解决系统间的解耦问题或者高并发消峰问题,但是消息的可靠 ...

  4. Kafka无消息丢失配置

    Kafka到底会不会丢数据(data loss)? 通常不会,但有些情况下的确有可能会发生.下面的参数配置及Best practice列表可以较好地保证数据的持久性(当然是trade-off,牺牲了吞 ...

  5. kafka知识体系-kafka设计和原理分析-kafka leader选举

    kafka leader选举 一条消息只有被ISR中的所有follower都从leader复制过去才会被认为已提交.这样就避免了部分数据被写进了leader,还没来得及被任何follower复制就宕机 ...

  6. Kafka设计解析(十一)Kafka无消息丢失配置

    转载自 huxihx,原文链接 Kafka无消息丢失配置 目录 一.Producer端二.Consumer端 Kafka到底会不会丢数据(data loss)? 通常不会,但有些情况下的确有可能会发生 ...

  7. kafka实现无消息丢失与精确一次语义(exactly once)处理

    在很多的流处理框架的介绍中,都会说kafka是一个可靠的数据源,并且推荐使用Kafka当作数据源来进行使用.这是因为与其他消息引擎系统相比,kafka提供了可靠的数据保存及备份机制.并且通过消费者位移 ...

  8. RabbitMQ,RocketMQ,Kafka 事务性,消息丢失和消息重复发送的处理策略

    消息队列常见问题处理 分布式事务 什么是分布式事务 常见的分布式事务解决方案 基于 MQ 实现的分布式事务 本地消息表-最终一致性 MQ事务-最终一致性 RocketMQ中如何处理事务 Kafka中如 ...

  9. Kafka在高并发的情况下,如何避免消息丢失和消息重复?kafka消费怎么保证数据消费一次?数据的一致性和统一性?数据的完整性?

    1.kafka在高并发的情况下,如何避免消息丢失和消息重复? 消息丢失解决方案: 首先对kafka进行限速, 其次启用重试机制,重试间隔时间设置长一些,最后Kafka设置acks=all,即需要相应的 ...

随机推荐

  1. Mongo 用户管理

    开启用户管理 auth = true 在配置文件或者参数中设置为改选项 开启认证服务,注意一点,很多人说在没有设置用户和配置用户之前,应该先不要开启,等设置完用户后再开启该参数,目前在win2008 ...

  2. 【API知识】一种你可能没见过的Controller形式

    前言 这里分享一下我遇到的一个挺有意思的Controller形式,内容涉及@RequestMapping注解的原理. 实际案例 一.基本描述 项目甲中有多个模块,其中就有模块A和B.(这里的模块指的是 ...

  3. .NET Core GC 的设计

    此文章转载自:http://www.cnblogs.com/zkweb/p/6288457.html 作者: Maoni Stephens ( @maoni0) - 2015 提示: 推荐看 The ...

  4. 痞子衡嵌入式:ARM Cortex-M内核那些事(4)- 性能指标

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是ARM Cortex-M性能指标. 1.处理器的性能指标 用于评价CPU的性能指标非常多,不同的性能侧重点下的测试标准可能得出的指标值不 ...

  5. 【Angular专题】——(1)Angular,孤傲的变革者

    目录 一. 漫谈Angular 二. 如果你还在使用Angularjs 三. 我计划这样学习Angular技术栈 一. 漫谈Angular Angular,来自Google的前端SPA框架,与Reac ...

  6. 【转载】C#处理空格和换行

    使用C#处理字符串是一个常见的情况,当字符串中含有空格或者换行符号的时候,如果业务需要,我们可以通过相应的方法将之处理掉,处理成不含空格和换行符号的字符串,处理的过程使用到正则表达式. 具体函数处理的 ...

  7. [C#] 使用 StackExchange.Redis 封装属于自己的 RedisHelper

    使用 StackExchange.Redis 封装属于自己的 RedisHelper 目录 核心类 ConnectionMultiplexer 字符串(String) 哈希(Hash) 列表(List ...

  8. WebStorm 配置微信小程序开发 用html样式打开wxml 用css样式打开wxss 配置微信小程序提醒

    1.点开preferences 2.搜索找到“File Types” 3.找到"HTML",点击“+”按钮,添加“*.wxml”然后“apply” 4.和3一样,再找到 ‘casc ...

  9. JS判断类型

    JS中的typeof方法可以查看数据的类型,如下: console.log(typeof 2); // number console.log(typeof "2"); // str ...

  10. 使用addviewController()实现无业务逻辑跳转

    需要实现WebMvcConfigurer类,重写addViewControllers方法. 添加@Configuration,等价于xml配置. package dbzx.config; import ...