应用场景

C端用户提交工单、工单创建完成之后、会发布一条工单创建完成的消息事件(异步消息)、MQ消费者收到消息之后、会通知各处理器处理该消息、各处理器处理完后都会发布一条将该工单写入搜索引擎的消息、最终该工单出现在搜索引擎、被工单处理人检索和处理。

事故异常体现

1、异常体现

从工单的流转记录发现、工单的状态从A->C->B、理论上 工单的状态只能从A->B->C。此处能得出两个结论、1、各处理器处理完工单之后、状态有误;2、写入到搜索引擎的工单数据被本该更早写入引擎的数据覆盖了。

从监控数据发现、结论1排除。

2、背景解释

一个工单创建完之后、会经历

  • 工单创建完城-->状态新建、将新工单信息更新至ES(搜索引擎)
  • 工单内容审核-->状态已审核、将新工单信息更新至ES
  • 工单分配给指定工作人员-->状态已分配、将最新工单信息更新至ES
  • 其他操作-->状态改变-->将最新工单信息更新至ES

说明:
所有工单的操作都是异步的、没有固定顺序。
保证点:
写到ES之前从数据库所获取的工单信息都是最新的工单信息、无误。
案例中异常情况:
工单实际已经分配了工作人员(已分配状态)、可以查询到被分配的人、但是工单的状态显示是新建状态。

3、事故异常分析

1、创单的顺序是优先于派单的
2、创单之后抛出一个写ES的MQ消息--消息A
3、派单之后也会抛出一个写ES的MQ消息--消息B
4、如果MQ是有顺序的、按照顺序消费消息、MQ消费者消费第一个消息(消息A)肯定是比第二份消息(消息B)要快的、正常情况、工单是绝对没有问题。
(非正常情况、可能是ES自身写消息到集群、有快慢之分、第二个消息会先写完、此种情况基本忽略不计)

5、此处异常是、MQ消息消费无序

  正常拿到消息A、查询数据库的状态正确、可以推送ES消息、再接着拿到消息B、查询数据库的状态正确、可以推送ES消息、因为推送ES没有加分布式锁、导致消息B那个时刻的工单数据被先写入ES、消息A那个时刻的工单数据后写入ES、导致ES的数据被覆盖、最终ES的最新版本的工单状态和数据库的工单状态不一致。

4、解决方式

背景说明(续):写ES的MQ消息可以理解为并发出现、在工单创建的那一刻、所有改动工单状态的消息基本会在ms级别时间内到达。
前提:在写ES的MQ消息中、携带更新完工单之后该工单的时间戳、作为工单的版本号。

方式一:

  暴力方式、直接在写ES的接口新增分布式锁、通过对比消息的版本号和工单数据库中的版本号、即可判定消息要舍弃还是写入ES(不采取、会严重降低写ES的效率)
方式二:
  仅对工单使用分布式锁、同时、在一定时间内(秒级)收集写ES的消息、并且对消息进行排序过滤、仅处理最新版本的工单消息写入ES。

5、感想

1、有序的MQ消息资源会比较贵,还是要代码层保证数据稳定性。
2、验证异常论断的方式是、第一个大胆猜想、第二个必须保证有日志可追踪查询论证。

记一次RocketMQ消费非顺序消息引起的线上事故的更多相关文章

  1. RocketMQ学习笔记(9)----RocketMQ的Producer 顺序消息

    1. 顺序消息原理图 2. 什么是顺序消息? 消费消息的顺序要求同发送消息的顺序一致,在RocketMQ中,主要指的是局部顺序,即一类消息为满足顺序性,必须Producer单线程顺序发送,并且发送给到 ...

  2. 记一次线上事故的JVM内存学习

    今天线上的hadoop集群崩溃了,现象是namenode一直在GC,长时间无法正常服务.最后运维大神各种倒腾内存,GC稳定后,服务正常.虽说全程在打酱油,但是也跟着学习不少的东西. 第一个问题:为什么 ...

  3. 记一次真实的线上事故:一个update引发的惨案!

    目录 前言 项目背景介绍 要命的update 结语 前言   从事互联网开发这几年,参与了许多项目的架构分析,数据库设计,改过的bug不计其数,写过的sql数以万计,从未出现重大纰漏,但常在河边走,哪 ...

  4. RocketMQ源码 — 十、 RocketMQ顺序消息

    RocketMQ本身支持顺序消息,在使用上发送顺序消息和非顺序消息有所区别 发送顺序消息 SendResult sendResult = producer.send(msg, new MessageQ ...

  5. 聊一聊顺序消息(RocketMQ顺序消息的实现机制)

    当我们说顺序时,我们在说什么? 日常思维中,顺序大部分情况会和时间关联起来,即时间的先后表示事件的顺序关系. 比如事件A发生在下午3点一刻,而事件B发生在下午4点,那么我们认为事件A发生在事件B之前, ...

  6. 【mq读书笔记】顺序消息

    注意异常情况导致整个消费无限重试 阻塞消费 mq支持局部消息顺序消费,可以确保同一个消息消费队列中的消息被顺序消费.看下针对顺序消息在整个消费过程中做的调整: 队列负载: DefaultMQPushC ...

  7. RocketMQ专题2:三种常用生产消费方式(顺序、广播、定时)以及顺序消费源码探究

    顺序.广播.定时任务 前插 ​ 在进行常用的三种消息类型例子展示的时候,我们先来说一说RocketMQ的几个重要概念: PullConsumer与PushConsumer:主要区别在于Pull与Pus ...

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

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

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

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

  10. RocketMQ顺序消息

    rocketmq的顺序消息需要满足2点: 1.Producer端保证发送消息有序,且发送到同一个队列.2.consumer端保证消费同一个队列. 生产端: RocketMQ可以严格的保证消息有序.但这 ...

随机推荐

  1. AtCoder Beginner Contest 333

    总结 人生第一次掉rating 各种降智操作 A 水题 B 逆天操作 WA了3发 第三次交的时候以为过了,等到切完E发现怎么B还没过( #include<bits/stdc++.h> us ...

  2. 机器学习策略篇:详解开发集和测试集的大小(Size of dev and test sets)

    在深度学习时代,设立开发集和测试集的方针也在变化. 可能听说过一条经验法则,在机器学习中,把取得的全部数据用70/30比例分成训练集和测试集.或者如果必须设立训练集.开发集和测试集,会这么分60%训练 ...

  3. 使用小波分析和深度学习对心电图 (ECG) 进行分类 mcu-ai低成本方案 mcu-ai低成本方案

    具体的软硬件实现点击 http://mcu-ai.com/ MCU-AI技术网页_MCU-AI人工智能 此示例说明如何使用连续小波变换 (CWT) 和深度卷积神经网络 (CNN) 对人体心电图 (EC ...

  4. 抛砖系列之文本处理工具-awk

    AWK是一个优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一.这种编程及数据操作语言(其名称得自于它的创始人阿尔佛雷德·艾侯.彼得·温伯格和布莱恩·柯林汉姓氏的首个字母 ...

  5. three.js教程8-渲染器WebGLRenderer和前端UI界面

    1.html的UI交互界面与Canvas画布叠加 需求:把threejs Cavnas画布和HTML元素叠加布局,在canvas上添加按钮,通过按钮点击修改canvas场景. // canvas画布绝 ...

  6. GPS坐标、火星坐标、百度坐标之间的转换--提供javascript版本转换代码

    1.国内几种常用坐标系说明 WG-S84: GPS仪器记录的经纬度信息,Google Earth采用,Google Map中国范围外使用,高德地图中国范围外使用.GCJ-02: 火星坐标系,中国国家测 ...

  7. RMBG1.4服务器部署指南

    近期,一家AIGC公司BRIA开源了一个出圈的模型:RMBG-1.4,它可以实现高质量地一键去除图片中的背景.下面是一些具体的例子,可以看到这个模型可以实现非常精细的"抠图". R ...

  8. 全面系统的AI学习路径,帮助普通人也能玩转AI

    前言 现如今AI技术和应用的发展可谓是如火如荼,它们在各个领域都展现出了巨大的潜力和影响力.AI的出现对于我们这些普通人而言也是影响匪浅,比如说使用AI工具GPT来写文档查问题.使用AI辅助编程工具帮 ...

  9. 密码学—DES加密的IP置换Python程序

    文章目录 IP初始置换与逆置换 编程想法 转二进制过程中的提取一些数据 64为一组 IP置换 IP逆置换 DES发明人 美国IBM公司W. Tuchman 和 C. Meyer1971-1972年研制 ...

  10. Linux之kill命令

    1.kill命令的使用格式 kill [参数] [进程号] 2.kill命令的功能 发送指定的信号到相应进程.不指定型号将发送SIGTERM(15)终止指定进程.如果任然无法终止该程序可用" ...