关于 Kafka 消息丢失、重复消费和顺序消费的问题

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

消息丢失问题

比如我们使用 Kakfa 时,以下场景都会发生消息丢失:

  • producer -> broker (生产者生产消息)
  • broker -> broker (集群环境,broker 同步给其他 broker)
  • broker -> consumer (消费者消费消息)

解决方案也很简单,设置 acks(消息确认机制)retries(重试机制)factor(设置 partition 数量)...

一般来说,最常见的消息丢失场景就是:consumer 消费消息

要保证 consumer 消费消息时不丢失消息,必须使用手动提交 ack

我们业务是这样实现的:

  1. Kafka 拉取消息(一次批量拉取 100条)
  2. 为每条消息分配一个 msgId(递增)
  3. msgId 存入内存队列(sortSet)
  4. 使用 Map 存储 msgIdmsg (包含 offset)的映射关系
  5. 当业务处理完消息后,获取当前消息的 msgId,然后从 sortSet 中删除该 msgId(表示该消息已经处理过了)
  6. ack 时,如果当前 msgId <= sortSet(msgId 在 sortSet 中是从小到大排列) ,就提交当前 offset
  7. 就算 consumer 在处理消息时挂了,下次重启时就会从 sortSet 队首的消息开始拉取,实现至少处理一次语义。
  8. 步骤 7 存在一个问题:当消息处理完后,还没从 sortSet 中删除该 msgId,系统就挂了,当系统重启时,又会重新处理一次刚刚已处理过的消息,这就引出消息重复消费的问题了。

消息重复消费

要解决消息重复消费,也就是要实现幂等(幂等就是:多次请求,但结果保持不变,举一个例子你就明白了:在 http 中,你发送同一个 get 请求,无论发送多少次,返回结果都是一样的

回到我们的业务场景上,我以处理订单消息为例:

  • 幂等Key 由我们的订单Id + 订单状态组成(一笔订单的状态只会处理一次)

  • 在处理之前,我们首先会去 Redis 查询是否存在这个 Key

    如果存在,说明我们已经处理过了,直接丢掉;

    ​ 如果不存在,说明没处理过,继续往下处理;

  • 最终的逻辑是:将处理过的数据存到DB上,再把 幂等Key 存到 Redis

显然一般场景下 Redis 是无法保证幂等的

所以Redis只是一个前置处理,最终的幂等性依赖 DB唯一Key(订单Id+订单状态)

总的来说就是:通过 Redis 做前置处理,DB 唯一索引做最终保证实现幂等性

消息顺序消费

消息的顺序性很好理解,还是以订单处理为例

订单的状态有:支付、确认收货、完成等等,而订单下还有计费、退款的消息报

理论上来说:支付的消息肯定要比退款的消息先到。

但是程序处理的过程就不一定了,所以我们处理消息顺序消费的流程如下:

  • 宽表:创建一张宽表,唯一索引是 订单Id,将订单的每个状态拆分为一个列,当消息来了,只更新对应的字段就好,消息只会存在短暂的状态不一致问题,但是最终状态是一致的
  • 消息补偿机制
  • 把相同的 userID/orderId 发送到相同的 partition(因为一个 consumer 消费一个 partition)

实际业务处理 Kafka 消息丢失、重复消费和顺序消费的问题的更多相关文章

  1. Kafka消息丢失

    1.Kafka消息丢失的情况: (1)auto.commit.enable=true,消费端自动提交offersets设置为true,当消费者拉到消息之后,还没有处理完 commit interval ...

  2. RocketMQ事务消费和顺序消费详解

    一.RocketMq有3中消息类型 1.普通消费 2. 顺序消费 3.事务消费 顺序消费场景 在网购的时候,我们需要下单,那么下单需要假如有三个顺序,第一.创建订单 ,第二:订单付款,第三:订单完成. ...

  3. 【转】RocketMQ事务消费和顺序消费详解

    RocketMQ事务消费和顺序消费详解 转载说明:该文章纯转载,若有侵权或给原作者造成不便望告知,仅供学习参考. 一.RocketMq有3中消息类型 1.普通消费 2. 顺序消费 3.事务消费 顺序消 ...

  4. MQ的消息丢失/重复/积压的问题解决

    在我们实际的开发过程中,我们肯定会用到MQ中间件,常见的MQ中间件有kafka,RabbitMQ,RocketMQ.在使用的过程中,我们必须要考虑这样一个问题,在使用MQ的时候,我们怎么确保消息100 ...

  5. Kafka丢数据、重复消费、顺序消费的问题

    面试官:今天我想问下,你觉得Kafka会丢数据吗? 候选者:嗯,使用Kafka时,有可能会有以下场景会丢消息 候选者:比如说,我们用Producer发消息至Broker的时候,就有可能会丢消息 候选者 ...

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

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

  7. RocketMQ的顺序消费和事务消费

    一.三种消费 :1.普通消费 2. 顺序消费 3.事务消费 1.1  顺序消费:在网购的时候,我们需要下单,那么下单需要假如有三个顺序,第一.创建订单 ,第二:订单付款,第三:订单完成.也就是这个三个 ...

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

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

  9. kafka系列八、kafka消息重复和丢失的场景及解决方案分析

    消息重复和丢失是kafka中很常见的问题,主要发生在以下三个阶段: 生产者阶段 broke阶段 消费者阶段 一.生产者阶段重复场景 1.根本原因 生产发送的消息没有收到正确的broke响应,导致pro ...

随机推荐

  1. [] == ![] 返回 true

    对于==来说,如果数据类型不同,就会进行隐式类型转换. 首先判断是否在对比 null 和 undefined,是的话就会返回 true: 判断其中一方是否为 string ,在与 number进行比较 ...

  2. java的三大特性----封装、集成、多态

    当我们被问到你对java的封装.继承.多态是什么看法的时候,你会想到什么? 想到的会不会是封装就是将类的成员属性用privet修饰一下,达到私有化的目的,只暴露方法,从而达到成员变量私有化的目的. 而 ...

  3. git pull origin master 报错问题解决 fatal: couldn‘t find remote ref master

    报错:fatal: couldn't find remote ref master 解决:使用以下命令 git pull origin main 替代报错命令: git pull origin mas ...

  4. CF698C题解

    为什么 \(n,k \leq 20\)? 我还以为是什么 \(n,k \leq 10^6\) 的厉害题/qd 看到这个队列操作很迷惑,但是仔细看看要操作 \(10^{100}\) 遍,所以我们可以直接 ...

  5. WMTS服务解析

    WMTS服务解析 1.基本思路 拼接地址,请求xml文件 ↓ 处理获取的xml文件,返回参数 ↓ 获取xml解析得到的参数,组织结构 2.对应函数 requestWMTS (olUrl) ↓ hand ...

  6. Oneops运维系统

      背景:公司对接其他系统时都会将业务分为几大模块由不同的人员去开发部署.那么部署方式为传统方式登录服务器,然后操作.所以每次上线我们可能都需要等待别的同事操作完才能操作自己所负责的业务系统.针对以上 ...

  7. 嵌入式Linux应用开发完全手册之环境搭建

    @ 目录 0.下载源配置 1.电脑BIOS启动虚拟化 2.linux网卡查看与IP设置 3.windows NAT虚拟网络配置 4.修改 Ubuntu 的 mountd 端口 5.vim设置 6.Mo ...

  8. 4月17日 python学习总结 反射、object内置方法、元类

    一.反射 下述四个函数是专门用来操作类与对象属性的,如何操作? 通过字符串来操作类与对象的属性,这种操作称为反射 class People: country="China" def ...

  9. sql注入mysql注入

    #跨库查询及应用思路 information_schema表特性,记录数据库名.表名.列名对应表 information_schema.schemata:存储所有数据库名 schema_name:数据 ...

  10. 深入理解Java虚拟机-HotSpot虚拟机对象探秘

    一.对象的创建过程 虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载.解析和初始化过.如果没有,那就先执行相应的类 ...