一文了解清楚kafka消息丢失问题和解决方案
前言
今天分享一下kafka的消息丢失问题,kafka的消息丢失是一个很值得关注的问题,根据消息的重要性,消息丢失的严重性也会进行放大,如何从最大程度上保证消息不丢失,要从生产者,消费者,broker几个端来说。
消息发送和接收流程
kafka生产者生产好消息后,会将消息发送到broker节点,broker对数据进行存储,kafka的消息是顺序存储在磁盘上,以主题(topic),分区(partition)的逻辑进行划分,消息最终存储在日志文件中,消费者会循环从broker拉取消息。
那么从上图的图中可以看出kafka丢消息可能存在的三个地方分别为:
- 生产者到broker
- broker到磁盘
- 消费者
生产者到broker消息丢失
生产者发送消息到broker是会存在消息丢失的,大多可能是由于网络原因引起的,消息中间件中一般都是通过ack来解决这个问题的,kafka中可以通过设置ack来解决这个问题。
acks有三种类型:
- 0
- 1
- -1(all)
acks为0
acks设置为0,代表生产者发送消息后就不管不顾了,不用等待broker的任何响应,那么可能网络异常或者其他原因导致broker没有处理到到这条消息,那么消息就丢失了。
acks为1
acks设置为1,代表生产者发送消息到broker后,只需要broker的leader副本确认收到后就成功响应,不需要follower副本响应,就算follower副本崩溃了,也会成功响应。
acks为-1(all)
acks设置为-1,或者为all,那么生产者发送消息需要leader和follower都收到并写入消息才成功响应生产者,也就是ISR
集合要全部写入,当ISR集合中只要有一个没有写入成功,那么就收到失败响应,所以acks=-1能够在最大程度上保证消息的不丢失,但是也是有条件的,需要ISR集合中有两个以上副本才能保证,如果只有一个副本,那么就是就只有一个leader,没有follower,如果leader挂掉,就不能选举出一个eader,消息自然也就丢失,这和acks=1是一样的
。
解决消息丢失
从上面三种类型的acks中我们可以看出,acks=-1是保证消息从生产者到broker不丢失的最佳设置方式,不过我们也能想到,它需要ISR每个副本都成功应答,所以它的效率自然没有前面两个高,不过此篇我们讨论的是保证消息不丢失问题,所以一切从不丢失层面区说。
如果消息发送失败,那么生产者可以重试发送消息,可以手动在代码中编写消息重发逻辑,也可以配置重试参数。
- retries
- retry.backoff.ms
retries表示重试次数,retry.backoff.ms表示重试时间间隔,比如第一次重试依旧没成功,那么隔多久再进行重试,kafka重试的底层逻辑是将没发送成功的消息重新入队,因为kafka的生产者生产消息后,消息并非就直接发送到broker,而是保存在生产者端的收集器(RecordAccumulator)
,然后由Sender线程去获取RecordAccumulator中的消息,然后再发送给broker,当消息发送失败后,会将消息重新放入RecordAccumulator中,具体逻辑可以看kafka的生产者端Sender的源码。
消息重发引起的消息顺序性问题
要注意,消息发送失败进行重发不能保证消息发送的顺序性,这里的顺序性是单分区顺序性
,如果服务对于消息的顺序性有严格的要求,那么我们可以通过设置属性max.in.flight.requests.per.connection=1
来保证消息的顺序性,这个配置对应的是kafka中InFlightRequests
,max.in.flight.requests.per.connection
代表请求的个数,kafka在创建Sender的时候会判断,如果maxInflightRequests为1,那么guaranteeMessageOrder就为true,就能保证消息的顺序性。
broker到磁盘丢消息
broker收到消息后,需要将消息写入磁盘的log文件中,但是并不是马上写,因为我们知道,生产者发送消息后,消费者那边需要马上获取,如果broker要写入磁盘,那么消费者拉取消息,broker还要从log文件中获取消息,这显然是不合理的,所以kafka引入了(page cache)页缓存。
page cache是磁盘和broker之间的消息映射关系,它是基于内存的,当broker收到消息后,会将消息写入page cache,然后由操作系统进行刷盘,将page cache中的数据写入磁盘。
如果broker发生故障,那么此时page cache的数据就会丢失,broker端可以设置刷盘的参数,比如多久刷盘一次,不过这个参数不建议去修改,最好的方案还是设置多副本,一个分区设置几个副本,当broker故障的时候,如果还有其他副本,那么数据就不会丢失。
消费者丢消息
kafka的消费模式是拉模式,需要不断地向broker拉取消息,拉取的消息消费了以后需要提交offset,也就是提交offset这里可能会出现丢消息,kafka中提供了和offset相关的几个配置项。
- enable.auto.commit
- auto.commit.interval.ms
- auto.offset.reset
下面我们先了解一下kafka offset的提交和参数详解。
enable.auto.commit代表是否自动提交offset,默认为true,auto.commit.interval.ms代表多久提交一次offset,默认为5秒。
如下图,当前消费者消费到了分区中为3的消息。
那么下次当消费者读取消息的时候是从哪里读取呢,当然从4
开始读取,因为是从上次读取的offset的下一位开始读取,所以我们就说当前消费组的offset为4
,,因为下次是从4开始消费,如果5秒之内又消费了两条消息然后自动提交了offset,那么此时的offset如下:
enable.auto.commit如果为false,就代表不会自动提交offset。
auto.offset.reset=latest代表从分区中最新的offset
处开始读取消息,比如某个消费者组上次提交的偏移量为5,然后后面又生产了2条消息,再次读取消息时,读取到的是6,7,8
这个三个消息,如果enable.auto.commit
设置为false,那么不管往分区中写入多少消息,都是从6
开始读取消息。
此时如果一个新的的消费组
订阅了这个分区,因为这个消费者组没有在这个分区提交过offset,所以它获取消息并不是从6
开始获取,而是从1
开始获取。
所以可知每个消费者组在分区中的offset是独立的。
auto.offset.reset还可以设置为earliest
和none
,使用earliest,如果此消费组从来没有提交过offset,那么就从头开始消费,如果提交过offset,那么就从最新的offset处消费,就和latest一样了
,使用none,如果消费组没有提交过offset,在分区中找不到任何offset,那么就会抛出异常。
org.apache.kafka.clients.consumer.NoOffsetForPartitionException: Undefined offset with no reset policy for partitions: [stock1-0]
上面我们初步了解了offset的一些知识,对offset的提交和和读取有一些了解,因为上面我们只提及offset的自动提交,而自动提交的主动权在kafka,而不在我们,所以可能因为一些原因而导致消息丢失。
消息处理异常
当我们收到消息后对消息进行处理,如果在处理的过程中发生异常,而又设置为自动提交offset,那么消息没有处理成功,offset已经提交了,当下次获取消息的时候,由于已经提交过ofset,所以之前的消息就获取不到了,所以应该改为手动提交offset,当消息处理成功后,再进行手动提交offset。
总结
关于kafka的消息丢失问题和解决方案就说到这里,我们分别从生产者到broker,broker到磁盘以及消费者端进行说明,也引申出一些知识点,可能平时没有遇到消息丢失的情况,那是因为网络比较可靠,数据量可能不大,但是如果要真的实现高可用,高可靠,那么就需要对其进行设计。
今天的分享就到这里,感谢你的观看,我们下期见,如果文中有说得不合理或者不正确的地方,希望你能进行指点
一文了解清楚kafka消息丢失问题和解决方案的更多相关文章
- 转载来自朱小厮博客的 一文看懂Kafka消息格式的演变
转载来自朱小厮博客的 一文看懂Kafka消息格式的演变 ✎摘要 对于一个成熟的消息中间件而言,消息格式不仅关系到功能维度的扩展,还牵涉到性能维度的优化.随着Kafka的迅猛发展,其消息格式也在 ...
- Kafka消息丢失
1.Kafka消息丢失的情况: (1)auto.commit.enable=true,消费端自动提交offersets设置为true,当消费者拉到消息之后,还没有处理完 commit interval ...
- 实际业务处理 Kafka 消息丢失、重复消费和顺序消费的问题
关于 Kafka 消息丢失.重复消费和顺序消费的问题 消息丢失,消息重复消费,消息顺序消费等问题是我们使用 MQ 时不得不考虑的一个问题,下面我结合实际的业务来和你分享一下解决方案. 消息丢失问题 比 ...
- 一文看懂Kafka消息格式的演变
摘要 对于一个成熟的消息中间件而言,消息格式不仅关系到功能维度的扩展,还牵涉到性能维度的优化.随着Kafka的迅猛发展,其消息格式也在不断的升级改进,从0.8.x版本开始到现在的1.1.x版本,Kaf ...
- 【消息队列面试】11-14:kafka高可靠、高吞吐量、消息丢失、消费模式
十一.kafka消息高可靠的解决方案 1.高可靠=避免消息丢失 解决消息丢失的问题 2.如何解决 (1)保证消息发送是可靠的(发成功了/落到partition) a.ack参数 发送端,采用ack机制 ...
- 如何处理RabbitMQ 消息堆积和消息丢失问题
消息堆积 解决方案: 增加消费者或后台相关组件的吞吐能力 增加消费的多线程处理 根据不同的业务实现不同的丢弃任务,选择不同的策略淘汰任务 默认情况下,RabbitMQ消费者为单线程串行消费,设置并行消 ...
- Kafka无消息丢失配置
Kafka到底会不会丢数据(data loss)? 通常不会,但有些情况下的确有可能会发生.下面的参数配置及Best practice列表可以较好地保证数据的持久性(当然是trade-off,牺牲了吞 ...
- kafka消息会不会丢失
转载:https://baijiahao.baidu.com/s?id=1583469327946027281&wfr=spider&for=pc 消息发送方式 想清楚Kafka发送的 ...
- Kafka leader副本选举与消息丢失场景讨论
如果某个broker挂了,leader副本在该broker上的分区就要重新进行leader选举.来简要描述下leader选举的过程 1.4.1 KafkaController会监听ZooKeeper的 ...
- kafka系列八、kafka消息重复和丢失的场景及解决方案分析
消息重复和丢失是kafka中很常见的问题,主要发生在以下三个阶段: 生产者阶段 broke阶段 消费者阶段 一.生产者阶段重复场景 1.根本原因 生产发送的消息没有收到正确的broke响应,导致pro ...
随机推荐
- shell语法1-概论、注释、变量、字符串
如果感觉有点忘了或者有点懵,敲出来测试测试就好了 一:概论 Linux系统中一般默认使用bash,文件开头需要写#! /bin/bash,指明bash为脚本解释器chmod +x filename:使 ...
- el-dropdown-item 添加点击 事件无效 (vue)
如图 无效!!! 为什么呢?? 想了一下,可能是因为 el-dropdown-item 没有自定义click事件 so! 解决办法就是 添加原生事件 : @click.native 还有 ...
- 解决通过Eclipse启动Tomcat-Run On Server出现The selection cannot be run on any server
有时候通过Eclipse启动Tomcat-Run On Server会出现The selection cannot be run on any server的情况如下图: 这是因为没有在eclipse ...
- WEB攻击与防御技术 pikachu——文件包含下载上传漏洞
文件包含漏洞 一.LOCAL 上来就是一个选择,当我们选择一个球员的时候,如图所示,url会提交一个get请求 如果这个服务器架设在linux上我们就可以一直../../../../../到根目录然后 ...
- flume往kafka中导入数据
1.编辑flume的配置文件 a1.sources = r1 a1.channels = c1 # Describe/configure the source a1.sources.r1.type = ...
- kafka工具的使用-发送数据
1.了解推送数据的是哪个topic,选择对应topic下面的partition分区 2.右侧界面选择Data,并点击『+』号: 3.可选择添加单个消息『add Single Message』或者添加多 ...
- Java基础Day7-值传递和引用传递
一.值传递 Java都是值传递. 值传递:是指在调用函数时,将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,就不会影响到实际参数. 值传递是对基本数据类型而言. 二.引用传递 引用传递 ...
- 库已安装但找不到ttkbootstrap库
cmd里装,弹提示Requirement already satisfied pip install --target=F:\Python37\lib ttkbootstrap https://blo ...
- 我的JAVA后端技术选型(2020版)
JAVA后端技术选型(2020版)集群网关: LVS+keepalived 或 HAProxy服务网关 : zuul1.x注册中心: Eureka,Zookeeper配置中心: Spring Clou ...
- 探秘ThreadLocal
一 类结构 主要是set(T), get(), remove()方法 二 TheadLocal是什么时候创建的 threadLocal的初始化, lazy creating, 用到的时候(get 或 ...