在日常开发或线上运维中,我们经常会遇到各种数据库异常,例如超时、死锁等。但有些问题,表面看似平常,背后却藏着意想不到的原因。

今天就分享一次由服务器时间跳跃引发的 MySQL 获取锁超时问题的排查过程。

问题现象:大量锁超时日志出现

某天系统日志中突然频繁出现如下报错信息:

Caused by: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

获取锁超时导致事务失败。

初步分析:死锁?

可能是出现死锁了,于是根据异常栈定位到问题代码,但发现该方法逻辑简单,仅修改一个entity,类似下面这样。(非真实业务代码)

// 仅更新用户的最后访问时间
user.setLastVisitTime(LocalDateTime.now());
userRepository.save(user);

强行分析(猜想),这个修改是每个请求都会改到的,由于在请求事务内,事务没提交就会一直锁着,直到请求完成。

但一个长期稳定运行的项目,请求不太可能突然变慢

深入排查:慢日志未出现异常

如果出现死锁,那么慢日志里面一定有记录。但实际排查袭来,慢日志并无User相关的慢查询。

蛛丝马迹:不太常见的日志

om.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Thread starvation or clock leap detected (housekeeper delta=1m26s857ms76µs413ns).

翻阅日志,发现一条clock leap detected的异常记录。于是验证服务器时间,发现比本地环境快了40多秒。

真相大白:服务器时间跳跃引发误判

MySQL进行锁等待和事务超时时,依赖系统时间戳进行判断。当系统时间突然跳跃到未来时间,导致MYSQL误判。

至于跳跃原因,推测是 NTP 客户端在检测到时间漂移后进行了强制同步(stepping)操作,瞬间将时间快进了几十秒。

更近一步:有哪些操作会导致获取锁超时?

在 MySQL 使用 InnoDB 引擎的前提下,锁超时Lock wait timeout exceeded)的出现通常有两个主要诱因:

1. 死锁(Deadlock)

最常见的原因就是死锁。死锁往往由于多个事务以不同顺序下修改相同资源,彼此持有对方需要的锁,造成互相等待、永远无法释放。

比如:

  • 事务 A 修改顺序是:先改用户,再改订单;

  • 事务 B 修改顺序是:先改订单,再改用户;

  • 双方各自持有一个锁,又想获取对方的,结果就死锁了。

MySQL 会检测到死锁并主动中断其中一个事务。(这时候日志里就会出现Dealock报错了)

其实,只要在项目中统一规定 Entity 的修改顺序,大部分死锁是可以避免的。

2. 长事务导致的锁未及时释放

InnoDB 中,事务未提交期间会一直持有锁。如果事务执行时间过长,会导致其他并发请求长时间阻塞,最终抛出锁等待超时异常。

事务执行过长,常见原因包括:

  • Entity 修改过多

    比如循环中逐个修改并保存,每次都 save(),反复刷 SQL。

  • 事务中包含耗时操作

    例如调用外部服务、HTTP 接口、微服务 RPC 等,尤其是对慢接口没有超时控制时。

  • 事务中存在显式等待

    Thread.sleep() 用于调试、限速等场景,期间锁不会释放。

【杂谈】死锁?NO,时间跳跃!的更多相关文章

  1. 使用SQL Server 扩展事件来创建死锁的时间跟踪

    我们通过SQL Server 2012图形界面来部署一个扩展事件跟踪会话.然后可以生成SQL脚本,在2008或2008 R2版本下运行类似的跟踪. 步骤1: 通过“Object Explorer”连接 ...

  2. 【DP】【P5615】 [MtOI2019] 时间跳跃

    Description 给定 \(n\) 条边,第 \(i\) 条边的长度为 \(i\),每条边都有 \(50\%\) 的概率被选择,求如果选出的边能组成一个平面凸多边形,则方案的权值是方案中边的数量 ...

  3. DB2死锁的解决办法

    db2 get snapshot for locks on sampledb2 get db cfg for sampledb2 update db cfg using dlchktime 10000 ...

  4. 时间,闰秒,及NTP

    1.时间 格林尼治时间 GMT,以地球自转为准的时间,也叫世界时UT,但是由于自转速度会变化,所以后来不被作为标准. 世界协调时UTC,以原子钟为准,现在时间校准的标准就是原子钟. 2.闰秒 是指地球 ...

  5. 数据结构与算法(c++)——跳跃表(skip list)

    今天要介绍一个这样的数据结构: 单向链接 有序保存 支持添加.删除和检索操作 链表的元素查询接近线性时间 ——跳跃表 Skip List 一.普通链表 对于普通链接来说,越靠前的节点检索的时间花费越低 ...

  6. 基于innodb_print_all_deadlocks从errorlog中解析MySQL死锁日志

    本文是说明如何获取死锁日志记录的,不是说明如何解决死锁问题的. MySQL的死锁可以通过show engine innodb status;来查看,但是show engine innodb statu ...

  7. java和mysql之间的时间日期类型传递

    摘自:http://blog.csdn.net/weinianjie1/article/details/6310770 MySQL(版本:5.1.50)的时间日期类型如下: datetime 8byt ...

  8. 一次查找sqlserver死锁的经历

    查找bug是程序员的家常便饭,我身边的人喜欢让用户来重现问题.当然他们也会从正式服务器上下载错误log,然后尝试分析log,不过当错误不是那种不经思考就可识别的情况,他们就会将问题推向用户,甚至怪罪程 ...

  9. mysql和java的时间对应关系

    引用:http://blog.csdn.net/xinghuo0007/article/details/51500923 MySQL(版本:5.1.50)的时间日期类型如下: datetime 8by ...

  10. linux环境下的时间编程

    Linux下提供了丰富的api以供开发者们处理和时间相关的问题.然而这些接口看似各自为政实则有有着千丝万缕的联系,在学习和时间中引发了各种各样的混乱.因此时间处理成为了许多Linux开发者的梦魇,遇到 ...

随机推荐

  1. Codeforces Round 958 (Div. 2)

    题目链接:Codeforces Round 958 (Div. 2) 总结:C因为常数没转\(long long\) \(wa\)两发,难绷. A. Split the Multiset fag:模拟 ...

  2. 正确停止Oracle expdp/impdp作业操作方法

    1.使用命令查看在运行的作业名称,找到STATE是EXECUTING的作业名称. select job_name,state from dba_datapump_jobs; 2.再CMD命令窗口,键入 ...

  3. 云数据库MySQL多人协同开发实践

    本文分享自天翼云开发者社区<云数据库MySQL多人协同开发实践>,作者:不知不觉 随着云计算技术的快速发展,云数据库作为云计算的重要组成部分,为企业提供了高效.灵活和可靠的数据存储和管理服 ...

  4. Q:plsql中文显示??处理

    1.查询数据库字符集select userenv('language') from dual; 2.修改NLS_LANG环境变量:将NLS_LANG环境变量设置为正确的字符集 windows设置系统环 ...

  5. Linux驱动---按键

    目录 一.Input子系统 1.1.简介 1.2.Input子系统构成 1.3.input_dev结构体 二.输入设备驱动开发流程 2.1.分配和初始化输入设备 2.2.注册设备 2.3.事件上报 2 ...

  6. Drasi Reactions SDK

    Drasi Reactions SDK 是一个跨语言的开发工具包,用于实现和处理 Drasi 平台的 Reactions(反应器)功能.该 SDK 目前支持三种主流编程语言:JavaScript/Ty ...

  7. 天线的OTA测试

    有源测试 (即OTA测试) 把使用综测仪的测试叫做有源测试(Active).使用有源测试的测试速度比较无源相对要慢,但是因为手机是一个复杂材料体,往往无源测试对发射性能的模拟是可信的,但是对于接收性能 ...

  8. element-ui实现table表格的嵌套(table表格嵌套)功能实现

      最近在做电商类型的官网,希望实现的布局如下:有表头和表身,所以我首先想到的就是table表格组件. 表格组件中常见的就是:标题和内容一一对应:像效果图中的效果,只用基础的表格布局是不行的,因此我想 ...

  9. Github Copilot的使用方法和快捷键

    GitHub Copilot是一款由GitHub和OpenAI共同开发的代码智能补全工具,它使用机器学习模型来为你提供代码建议和自动完成,可以加快开发过程并提高代码质量.下面是使用GitHub Cop ...

  10. MySQL - [04] 分布式部署&主从复制&读写分离

    一.前言 Q1:为什么需要主从复制? 1.在业务复杂的系统中,有一条SQL语句需要锁表,导致暂时不能使用读的服务,那么就很影响运行中的业务.使用主从复制,让主库负责写,从库负责读,这样即使主库出现了锁 ...