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 表示列名࿱…...

Java源码中有哪些细节可以参考?(持续更新)
欢迎来到啾啾的博客🐱。 记录学习点滴。分享工作思考和实用技巧,偶尔也分享一些杂谈💬。 有很多很多不足的地方,欢迎评论交流,感谢您的阅读和评论😄。 目录 String的比较final的使用transient避免序列化 St…...

实验设计与分析(第6版,Montgomery)第5章析因设计引导5.7节思考题5.8 R语言解题
本文是实验设计与分析(第6版,Montgomery著,傅珏生译) 第5章析因设计引导5.7节思考题5.8 R语言解题。主要涉及方差分析,正态假设检验,残差分析,交互作用图。 (a) dataframe<-data.frame( Lightc(580,568…...
python37天打卡
知识点回顾: 过拟合的判断:测试集和训练集同步打印指标 模型的保存和加载 仅保存权重 保存权重和模型 保存全部信息checkpoint,还包含训练状态 早停策略 作业:对信贷数据集训练后保存权重,加载权重后继续训练50轮&am…...
LVS + Keepalived高可用群集
目录 一:keepalived双击热备基础知识 1.keepalived概述及安装 1.1keepalived的热备方式 1.2keepalived的安装与服务控制 (1)安装keepalived (2)控制keepalived服务 2.使用keepalived实现双击热备. 2.1主服务器的…...
HTML、XML、JSON 是什么?有什么区别?又是做什么的?
在学习前端开发或者理解互联网工作原理的过程中,我们经常会遇到三个非常重要的概念:HTML、XML 和 JSON。它们看起来有点像,但其实干的事情完全不同。 🏁 一、他们是谁?什么时候诞生的? 名称全称诞生时间谁…...
深度解析UniApp盲盒系统开发:从源码架构到多端部署全流程
一、正版盲盒系统的技术选型与源码设计 跨平台开发框架的核心配置 UniApp多端适配方案 环境搭建:全局安装vue/cli与npm install -g dcloudio/uni-cli,通过uni -V验证版本(需≥3.0)。多端编译命令: # 编译微…...

python:机器学习(KNN算法)
本文目录: 一、K-近邻算法思想二、KNN的应用方式( 一)分类流程(二)回归流程 三、API介绍(一)分类预测操作(二)回归预测操作 四、距离度量方法(一)…...
CSS--background-repeat详解
属性介绍 background-repeat 属性在CSS中用于控制背景图像是否以及如何重复。当背景图像的尺寸小于其容器的尺寸时,该属性决定了图像如何填充额外的空间。默认情况下,背景图像会在横向和纵向上重复,直到覆盖整个元素。 常见取值 repeat …...
WHAT - 学习 WebSocket 实时 Web 开发
文章目录 一、基础知识了解1. WebSocket 是什么?2. 它的优势: 二、基本工作流程三、快速体验:使用原生 WebSocket客户端(浏览器端 JS):服务端(Node.js 示例,使用 ws 库) …...

代码随想录第43天:图论4(最小生成树、拓扑排序)
一、冗余的边II(Kamacoder 109) from collections import defaultdict# 并查集 - 查找根节点(路径压缩) def find(fa, x):if fa[x] ! x:fa[x] find(fa, fa[x])return fa[x]# 并查集 - 合并两个集合,返回是否合并成功 …...