seata事务回滚引起的skywalking数据库存储空间剧增的问题排查
-
基本信息
产品名称:ATS3.0
问题分类:编码问题
环境类型:环境无关
-
问题现象
11月1日上午华润DBA收到数据库磁盘空间告警,检查后发现skywalking连接的mysql数据库占用空间从之前一直是比较稳定的,但是10月31日开始激增,一天左右原来剩250G+的磁盘空间只剩下了50G左右。进一步排查发现数据主要集中在skywalking的segment表中。 -
问题原因
seata回滚一个数据库操作较多的事务,由于seata客户端的问题,没有正常关闭PrepareStatement最终触发了ORA-01000-超出打开游标的最大数问题(生产库游标单个session最大300),导致回滚失败。然后seata每秒都会再次触发重试,又因为是一个大事务,导致每秒都有大量的事务回滚的sql操作。因为我们安装了skywalking的oracle插件,程序调用oracle的请求也会被记录,最终导致大量的链路信息被记录到segment表中造成了skywalking的存储数据库空间暴增。 -
排查过程
4.1 紧急处置
1.先让客户删除了mysql库今天之前的binlog,释放出部分空间,否正剩余50G很可能几个小时候就会耗尽,释放后剩余空间回到了250G左右,有了比较充足的排查时间。
2.预案:如果空间持续上升,且还没找到原因的话可以尝试临时删除部分skywalking的数据,因为只是用于监控,不影响业务。或者暂时停止下skywalking。
4.2 定位skywalking的空间是被什么请求占用
1.segment表里的endpoint_id表示请求服务及地址的信息,根据这个字段分类排序可以判断一段时间主要是哪个请求占用了空间。
sql: select count(*) as total , endpoint_id from segment s where start_time > 1667286000000 group by endpoint_id order by total desc;
start_time要根据查询的时间调整这个毫秒数


2. 发现主要是有两个请求触发的频率比较高
3. endponit_id下划线左边是服务名(最后的.1也要去掉才是服务名),右边是请求URL,查看skywalking源码,确定这串字符的编码规则,写了一个转换的逻辑new String(Base64.getDecoder().decode(待转换内容), StandardCharsets.UTF_8);
4. 转换后发现这两个请求分别是ntms-financing的Oracle/JDBI/PreparedStatement/executeQuery和Oracle/JDBI/PreparedStatement/executeUpdate
5. 发现都是数据库操作后去ELK查了下financing服务的日志发现有大量的数据库操作日志,都是seata回滚线程操作的,此时基本可以判断是seata不断尝试回滚事务产生的日志,接下来就需要具体是哪些事务回滚失败不停重试,以及回滚失败的原因。
4.3 确认为什么会触发大量的问题请求
触发大量请求的原因:
seata事务失败,如果能回滚成功,则会直接释放掉,如果回滚失败,则会一直尝试重试回滚,每1s重试一次,我们没有配置停止时间,所以会一直重试。回滚的时候会去做undo_log表的查询、根据undo_log表的数据做业务表的查询等操作,如果一个事务操作的数据量很大,那么每次回滚都会打印很多sql语句,也就会对skywalking记录的数据有影响了。
假设一个全局事务是插入1000条数据到表中,那么回滚的时候,会执行一次查询undo_log,对于每行数据,执行一次select for update,执行一次delete,共2001条sql。一次回滚正常要执行这么多sql,如果回滚失败了,过1s后还要再执行,可以看到数据量是很大的。一天之内回滚日志就有五千多万条:

查找回滚失败原因:
通过查看日志找到每次执行一堆回滚sql后都会有一个报错:

报错日志为”ORA-01000: maximum open cursors exceeded“,也就是说seata很可能因为这个问题导致数据无法回滚。
对这个异常的解释:oracle ORA-01000: maximum open cursors exceeded问题的解决方法-CSDN博客
简单地说就是conn.prepareStatement()会打开一个游标,如果循环里调用这段代码,并且没调用close方法的话,就有可能造成上面的问题。
一些命令:oracle怎么查询游标-Oracle-PHP中文网
# 查看当前打开的游标总数
select count(*) from v$open_cursor;
# 每个连接能打开的最大游标数
select value from v$parameter where name = 'open_cursors';
# 更改连接能开启的最大游标数(改成1000)alter system set open_cursors=1000 scope=both;
定位问题:
通过条件"100.100.3.253:8091:4602887063828890271" and "error" 可以看到有一个异常日志,通过调用栈可以大概找到报错的地方

再结合上面的”branchRollback failed. branchType:“可以大概定位到报错位置。
在io.seata.rm.datasource.undo.AbstractUndoLogManager#undo这段代码的位置,是对当前事务分支做回滚的操作。先获取undo_log的中该分支的数据,做反序列化后可以得到执行的每条sql的undo_log。(一个本地事务每次执行sql都会生成一个SQLUndoLog,在连接最后提交时会把该本地事务操作的所有SQLUndoLog封装为BranchUndoLog,序列化到undo_log表中)
再遍历该BranchUndoLog的SQLUndoLog的list,对每一条SQLUndoLog执行io.seata.rm.datasource.undo.AbstractUndoExecutor#executeOn回滚操作。问题就出在这个方法
public void executeOn(Connection conn) throws SQLException {//dataValidationAndGoOn执行一下select xxx for update,对该数据加锁。if (IS_UNDO_DATA_VALIDATION_ENABLE && !dataValidationAndGoOn(conn)) {return;}PreparedStatement undoPST = null;try {String undoSQL = buildUndoSQL();//在这里开启一个游标undoPST = conn.prepareStatement(undoSQL);TableRecords undoRows = getUndoRows();for (Row undoRow : undoRows.getRows()) {ArrayList<Field> undoValues = new ArrayList<>();List<Field> pkValueList = getOrderedPkList(undoRows, undoRow, getDbType(conn));for (Field field : undoRow.getFields()) {if (field.getKeyType() != KeyType.PRIMARY_KEY) {undoValues.add(field);}}undoPrepare(undoPST, undoValues, pkValueList);//做undolog的回滚undoPST.executeUpdate();}} catch (Exception ex) {if (ex instanceof SQLException) {throw (SQLException) ex;} else {throw new SQLException(ex);}}//处理完并没有关闭游标
}
看到该方法只开启了游标,并没有关闭。外面还有一个undo_log的循环,当BranchUndoLog的list过多时,会超过游标数量。
代码模拟:
public void add() {for (int i1 = 0; i1 < 10000; i1++) {TestPO testPO = new TestPO();testPO.setUrid("" + i1);testPO.setName("name" + i1);testPO.setAge(i1);testMapper.insert(testPO);}}@GlobalTransactionalpublic void update() {((TestService)AopContext.currentProxy()).doupdate();int i = 1/0;}@Transactionalpublic void doupdate(){for (int i1 = 0; i1 < 10000; i1++) {TestPO testPO = new TestPO();testPO.setUrid("" + i1);testPO.setName("name2" + i1);testPO.setAge(i1);testMapper.updateById(testPO);}}create table TSYS_TEST
(URID VARCHAR2(64) not nullconstraint TSYS_TEST_PKprimary key,NAME VARCHAR2(64),AGE NUMBER(38)
)
/
执行完add后,再执行update,会报上面超过游标数量的问题。
该问题seata新版本已经更改。就是在上面的方法后面把statement关闭了。

现场的解决方案时先把游标数调成了3000,该事务可以正常回滚了,把资源都释放掉了。等下次xx发版的时候,再把这段逻辑加上。
现场的最大游标是300,也就是说每次失败大概会打印300(回滚条数)+300(select for update)+1(select from undo_log)条日志,一天要打印601*60*60*24=51,926,400 ,基本上就是上面所有命中次数了。所以该结论没什么问题。
-
解决方案
1.临时调大了生产oracle库的游标数,从300调整到了3000,因为游标数不够而一直重试的回滚操作回滚成功了,暂时解决了问题
2.seata client没有正常关闭PrepareStatement的问题已修复,等下下次华润升级的时候更新过去
3. seata事务没有正常结束的情况需要监控起来,不然只能等到引起问题才发现,如果此时存在大量的未完成事务可能就非常难以解决了。
相关文章:
seata事务回滚引起的skywalking数据库存储空间剧增的问题排查
基本信息 产品名称:ATS3.0 问题分类:编码问题 环境类型:环境无关 问题现象 11月1日上午华润DBA收到数据库磁盘空间告警,检查后发现skywalking连接的mysql数据库占用空间从之前一直是比较稳定的,但是10月31日…...
数据库SQL
数据库&SQL 数据库基本概念数据库DataBase定义 数据库管理系统(DBMS)定义在JAVA项目中与数据库的结合数据库管理系统中常见的概念库与表的关系 SQL数据类型数字类型浮点类型字符类型TEXT类型日期类型 SQL语言的分类DDL:数据定义语言修改表结构的注意事项 DML:数据操作语言D…...
C语言实现给一个不多于5位的正整数,要求:一、求它是几位数,二、逆序打印出各位数字。
完整代码: // 给一个不多于5位的正整数,要求:一、求它是几位数,二、逆序打印出各位数字。 #include<stdio.h>int main(){int num;int len0;printf("请输入一个不多于5位的正整数:");scanf("%d",&n…...
101 对称二叉树
原题链接:101 对称二叉树 全代码: /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : va…...
安全测试,接口返回内容遍历~
最近公司被人大量爬取数据,查了一下发现,用户主页接口,没有加用户登录校验,返回了用户的敏感信息有手机号和邮箱,其实这个接口是用不到这些信息的。再加上用户id是自增长的,所以很容易被别人爬取。 既然这…...
【GIS】地理坐标系与投影坐标系的区别
在地理信息系统中,坐标系的选择和使用是至关重要的。我们通常使用的坐标系有两种:地理坐标系和投影坐标系。本文将详细介绍这两种坐标系的概念、区别、转换方式以及常见投影。 一、定义 地理坐标系(Geographic Coordinate System)…...
太细了:美团一面连环夺命20问,搞定就60W起
说在前面 在40岁老架构师尼恩的(50)读者社群中,经常有小伙伴,需要面试美团、京东、阿里、 百度、头条等大厂。 下面是一个小伙伴成功拿到通过了美团一面面试,现在把面试真题和参考答案收入咱们的宝典。 通过美团一面…...
休眠和睡眠有哪些区别?如何让电脑一键休眠?
电脑中有休眠和睡眠,那么它们有什么区别呢?下面我们就通过本文来了解一下。 休眠和睡眠的区别 电脑在睡眠状态时,会切断内存之外的设备电源,电脑会进入睡眠状态,当再次唤醒电脑后,不会影响睡眠前保存好的工…...
Kibana使用Timelion根据时间序列展示数据
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...
基础:JavaScript的怪癖之一:提升(Hoisting)
JavaScript,通常被称为“Web 语言”,是一种多功能且广泛使用的编程语言。它以其怪癖而闻名,其中之一就是 hoisting(提升)。无论你是经验丰富的开发人员还是刚刚开始你的编码之旅,理解提升对于编写干净和高效…...
前端特殊字符转码
前端特殊字符转码 建议 最好不要传名称,传ID 是在不行就用这个方法 name encodeURIComponent(name),...
Python开发运维:Python3.7安装Django3.2
目录 一、理论 1.pip 2.Django 3.Pycharm国内镜像源 二、实验 1.Python3.7安装Django3.2 三、问题 1.安装django3.2报错 2.pip更新报错 一、理论 1.pip (1)概念 1)pip pip 是 Python 的包安装程序。其实,pip 就是 Pyt…...
B站双11,联手天猫暴涨2亿消费新势力
一直以来,手持高活跃、高粘性用户群体的B站是行业用来观察年轻人消费习惯的重要平台。以至于用户群体的不断壮大带动了B站的商业价值。如今B站的商业舞台越来越大,不断地向外界招手,欢迎更多品牌积极加入到这个千万年轻人聚集的内容社区。 2…...
如何选择SVM中最佳的【核函数】
参数“kernel"在sklearn中可选以下几种 选项: 接下来我们 就通过一个例子,来探索一下不同数据集上核函数的表现。我们现在有一系列线性或非线性可分的数据,我们希望通过绘制SVC在不同核函数下的决策边界并计算SVC在不同核函数下分类准确…...
RT-Thread的构建与配置系统
Kconfig:kernel config配置文件(提供系统的配置裁剪功能)Scons:构建工具env工具:主要提供构建系统所需的各种环境变量以及软件包的管理 Env Env是RT-Thread推出的开发辅助工具,针对基于RT-Thread操作系统…...
合肥中科深谷嵌入式项目实战——基于ARM语音识别的智能家居系统(一)
基于ARM语音识别的智能家居系统 我们接下来带大家完成基于语音识别的智能家居系统嵌入式项目实战,使用到stm32开发板,讯飞的离线语音识别,我们在此之前,我们先学习一些Linux系统的基本操作。 。 一、Linux简介 在嵌入式开发中&am…...
Git的简介以及基本使用
目录 一.Git的简介 拓展:Git与SVN的区别(各自的优点与缺点) 二.Git文件的4种状态 三.Git的常用命令 搭建完成之后,将项目文件也上传之后,现在模拟其他人来下载这个代码 今天就分享到这啦!!…...
django安装数据库
使用pip安装django pip3 install django注意我使用的是python3所以用pip3安装,如需安装指定版本 django ..* 检测是否安装成功,不报错,则安装成功 # python3 # import django下边这是报错的 django迁移数据库 再mysql中简历数据库 CREATE DATABA…...
springboot--外部环境配置
外部环境配置 前言1、配置优先级配置文件优先级如下(后面的覆盖前面的)测试 2、外部配置3、导入配置4、属性占位符 前言 场景:线上应用如何快速修改配置,并引用最新配置? springBoot 使用配置优先级外部配置 简化配置…...
『MySQL快速上手』-④-表的操作
文章目录 1.创建表2.查看表结构3.修改表4.删除表 1.创建表 语法格式如下: CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引擎;说明: field 表示列名࿱…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
windows系统MySQL安装文档
概览:本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容,为学习者提供全面的操作指导。关键要点包括: 解压 :下载完成后解压压缩包,得到MySQL 8.…...
自然语言处理——文本分类
文本分类 传统机器学习方法文本表示向量空间模型 特征选择文档频率互信息信息增益(IG) 分类器设计贝叶斯理论:线性判别函数 文本分类性能评估P-R曲线ROC曲线 将文本文档或句子分类为预定义的类或类别, 有单标签多类别文本分类和多…...
多元隐函数 偏导公式
我们来推导隐函数 z z ( x , y ) z z(x, y) zz(x,y) 的偏导公式,给定一个隐函数关系: F ( x , y , z ( x , y ) ) 0 F(x, y, z(x, y)) 0 F(x,y,z(x,y))0 🧠 目标: 求 ∂ z ∂ x \frac{\partial z}{\partial x} ∂x∂z、 …...
