当前位置: 首页 > news >正文

completefuture造成的rpc重试事故

前言

最近经历了一个由于 completefuture 的使用,导致RPC重试机制触发而引起的重复写入异常的生产bug。复盘下来,并非是错误的使用了completefuture,而是一些开发时很难意识到的坑。

背景

用户反馈通过应用A使用ota批量升级设备时存在概率性失败的可能;

功能的运行流程如下:

  1. 应用A调用应用B的rpc接口
  2. 应用B将请求发布至mqtt
  3. 设备订阅接收,开始进行ota升级

通过复盘设备端以及后台的调用日志得知,设备端在相同时间戳或毫秒级相差的时间戳内收到了两条相同的指令,后台日志中也可以找到对应的消息发送日志。

那么这就是一个消息被重复发送的问题,一般有两种情况:

  1. rpc接口被多次调用
  2. 发布消息时出现重复发送

考虑到mqtt的qos特殊性,短暂的将qos=0,即不存在mqtt重发机制,依然会出现重复发送问题;

结合后台的接口调用日志后,可以确认是应用A重复调用了rpc接口。

复盘

在定位到是后台重复调用rpc接口问题后,解决与排查方式也就变得透彻了。

首先是查看代码:经过排查以及debug,应用A只是简单的业务方调用接口,并且由于app上有防触和后台接口限流处理,排除应用A的功能开发问题;

问题只可能出现在 调用rpc应用B接收与返回 两个动作上;

熟悉远程调用服务的同学应该明白,rpc接口调用,特别是基于dubbo-注册中心这样的传统调用方式,是存在默认的失败熔断、降级,以及造成这次事故的罪魁祸首 异常重试机制

重试机制:

在分布式接口调用场景中,上游方调用接口,为保证其接口的高可用性,会配置无感的重试时间以及重试策略用来抵御当网络波动,请求丢失,异常等问题时的接口可用性

由于应用B是中心类应用,是很多服务的下游应用,所以针对接口的高可用的设计都将其考虑到了正常调用的范畴中。

因此未防止应用A发起请求后,出现由于应用B的网络波动或业务内部的长链路导致的超时而出现重试调用的问题,业务B中采用了以下的执行器方式进行具体消息的发布:

    public static void main(String[] args) {System.out.println("我已经收到了:"+t());}public static void rpcInterface(){Executor executor = new ThreadPoolExecutor(1, 2, 1L,TimeUnit.SECONDS, new LinkedBlockingDeque<>(2), Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {System.out.println("业务开始,时间:"+System.currentTimeMillis());try {Thread.sleep(1000L);} catch (InterruptedException e) {}System.out.println("开启供应链头,组装消息");System.out.println("组装");String message = "message";return message;}, executor);completableFuture.whenComplete((message, exception) -> {System.out.println("消息发送:" + message);});return "ok";}

当应用B的接口判断为处理时间不可控、非查询、消息发布等特殊接口时,会通过以上处理,将实际处理动作线程与rpc接口调用的返回分割开。

比如以上代码执行结果为:

出现问题

在排查过程中,猜测一定是CompletableFuture运行中出现了阻塞,导致返回 ok 的时间超过配置的超时时间而发生重试;

往这个方向考虑结果就很清晰了:

CompletableFuture发生阻塞,再次请求rpc接口,这时CompletableFuture运行,第一次与第二次请求同时进行了消息发布动作;

这里先提应用B在此处线程池的设计与使用了:超时时间3S,有边界队列,拒绝策略为线程等待或主线程执行;

在经过压测后并未发现问题,于是在次接口处理中同样使用了该线程池;

但是,批量ota升级这个动作有些业务上的特殊,会导致任务入队到执行的时间比预想中的要长;

因此这里出现阻塞的原因通过一步步排查得出结论为:

1、多个地方使用同一线程池,而最大线程数未扩容;
2、业务内部设计不合理,出现预料外的慢业务链路,导致占满

结论

这就像是一个陌生的同事接手了一个业务,然后模仿其他相识接口的开发copy 了相同的线程池执行器,然后一股脑的进行套用;

最终出现了这种在测试环境很难出现的问题,因为本地网络加上测试环境线程充足的原因,并且因为相同的线程执行器所以也未考虑到经过压测;

不过回顾这次事故本身,问题与解决很简单,可以算是不熟悉系统导致的bug。但是从另一个角度上看,其实完全可以从源头上避免掉这种重复调用rpc接口的bug出现。

接口幂等

处理重复调用,即对接口进行幂等性;

并非所有的rpc接口都需要对接口做幂等处理,对于非订单操作,db生成的功能,仅查询是无所谓重复调用的。

不过还是需要结合实际考虑,因为本次事故的接口中也是考虑到线程的分离也就没注意对接口进行幂等;

rpc接口幂等有三种通用方案:

方案一:

请求方请求时创建对应接口规则的分布式锁,下游方针对该锁作本次请求的一次调用

方案二:

结合重试时间对接口进行同一请求,几秒内请求n次的限制

方案三:

前两者是比较自定义式的在接口的入口处进行幂等的处理方式;

在spring项目中,我们还可以通过aop组件去实现一个基于自定义注解的接口增强;

我们可以设计一个公共的sdk包common,在其中实现接口幂等组件的装配;

实现方式也很简单:

@Aspect
@Component
public class InterfacelimitAspect {@Around("@annotation(limitInterface)) ")public Object limit(ProceedingJoinPoint point, VoiceEnter voiceEnter) throws Throwable {// 组成唯一的业务id point.getArgs();//或使用traceIdboolean is =localCache.get(id);if(is)  //判断是否已经被执行 return;Object proceedResult =  point.proceed();return proceedResult;}
}

版权声明:本站原创文章,于2024-04-03,乐云一发表
转载请注明:https://leyunone.com/normal-notes/rpc-reload.html

相关文章:

completefuture造成的rpc重试事故

前言 最近经历了一个由于 completefuture 的使用&#xff0c;导致RPC重试机制触发而引起的重复写入异常的生产bug。复盘下来&#xff0c;并非是错误的使用了completefuture&#xff0c;而是一些开发时很难意识到的坑。 背景 用户反馈通过应用A使用ota批量升级设备时存在概率…...

6月11号作业

思维导图 #include <iostream> using namespace std; class Animal { private:string name; public:Animal(){}Animal(string name):name(name){//cout << "Animal&#xff1b;有参" << endl;}virtual void perform(){cout << "讲解员的…...

探究Vue源码:深入理解diff算法

前言 在Vue中 组件初次渲染时&#xff0c;会调用 render 函数生成初始的虚拟 DOM 树。 当组件的状态发生变化时&#xff0c;Vue 会重新调用 render 函数生成新的虚拟 DOM 树。 而Diff 算法是用来比较新旧虚拟 DOM 树的差异&#xff0c;并且只对差异部分进行更新的算法,从而尽量…...

qt自适应图片

在 Qt 中&#xff0c;通过重写 paintEvent 方法来添加自适应背景图片的过程如下&#xff1a; 创建一个自定义的 QWidget 子类。重写 paintEvent 方法&#xff0c;在该方法中使用 QPainter 绘制背景图片。使用 QPixmap 加载图片&#xff0c;并调整图片的大小以适应窗口的大小。…...

【区块链】解码拜占庭将军问题:区块链共识机制的哲学基石

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 解码拜占庭将军问题&#xff1a;区块链共识机制的哲学基石引言一、拜占庭将军问…...

MCK主机加固:智能科技,构筑网络安全的铜墙铁壁

在数字化转型的浪潮中&#xff0c;企业服务器的安全已成为维护业务连续性和保护数据资产的关键。MCK主机加固产品&#xff0c;以其创新技术&#xff0c;为企业提供了一个全面、智能、高效的安全解决方案。 一、智能安全监测 MCK主机加固产品采用深度学习算法&#xff0c;能够…...

OpenCV 双目相机标定

文章目录 一、简介1.1单目相机标定1.2双目相机标定二、实现代码三、实现效果参考资料一、简介 1.1单目相机标定 与单目相机标定类似,双目标定的目的也是要找到从世界坐标转换为图像坐标所用到的投影P矩阵各个系数(即相机的内参与外参)。具体过程如下所述: 1、首先我们需要…...

WPF/C#:异常处理

什么是异常&#xff1f; 在C#中&#xff0c;异常是在程序执行过程中发生的特殊情况&#xff0c;例如尝试除以零、访问不存在的文件、网络连接中断等。这些情况会中断程序的正常流程。 当C#程序中发生这种特殊情况时&#xff0c;会创建一个异常对象并将其抛出。这个异常对象包…...

2024年跨平台应用解决方法

个人博客:Sekyoro的博客小屋 个人网站:Proanimer的个人网站 很久没有写这类high-level的文章了,本身这类框架就一直层出不穷,但是其中历久弥坚,坚韧不拔的框架又有多少呢? 首先考虑到学习成本以及掌握一些编程语言在工作、学习生态上的价值,给这些东西适用生态划分一下. Reac…...

人工智能ChatGPT的多种应用:提示词工程

简介 ChatGPT 的主要优点之一是它能够理解和响应自然语言输入。在日常生活中&#xff0c;沟通本来就是很重要的一门课程&#xff0c;沟通的过程中表达的越清晰&#xff0c;给到的信息越多&#xff0c;那么沟通就越顺畅。 和 ChatGPT 沟通也是同样的道理&#xff0c;如果想要 …...

OceanBase v4.2 解读:tenant=all 语义优化,提升易用性

1 背景 1.1 租户类型及特点 OceanBase中有三种类型的租户&#xff1a; sys租户&#xff1a;集群默认创建&#xff0c;生命周期与集群相一致&#xff0c;管理集群和其他租户&#xff0c;具有较高的地位。用户租户&#xff1a;用户创建的业务租户或普通租户&#xff0c;用于运…...

理论和实验

一、理论和实验的关系 (一)理论可以指导实验 理论家提出理论和猜想&#xff0c;实验家就可以做个实验来验证是否适用。 (二)实验可以提升理论认识 实验家通过做实验&#xff0c;观察实验过程和结果后&#xff0c;如果发现和理论预测有误差&#xff0c;那么理论家就能根据新发现…...

Linux 常用命令 - userdel 【删除用户】

简介 userdel 这个命令源自于 “user delete”,即用户删除。这个命令主要用于在 Linux 系统中删除用户账户及其相关文件。当管理员需要移除一个用户及其在系统中的所有踪迹时,会用到这个命令。 使用方式 userdel [选项] 用户名常用参数 -f:强制删除用户,即使用户当前已登…...

等保测评和安全运维

# 等保测评与安全运维&#xff1a;构建企业网络安全的双重保障 引言 在数字化时代&#xff0c;企业面临着日益复杂的网络安全威胁。为了应对这些挑战&#xff0c;企业不仅要实施有效的安全运维措施&#xff0c;还需要通过等保测评确保其信息系统符合国家的安全标准。本文将探讨…...

Java课程设计:基于Java+Swing+MySQL的图书管理系统(内附源码)

文章目录 一、项目介绍二、项目展示三、源码展示四、源码获取 一、项目介绍 图书管理系统是一个常见的软件项目,广泛应用于图书馆、学校、企业等需要管理图书资源的场景。该系统通常涵盖图书信息录入、查询、借阅、归还等核心功能,是实现图书资源高效管理的重要工具。 随着信…...

WireGuard网络架构及配置详解

WireGuard网络架构及配置详解 一.点对点二.中心网关,实现nat穿透弊端:流量全部经过中心网关,带宽上限受限于中心网关 三.借助registry实现双向nat穿透需要借助registry实现 udp打洞, 待二开 一.点对点 yum install epel-release elrepo-release -y yum install yum-plugin-elr…...

VB.NET实现上位机自动识别可用串口

在实际应用中有时会牵扯到挑选可用串口&#xff0c;比如上位机和从站设备使用Modbus RTU协议进行通讯时需要选择COM串口&#xff0c;每次启动连接前都在设备管理器查看较为麻烦&#xff0c;可以设置一个串口自动识别功能&#xff0c;如果选择了错误的串口还可以提示串口选择错误…...

Node.js版本管理工具-NVM

在开发 Node.js 项目时&#xff0c;经常会遇到需要切换不同版本的 Node.js 的情况。为了方便管理和切换各个版本&#xff0c;我们可以使用一些 Node.js 版本管理工具。 Node Version Manager&#xff1a;简称NVM&#xff0c;最流行的 Node.js 版本管理工具之一。它允许我们在同…...

【react】useEffect 快速上手

useEffect 快速上手 useEffect(setup, dependencies?) 可以接收两个参数&#xff0c;分别是回调函数与依赖数组. useEffect 用什么姿势来调用&#xff0c;本质上取决于你想用它来达成什么样的效果。下面我们来简单介绍 useEffect 的调用规则。 每一次渲染后都执行的副作用&a…...

docker容器部署jenkins

提前安装好jdk和maven&#xff0c;jdk最好使用11版本&#xff0c;jdk-11.0.10 docker run -u root -d \ -p 100:8080 \ -v /var/jenkins_home/workspace/:/var/jenkins_home/workspace/ \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /usr/bin/docker:/usr/bin/docker…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

【HTTP三个基础问题】

面试官您好&#xff01;HTTP是超文本传输协议&#xff0c;是互联网上客户端和服务器之间传输超文本数据&#xff08;比如文字、图片、音频、视频等&#xff09;的核心协议&#xff0c;当前互联网应用最广泛的版本是HTTP1.1&#xff0c;它基于经典的C/S模型&#xff0c;也就是客…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)

船舶制造装配管理现状&#xff1a;装配工作依赖人工经验&#xff0c;装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书&#xff0c;但在实际执行中&#xff0c;工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...