SpringBoot Seata 死锁问题排查
现象描述:Spring Boot项目,启动的时候卡住了,一直卡在那里不动,没有报错,也没有日志输出

但是,奇怪的是,本地可以正常启动

好吧,姑且先不深究为什么本地可以启动而部署到服务器上就无法启动的问题,这个不是重点,重点是怎么让它启动起来。(PS:我猜测可能是环境不同造成的,包括操作系统不同和JDK版本不同)
遇到这种情况,我先用jstack查看堆栈情况,果然发现了死锁

拿到jstack的完整信息,然后仔细排查,看不懂的话也可以借助工具


分析了每个被阻塞的线程之后,发现main线程和timeoutChecker_1_1互相等待对方持有的锁,从而形成了死锁
可以通过 jconsole 和 jvisualvm 查看

需要注意,如果是查看远程进程,则需要加一些启动参数
- -Dcom.sun.management.jmxremote:启用JMX
- -Dcom.sun.management.jmxremote.port=<端口号>:指定JMX远程连接的端口号
- -Dcom.sun.management.jmxremote.authenticate=false:禁用JMX远程连接的认证
- -Dcom.sun.management.jmxremote.ssl=false:禁用JMX远程连接的SSL加密
于是,我又重启启动
java -jar -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9099 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false app.jar
通过jps或者ps命令查找应用的pid





用jvisualvm查看也可以,不再赘述,结果都是一样的


好了,工具介绍到此为止,下面重点看代码

main线程持有<0x00000000c07a33d8>这个对象的锁,同时它还需要<0x00000000ff295ca8>对象的锁,而timeoutChecker_1_1线程正好相反,于是死锁了
main线程很好理解,就是我们这个SpringBoot应用的主线程,但是timeoutChecker_1_1线程是哪儿来的呢,通过分析发现它来自Seata
对了,该项目中Spring Boot版本是2.6.6,Seata版本是1.4.2
找到timeoutChecker的出处了



延迟60秒启动定时任务,每隔10秒执行一次,调用io.seata.core.rpc.netty.NettyClientChannelManager#reconnect()


记住这一行,首先调用RegistryFactory.getInstance()获取一个RegistryService,然后调用RegistryService对象的lookup()方法


接着看1.4.2

最重要的是 EnhancedServiceLoader.load(ExtConfigurationProvider.class).provide(configuration);

所以,ExtConfigurationProvider 是 SpringBootConfigurationProvider



回到seata-1.4.2,可以看到这里调用了applicationContext.getBean(),于是DefaultListableBeanFactory.getBean()





可以看到,getSingletonFactoryBeanForTypeCheck()方法里,对singletonObjects加了同步锁
凡是通过DefaultSingletonBeanRegistry#getSingleton()获取单例Bean的都会先对singletonObjects加锁
接下来看lookup


可以看到,NacosRegistryServiceImpl的lookup()这里也加了锁。另外,getNamingProperties()的时候由于再次用到了ConfigurationFactory.CURRENT_FILE_INSTANCE,所以又到了SpringBootConfigurationProvider#provide()
至此,Seata整个定时任务启动的主要逻辑我们都梳理完了,几处加锁的也都找到了

这些加锁的地方也就是容易出现死锁的地方
死锁是由于加锁顺序不一致造成的
下面看main线程启动
由于SeataDataSourceBeanPostProcessor实现了BeanPostProcessor接口,所以在创建容器之后会回调其postProcessAfterInitialization()方法









所以,最终还是调NettyClientChannelManager#reconnect()

Spring启动的时候去创建Spring容器,后面就是Spring那一套
ConfigurableApplicationContext#refresh()
ServletWebServerApplicationContext#refresh()

不再赘述
由于需要注入依赖,所以,这个过程中肯定会多次调用 AbstractBeanFactory.getBean()
前面我们讲过,DefaultSingletonBeanRegistry.getSingleton() 时是加了锁的。因此,main线程很有可能会先持有该锁,当初始化到Seata的时候,又要获取该锁,于是出现了锁争用。

由于两个线程对同一资源的加锁顺序不一致,导致死锁。
由于timeoutChecker是定时任务每隔10秒启一次,所以第二次加锁顺序变成231
好了,关于main线程和timeoutChecker线程死锁的分析就先到这里了
现在,回到项目中来,由于我们的项目中有一个比较耗时的操作,超时时间固定是60秒,这个方法本来应该在Seata代理数据源之后做,不知道为什么服务器上先执行了,导致main线程等待了60秒,之后才执行SeataDataSourceBeanPostProcessor#postProcessAfterInitialization()

最终解决方法时将@PostConstruct注解去掉,不在容器初始化的时候取做这么耗时的操作
如果采用Seata-1.5.2版本的话,可能也不会出现死锁问题
相关文章:
SpringBoot Seata 死锁问题排查
现象描述:Spring Boot项目,启动的时候卡住了,一直卡在那里不动,没有报错,也没有日志输出 但是,奇怪的是,本地可以正常启动 好吧,姑且先不深究为什么本地可以启动而部署到服务器上就无…...
文章解读与仿真程序复现思路——电力系统自动化EI\CSCD\北大核心《考虑两阶段鲁棒优化配置的多微网合作博弈》
这个标题涉及到多个概念,让我们逐步解读: 考虑两阶段鲁棒优化配置: 两阶段: 指的是在解决问题或进行优化时,可能存在两个不同的阶段或步骤。这表明问题的解决不是一步完成的,而是需要经过多个步骤或阶段。鲁…...
Redis常见类型
常用类型String字符串类型Hash字典类型List列表类型Set集合类型ZSet有序集合类型 Java程序操作Redis类型代码操作Redis 常用类型 String字符串类型 使用方式: 使用场景: Hash字典类型 字典类型(Hash) 又被成为散列类型或者是哈希表类型࿰…...
深入了解数据库锁:类型、应用和最佳实践
目录 1. 引言 2. 数据库锁的基本概念 2.1 悲观锁和乐观锁 2.2 排他锁和共享锁 3. 悲观锁的应用场景 3.1 长事务和大事务 3.2 并发修改 3.3 数据库死锁 4. 悲观锁的最佳实践 4.1 精细控制锁的粒度 4.2 避免死锁 4.3 考虑乐观锁 5. 案例分析 5.1 银行系统的转账操作…...
python3.5安装教程及环境配置,python3.7.2安装与配置
大家好,小编来为大家解答以下问题,python3.5安装教程及环境配置,python3.7.2安装与配置,现在让我们一起来看看吧! python 从爬虫开始(一) Python 简介 首先简介一下Python和爬虫的关系与概念&am…...
ubuntu安装tomcat并配置前端项目
1.1查找 # 先更新 sudo apt update # 查找 apt search jdk1.2安装 sudo apt install openjdk-8-jdk1.3验证 java -version 2.安装tomcat 下载链接:Apache Tomcat - Apache Tomcat 8 Software Downloadshttps://tomcat.apache.org/download-80.cgi下载这个&…...
GeoPandas初体验:它是什么,我用它展示一下shp矢量数据
GeoPandas 是一个开源的 Python 库,用于处理地理空间数据。它扩展了 Pandas 这个流行的 Python 数据操作库,增加了对地理数据类型和操作的支持。GeoPandas 结合了 Pandas、Matplotlib 和 Shapely 的功能,提供了一个易于使用且高效的工具&…...
Python-滑雪大冒险【附源码】
滑雪大冒险 《滑雪大冒险》是一款充满趣味性和挑战性的休闲竞技游戏,在游戏中,玩家将扮演一位勇敢的滑雪者,在雪山上展示他们的滑雪技巧,游戏采用2D图形界面,以第三人称视角呈现 运行效果:用方向键及方向键…...
Linux---日志管理
本章主要介绍Linux中的日志管理 了解rsyslog是如何管理日志的查看日志的方法 日志管理简介 工作当中的日志,特指硬件和软件的日志,管理员可以通过它来检查错误发生的原因,或者寻找受到攻击时攻击者留下的痕迹。日志管理包括管理系统日志、应…...
Java高级技术-单元测试
单元测试 Junit单元测试框架 Junit单元测试-快速入门 方法类 测试类 Junit框架的基本注解...
springboot集成邮箱验证功能
准备工作 开启SMTP服务 前往你的邮箱网站,以网易邮箱为例,打开网易邮箱地址,登录你的邮箱,进入邮箱管理后台界面。点击“设置”》》“POP3/SMTP/IMAP”后,点击开启SMTP服务即可。 技术实现 Spring Boot 发送邮件验证…...
HarmonyOS应用程序框架——UIAbility实操
UIAbility概述 UIAbility是一种包含用户界面的应用组件,主要用于和用户进行交互。UIAbility也是系统调度的单元,为应用提供窗口在其中绘制界面。 每一个UIAbility实例,都对应于一个最近任务列表中的任务。 一个应用可以有一个UIAbility&…...
数实融合!低代码推动工业数字化转型走“深”向“实”
当下,“数字化、智能化”已经不再是新鲜词。毕竟,在早几年前就已经有企业喊出大举进军数字化的口号,轰轰烈烈的数字化转型运动也持续了很长一段时间,有一些业内人士甚至判断“如今的企业数字化已经走过了成熟期,来到了…...
OpenGL学习资料
1.学习网站 Song Ho Ahn LearnOpenGL GAMES101:现代计算机图形学入门 OpenGL 官网 2.书籍 Fundamentals of computer graphics OpenGL ES 3.0编程指南 计算机图形学(OpenGL版)第3版 3.参考的一些文章 颜色缓冲区 深度缓冲 VBO,VAO和EBO详解 深入探索透视投影变…...
字符串指令集
字符串指令的格式 例子1就成功发送了指令 例子2就是发送的字符串有误 查询当前位置就会在附加信息中返回当前座位的坐标 第一个指令的参数就是闪灯的两个参数 如第一个示例就是10ms On Time 第二个就是Off Time 使用标准库来接收字符串命令 字符串指令的接收 因为一个指令就是…...
行云海CMS SQL注入漏洞复现
0x01 产品简介 行云海cms是完全开源的一套CMS内容管理系统,简洁,易用,安全,稳定,免费。 0x02 漏洞概述 行云海cms中ThinkPHP在处理order by排序时可利用key构造SQL语句进行注入,LtController.class.php中发现传入了orderby未进行过滤导致sql注入。攻击者除了可以利用 SQL 注入…...
窗口函数之 first_value() 和 last_value()
这次,我要从**last_value()**开始写! last_value() 众所周知,first_value() 和 last_value() 的作用是返回窗口中某个字段的第一行的值和最后一行的值。 但是在应用的时候,突然发现使用last_value() 返回了不止一条数据&#x…...
习题练习讲解
前言:这又是一个新坑,算上之前的4个坑这是第五个坑(1、C/C的讲解,2、C语言小游戏,3、大学生活,4、假哲家因为某些原因没GS),这个就是发一些自己在刷题的过程中遇到自己感觉还不错的习…...
C++STL的string模拟实现
文章目录 前言string的成员变量成员函数构造函数拷贝构造赋值重载 模拟实现string各种接口print迭代器普通迭代器const迭代器 string比较大小push_backinsert 和 eraseinserterase reserve和resizereserveresize swapfindcout和cincoutcin 前言 今天要讲string的底层实现&…...
基于ZLMediaKit的webrtc实时视频传输demo搭建
环境 ubuntu 20.04 gcc version 9.4.0 cmake version 3.16.3 部署ZLMediaKit流媒体服务器 安装openssl 首先可以检查一下自己的openssl的版本如果是1.1.1以上就可以忽略这一步 wget https://www.openssl.org/source/openssl-1.1.1k.tar.gz tar -xvzf openssl-1.1.1k…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...
vue3 daterange正则踩坑
<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...
【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道
文/法律实务观察组 在债务重组领域,专业机构的核心价值不仅在于减轻债务数字,更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明,合法债务优化需同步实现三重平衡: 法律刚性(债…...
实战设计模式之模板方法模式
概述 模板方法模式定义了一个操作中的算法骨架,并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。简单来说,就是在一个方法中定义了要执行的步骤顺序或算法框架,但允许子类…...
