本系列故事的所有案例和解决方案只是笔者以前在互联网工作期间的一些事例,仅供大家参考,实际操作应该根据业务和项目情况设计,欢迎大家留言提出宝贵的意见

背景

小王和小明分别维护分布式系统中A、b两个服务,有一个场景是 A服务会向B服务通过MQ发送事件并且推送用户信息,然后B服务保存用户信息。

有一天,小王和小明因为一件事讨论得热火朝天、互不相让,事情由来如下:

  • 风控部的童鞋找小明说在B服务的数据库找不到一些用户资料
  • 小明经过排查,B服务表里确实没有这批用户的数据,在日志里偶尔看到了一些Redis连接超时异常,小明想小王手动帮忙重推试试
  • 小王经过排查,确保自己已经成功推送了那几个用户的数据,并且推送的时候A服务并没有发现MQ异常,觉得自己没有义务去帮忙重推,应该小明自己解决

这时候,在一旁扫地的清洁工老梁过来调解,并帮忙排查分析,导致这个问题的主要原因如下:

  • B服务在接受MQ的处理类捕获了异常,因为异常并没有抛出,所以框架默认自动回复了ACK,MQ认为已经消费者处理成功,就不再重复投放到队列,但此时方法体内因为工具包出现Redis连接超时,抛出异常,导致消息并没有被正常处理

伪代码如下:

    @RabbitHandler
public void handle(byte[] message) {
try {
t = parseBody(messageStr);
} catch (Exception e) {
log.error("消费消息失败", e.getCause());
}
} private void handleMessage(T t) throws MQHandleException {
//唯一标识
String key = t.getLockedId();
//获取锁
DistributedLock lock = DistributedLockFactory.getLock(key);
try {
// 解决分布式服务提交相同资料并发问题
lock.lock(CacheConstants.LOCK_WAIT_TIME, CacheConstants.LOCK_LEASE_TIME, CacheConstants.DEFAULT_CACHE_UNIT);
// 处理业务逻辑
handleBusinessLogic(t);
} catch (LockException e) {
throw new MQHandleException(e);
} finally {
// 释放锁
lock.unLock();
}
}

  • 频繁Redis超时是因为A、B服务共用一个Redis,A服务Key太多把Redis内存资源占满了(也可能连接占满),导致了B服务经常出现连接超时(该故障不是本章主要关注目标)

  • B服务在已经成功接受到消息后,没有把消息先保存起来,所以也导致了自身并没有能力重跑

清洁工老梁跟小王和小明进行一番详谈后,了解到他们主要需求有两个:

  • B服务尽可能自己重新消费信息,而不是一昧依赖A服务手动重推
  • B服务对已接收到的消息,能自己重新消费,当然,这里指的是有意义的消息,如果一些本身A服务推送过来的消息就是有问题的,例如格式错误之类的,这些B服务可以要求A重推

解决思路

经过上面的分析,老梁的解题思路主要分为两个方向:

  • B服务建立自己的本地异常消息事件表。
  • B服务做异常分类,只对可以重跑的消息事件进行重跑

本地异常消息事件表

一般来说,常见的微服务架构实现最终一致性有三种模式:可靠事件模式、业务补偿模式、TCC模式。这里AB服务是通过业务补偿模式实现最终一致性,但这里又跟我们一般的分布式架构的事务问题不同,这里我们只需要保证B服务能最终把正常消息事件消费成功即可。

实现思路:

  • 建立一张本地异常消息事件表,为了避免太多数据库IO操作,这里只会记录异常事件
  • 提取一个通用消息处理层,统一保存异常消息事件,并进行状态更新
  • 提取一个事件恢复模块,统一对失败事件进行追踪
  • 对于重跑仍失败消息事件,设置一个重跑次数上限,进行自动重跑,可以通过调度任务去做(事件恢复模块),当重跑多次仍然失败(像网络异常和数据库异常之类,短时间不会被修复),则后期进行人工重跑

表设计


针对于B服务,对于收到的MQ信息没有进行有效的记录,而且MQ信息处理之后,存在修改错误,没法进行对应信息补充修复的功能,增加通用消息处理层,进行消息体的记录和回溯。 在获取消息之后进行一次记录,进行幂等操作和对应的状态更新, 消息状态在业务相关操作完成后,标记为处理完成,认为对应消息状态结束。

这里hash_value是对请求体进行hash计算得出来的一个值,例如:MD5、SHA-2,保证每个不同请求的hash码不一样,相同的请求hash码相同,可以用于幂等控制。

表大致操作流程:

异常消息状态设计

异常消息有4个状态

  • 待处理 当系统消费失败时,会对特定的异常插入异常事件表,初始状态为 待处理
  • 处理中 当失败恢复模块开始执行任务时会把当前异常事件状态设置为 处理中
  • 处理完成 当失败事件重跑成功后,会把当前异常事件状态设置为 处理完成
  • 异常 当失败事件重跑超过上限次数后,会把当前异常事件状态设置为 异常,等待后期人工重跑

事件恢复模块

失败事件队列在这里是采用数据库表代替


异常分类

因为并非所有的异常都能重跑就能解决问题,我们只能针对可以修复的异常进行重试,这里把异常分为两大类:

  • 可修复异常:可修复异常指的是可以通过重跑解决的异常,如:数据库超时、数据库缺少字段、Redis获取锁失败、处理逻辑有问题导致信息缺失、系统升级导致消费失败、网络问题、服务器不稳定等引起。

    • 可立即修复异常:指一些可以通过立即重试就能恢复的异常。例如短暂的网络中断引起的异常,一般可以在功能代码级进行立即重试,可以使用spring-retry等组件
    • 延迟修复异常:指一些短时间内不能立即恢复的异常,需要延迟执行,等待故障修复。例如依赖的下游系统正在升级,导致一段时间服务接口中断不可以用,需要等待服务启动才能使用,一般通过定时任务设定一定时间间隔或者重跑次数去解决
    • 人工修复异常:指系统没办法直接修复,出现了一些未知异常或者短时间内不可解决的异常,例如Redis宕掉无法预知修复时间、上线时脚本遗漏导致表里缺少字段等,需要人工干预进行重跑,一般通过后台管理页面操作
  • 不可修复异常:不可修复异常指不能通过重跑就能解决的异常。如:上游系统传输格式有问题、消息事件内容本身有误等引起的异常,这些即使重跑也解决不了问题,应该要从上游系统或者根源去解决。

B服务异常处理流程

最后小明负责的B服务按照老梁的思路,重新调整了代码,异常处理流程如下:

互联网那些事 | MQ数据丢失的更多相关文章

  1. 老杜告诉你java小白到大神是怎么炼成的(转载)

    老杜告诉你java小白到大神是怎么炼成的 1. 学习前的准备 一个好的学习方法(应该怎么学习更高效): 一个合格的程序员应该具备两个能力 有一个很好的指法速度(敲代码快) 有一个很好的编程思想(编程思 ...

  2. 最课程阶段大作业06:U度节能平台控制系统

    除了互联网项目,当今社会还有一个概念非常流行,那就是:物联网.什么是物联网?物联网是通过传感设备,按约定的协议,把任意物品与互联网相连接,进行信息交换和通信,以实现智能化识别.定位.跟踪.监控和管理的 ...

  3. IT码农哥放弃50万年薪:辞职卖咖喱凉皮(背后深藏功与名)_互联网的一些事

    IT码农哥放弃50万年薪:辞职卖咖喱凉皮(背后深藏功与名)_互联网的一些事 IT码农哥放弃50万年薪:辞职卖咖喱凉皮(背后深藏功与名)

  4. Aaron Swartz – 互联网天才开挂的人生历程:每时每刻都问自己,现在这世界有什么最重要的事是我能参与去做的?

    Aaron说的一句话让我挺有感触的-- 相信你应该真的每时每刻都问自己,现在这世界有什么最重要的事是我能参与去做的? 如果你没在做那最重要的事,那又是为什么? 1986年11月8日,有个叫Aaron ...

  5. 大型互联网架构概述 关于架构的架构目标 典型实现 DNS CDN LB WEB APP SOA MQ CACHE STORAGE

    大型互联网架构概述 目录 架构目标 典型实现 DNS CDN LB WEB APP SOA MQ CACHE STORAGE 本文旨在简单介绍大型互联网的架构和核心组件实现原理. 理论上讲,从安装配置 ...

  6. Python/MOOC /翻Wall和互联网编程的那些事

    Python MOOC 翻Wall和互联网编程的那些事 声明: 1)本报告由博客园bitpeach撰写,版权所有,免费转载,请注明出处,并请勿作商业用途. 2)若本文档内有侵权文字或图片等内容,请联系 ...

  7. 互联网 DBA 需要做那些事(转)

    众所周知,互联网DBA与传统行业DBA有很大的不同,那就是管理的机器多,新技术更新快,面对的开发多.网络环境复杂.要求7*24待机:这样就 导致互联网DBA的工作在传统DBA工作之上,增加了更多的复杂 ...

  8. MQ,互联网架构解耦神器

    一个架构常识:当调用方需要关心执行结果,通常使用RPC调用. ret = PassportService::userAuth(name, pass); switch(ret){  case(YES) ...

  9. 聊聊消息队列(MQ)那些事

    每年的双十一期间,各大电商平台流量暴增,同时,电商平台系统的负载压力也会很大.譬如订单支付的场景,每个订单支付成功后,服务器可能要完成扣减积分.扣减优惠券.扣减商品库存.发短信等一系列操作.单个用户请 ...

随机推荐

  1. GNE: 4行代码实现新闻类网站通用爬虫

    GNE(GeneralNewsExtractor)是一个通用新闻网站正文抽取模块,输入一篇新闻网页的 HTML, 输出正文内容.标题.作者.发布时间.正文中的图片地址和正文所在的标签源代码.GNE在提 ...

  2. $POJ2311\ Cutting\ Game$ 博弈论

    正解:博弈论 解题报告: 传送门! 首先看到说,谁先$balabala$,因为$SG$函数是无法解决这类问题的,于是考虑转化成"不能操作者赢/输"的问题,不难想到先剪出$1\cdo ...

  3. XRPC之接口双向调用

    一般远程接口调用的服务都是基于客户端主动调用服务端,由服务端来提供相关的接口服务:在新版本的XRPC中引入了一个新的功能,即接口双向通讯,组件提供服务创建客户会话的接口代理并调用客户提供的接口服务.接 ...

  4. POJ3252 Round Numbers 题解 数位DP

    题目大意: 求区间 \([x,y]\) 范围内有多少数的二进制表示中的'0'的个数 \(\ge\) '1'的个数. 解题思路: 使用 数位DP 解决这个问题. 我们设状态 f[pos][num0][n ...

  5. CF1200D White Lines | 前缀和

    传送门 Examples input 1 4 2 BWWW WBBW WBBW WWWB output 1 4 input 2 3 1 BWB WWB BWB output 2 2 input 3 5 ...

  6. leetcode腾讯精选练习之两数相加

    两数相加 题目: 给出两个非空的链表用来表示两个非负的整数.其中,它们各自的位数是按照逆序的方式存储的,并且它们的每个节点只能存储一位数字.如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们 ...

  7. [Windows] 系统清理与优化神器Advanced SystemCare 13 PRO非破解附正版激活码

    Advanced SystemCare是一款功能强大的系统清理优化软件,该软件提供的主要功能有:启动项优化.注册表整理和清理.隐私清扫.垃圾文件清理.快捷方式修复.恶意软件清除.网络加速.系统优化.安 ...

  8. ArcGIS Desktop 10.1 下载地址及破解

    ArcGIS Desktop 10.1 正式版请到这里下载 http://pan.baidu.com/share/link?shareid=27476&uk=3608003693 正式版破解方 ...

  9. 做前端的你还没用这些软件?? out 啦

    1. 编辑器 写代码只是生产软件过程中的一环.无论是数据结构.编译原理.操作系统还是组成原理都是编码的重要基础,试问没有学过编译原理的人能够针对性地进行编译优化吗?不懂操作系统的人能玩得转linux吗 ...

  10. 图解kubernetes调度器预选设计实现学习

    Scheduler中在进行node选举的时候会首先进行一轮预选流程,即从当前集群中选择一批node节点,本文主要分析k8s在预选流程上一些优秀的筛选设计思想,欢迎大佬们指正 1. 基础设计 1.1 预 ...