如果你的MQ消息要从Kafka切换到RocketMQ且不停机,怎么做?在让这个MQ消息调用第三方发奖接口,但无幂等字段又怎么处理?今天小傅哥就给大家分享一个关于MQ消息在这样的场景中的处理手段。

这是一种比较特例的场景,需要保证切换的MQ消息不被两端同时消费,并且还需要在一段消费失败后的MQ还可以继续重试。并且这一端消费的MQ消息,也要保证自身的幂等。

我们知道一般通用场景下,MQ消息都会有一个业务唯一ID值,用于接收方做仿重处理。但除此之外还应该有一个MQ消息本身的ID,这个ID也要全局唯一,每一条消息都要有一个ID,这是因为MQ是可能重复发送的(发送MQ成功,但获取MQ发送结果响应超时或更新库表消息状态失败,则重复发送),如果没有消息的唯一ID也就没法确保是哪一条消息了。

这个ID可以用于;唯一标识、去重、链路追踪、幂等性、事务以及安装性等,但可能有些伙伴在做MQ消息发送的时候,是容易忽略而没有在MQ中添加这个ID,或者随意用时间戳来当ID用,这样都是不合理的。会影响一些场景的代码健壮性设计。

需求背景描述好了,接下来,我们看看这样的场景怎么设计。

1. 场景问题

将原本使用 Kafka 的MQ方式,迁移到 RocketMQ,同时部分场景的 MQ 消息调用三方接口是没有幂等字段的,需要做好程序兼容处理。

2. 场景思考

首先我们要知道在分布式架构下,我们每做的技术方案都要考虑顺序性和临界状态。像是MQ的生产和消费都是多套应用实例部署的,那么生产端发送出来的MQ消息到不同的队列中也是有延迟和存放顺序以及拉取消费不同的情况。如;生产端发送MQ为A、B、C、D,但到Kafka/RocketMQ以及不同的消费端拉取时,不一定是A、B、C、D的顺序,那么直接做切量开关,是可能导致一个A消息在Kafka队列中消费完,点击切换开关(一种切量哈希计算手段,如消息{A}哈希值最后两位当做百分比用),正好RocketMQ也会把A消费掉。这样同一个消息就被重复消费了。

3. 方案设计

在整个方案设计中,我们要考虑几个非常重要的点。如图:

  • 一个是切换的两端MQ消费是抢占式加锁,避免重复消费。这是因为切量开关,切换过程中,两个消息队列中的MQ并不是顺序可靠的,可能存在重复消费,所以要加分布式锁。

  • 一段MQ消费失败要进行重试,但这个时候不能在消费失败后删分布式锁,因为MQ消费都是很快的,可能导致删锁后另外一端MQ进行了相同的消费。那可能有些伙伴会说,那也没关系呀,反正失败的这段没有消费成功。当往往失败并不一定是直接的结果失败,可能是网络失败,可能是超时失败等。也就是实际成功了,但超时反馈了。所以不能被其他端重复消费,并且要保证自己这一端消费失败后可重试。所以这块要设计可重入锁,也就是 setnx 加锁的值,为自身一段的 mq 类型,这样自己在接收mq消息以后,检查锁为自身加锁值可重试。这样也就保证了一端消费重试,不会让另外一端把MQ也跟着消费掉,因为setnx存在,并且有加锁值判断,所以不能进入。

  • 另外MQ消息还可能存在同一个MQ发送多次的场景,这个是非常正常的。比如,你再发送MQ的时候,超时网络抖动失败(1万次会有1次),那么就会补偿重发。但这个MQ已经发送过了,所以会接收2条MQ消息。那么在消费的时候,不能让2个MQ消息都进入消费中,因为多台实例消费,可能都去调用发奖了。那么这里还需要给MQ的ID进行幂等加锁。确保一个MQ消息,失败后,顺序轮训重试。也就保证了,发奖的过程中不会出现超发奖品。大部分三方接口还是有幂等字段的,有的话会更好。

  • 另外还有2个开关,一个是消费开关,一个是切量开关。消费开关要在整个新的MQ改造工程工程全部上线后开启,但还要被切量开关限定消费。开启后,切量开关才会生效。切量是一种哈希值的百分比比对,比如一个哈希值最后两位是10,那么切量配置小于等于10%则这个MQ则可以被切量后消费,另外一段则不消费这个MQ。

  • 另外,为了方便测试线上功能,还会加入白名单。不过大部分时候这类东西会用通用组件能力解决。

这样的场景方案设计,是非常值得积累的,同类的思想也可以帮我们解决很多共性问题。

可重入锁思想,设计MQ迁移方案的更多相关文章

  1. Java不可重入锁和可重入锁的简单理解

    基础知识 Java多线程的wait()方法和notify()方法 这两个方法是成对出现和使用的,要执行这两个方法,有一个前提就是,当前线程必须获其对象的monitor(俗称“锁”),否则会抛出Ille ...

  2. JAVA锁机制-可重入锁,可中断锁,公平锁,读写锁,自旋锁,

    如果需要查看具体的synchronized和lock的实现原理,请参考:解决多线程安全问题-无非两个方法synchronized和lock 具体原理(百度) 在并发编程中,经常遇到多个线程访问同一个 ...

  3. Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等

    Java 中15种锁的介绍 Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等,在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类 ...

  4. Java 种15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁等等…

    Java 中15种锁的介绍 1,在读很多并发文章中,会提及各种各样的锁,如公平锁,乐观锁,下面是对各种锁的总结归纳: 公平锁/非公平锁 可重入锁/不可重入锁 独享锁/共享锁 互斥锁/读写锁 乐观锁/悲 ...

  5. AQS学习(二) AQS互斥模式与ReenterLock可重入锁原理解析

    1. MyAQS介绍    在这个系列博客中,我们会参考着jdk的AbstractQueuedLongSynchronizer,从零开始自己动手实现一个AQS(MyAQS).通过模仿,自己造轮子来学习 ...

  6. Java中可重入锁ReentrantLock原理剖析

    本文由码农网 – 吴极心原创,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划! 一. 概述 本文首先介绍Lock接口.ReentrantLock的类层次结构以及锁功能模板类AbstractQue ...

  7. ReenTrantLock可重入锁(和synchronized的区别)总结

    ReenTrantLock可重入锁(和synchronized的区别)总结 可重入性: 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也 ...

  8. synchronized 是可重入锁吗?为什么?

    什么是可重入锁? 关于什么是可重入锁,我们先来看一段维基百科的定义. 若一个程序或子程序可以“在任意时刻被中断然后操作系统调度执行另外一段代码,这段代码又调用了该子程序不会出错”,则称其为可重入(re ...

  9. 可重入锁 & 不可重入锁

    可重入锁指同一个线程可以再次获得之前已经获得的锁,避免产生死锁. Java中的可重入锁:synchronized 和 java.util.concurrent.locks.ReentrantLock. ...

  10. Java并发编程原理与实战十七:AQS实现重入锁

    一.什么是重入锁 可重入锁就是当前持有锁的线程能够多次获取该锁,无需等待 二.什么是AQS AQS是JDK1.5提供的一个基于FIFO等待队列实现的一个用于实现同步器的基础框架,这个基础框架的重要性可 ...

随机推荐

  1. 分享一张2020年用jaegertracing画的tomcat8.5启动流程图

    今天整理电脑的时候意外发现一张tomcat8.5的启动流程图,是笔者2020年借助jaegertracing绘制的,想想还比较有意思,在这里分享一下,当初闲来无事折腾了小半天,具体过程已经是记不起来了 ...

  2. 07. C语言程序执行流程控制

    [有条件执行语句] if esle 语句 if else 语句根据一个条件确定是否执行一段代码,执行条件是一个布尔值,布尔值为true则执行,为false则不执行,同时可以设置不符合条件时执行的语句. ...

  3. Linux部署Apache 网站服务器(httpd服务)

    一.项目导入: 某学院组建了校园网,建设了学院网站.现需要架设Web服务器来为学院网站安家,同时在网站上传和更新时,需要用到文件上传和下载,因此还要架设FTP服务器,为学院内部和互联网用户提供WWW. ...

  4. kettle使用2-增量插入

    1.新建转换 2.在DB连接中,新建2个数据库连接 3.在输入中,新建:表输入 4.在输入中,新建:表输入 5.在输出中,新建:表输出

  5. C 语言编程 — 数据类型的别名

    目录 文章目录 目录 前文列表 typedef 关键字 typedef 和预处理器指令 #define 的区别 前文列表 <程序编译流程与 GCC 编译器> <C 语言编程 - 基本 ...

  6. Java面试题:Spring中的循环依赖,给程序员带来的心理阴影

    循环依赖通常发生在两个或多个Spring Bean之间,它们通过构造器.字段(使用@Autowired)或setter方法相互依赖,从而形成一个闭环.下面是一个使用字段注入(即使用@Autowired ...

  7. winform 绘图控件 chart 实时曲线图

    官方教程:http:////files.cnblogs.com/files/HelloQLQ/Winform图表.rar 更多参考:https://blog.csdn.net/boxuming/art ...

  8. layui-框架学习小总结

    主要6点: 1.导航栏变成了类似tab的页签,支持关闭,点击刷新. 2.左侧菜单树可隐藏. 3.树的搜索. 4.表格的新增行,并保存到后台. 5.表格 加载 下拉框,并赋值,选择了值后把值同步到表格对 ...

  9. 浅析MySQL 8.0直方图原理

    本文分享自华为云社区<[MySQL技术专栏]MySQL8.0直方图介绍>,作者:GaussDB 数据库. 背景 数据库查询优化器负责将SQL查询转换为尽可能高效的执行计划,但因为数据环境不 ...

  10. 如何解决 IntelliJ Idea 编译 Java 项目时,找不到包或找不到符号的问题?

    执行 Maven Reimport 描述: 重新导入 Maven 包. 操作步骤: -> 选择 Project 目录右键 -> Maven -> Reimport 执行 Invali ...