一次 select for update 的悲观锁使用引发的生产事故
1.事故描述
本月 8 日上午十点多,我们的基础应用发生生产事故。具体表象为系统出现假死无响应。
查看事发时间段的基础应用 error 日志,没发现明显异常。查看基础应用业务日志,银行结果处理的部分普遍很慢,大都在十分钟以上。
2.AWR 报告
向 DBA 要了一下那个时间段的 AWR 报告,发现以下三个地方有些异常:
2.1.CPU 利用率过高
如上图所示,CPU利用率:1883.25分钟DB时间/(16核心*119.45分钟采样时间段时间) = 98.54%,CPU 利用率过高。
2.2.行锁等待严重
如上图"Top 5 Timed Events"所示,行锁等待占用了 80% 的 CPU 时间,基本可以确定它就是造成本次生产事故的直接元凶。
所以我们直接跳到"Wait Events"排行榜:
这说明了什么?在本次 AWR 报告的 09:00:45 - 11:00:12 大约 119.45 分钟的时间里,行锁等待的时间为 99974 秒,合 1666.23 分钟!
2.3.悲观锁慢查询严重
那么是什么操作造成行锁等待如此之严重呢?如此严重的行锁等待,慢查询统计列表里应该很突出地指示出来,我们直接跳到"SQL ordered by Elapsed Time"慢查询排行榜:
果不其然,两个小时的时间内,id 为 3x0hq0nmj6a93 的那条 sql 查询耗时 93158 秒(合 1552.63 分钟),平均每条执行时间为 306.44 秒(合 5.11 分钟),占用了 80% 以上的的 CPU。
让我们来看看这条 sql 的真面目吧:
select ORD_BILLNO, ORD_PRDCODE, ORD_CRCODE, ORD_MERBILLNO, ORD_PRETIME, ORD_DOTIME, ORD_MERTIME, ORD_MERCODEFROM, ORD_TYPEFROM, ORD_MERCODETO, ORD_TYPETO, ORD_ACCCODEFROM, ORD_ACCCODETO, ORD_AMT, ORD_STATUS, ORD_ATTACH, ORD_UPDATETIME, ORD_PRODUCT, ORD_REFUNDED, ORD_REFUSE, ORD_PREIP, ORD_ENDIP, ORD_BILLEXPTIME, ORD_DIRECTLY, ORD_SYSCODE, ORD_BRCCODE, ORD_SRCCODE, ORD_PAYEDAMT, TRD_CODE, RESV1, RESV2, RESV3, ORD_PRDCODE_OLD, TRD_CODE_OLD, ORD_USERACCTYPE from T_PSFP_ORDER_TMP where ORD_BILLNO = :1 for update
这是一条 select for update 数据库悲观锁查询语句,因为指定订单号,所以会锁定 T_PSFP_ORDER_TMP 表的某一条语句,印证了 2.2 中的结论。
3.代码分析
调用上述 sql 的代码:
Order tempOrder = orderTempDao.selectOrderByPrimaryKeyForUpdate(verifyResult.getBillNo());
该业务代码先拿到该临时交易的锁,然后继续处理后续相当繁琐业务逻辑,中间还有大量的其它数据库操作,因为是声明式事务处理,所以在整个业务逻辑执行结束之后才会 commit,这段时间内如果还有其它 session 想拿这个行锁,就必须等到这一系列业务逻辑执行完毕。
正常情况下,这个逻辑是没问题的,但是在高并发的时候,这些业务逻辑受到 CPU 及网络等资源的限制可能会被拖慢,业务逻辑处理慢倒没什么,可怕的是数据库被拖慢,反过来又影响这些业务逻辑,形成一个滚雪球的效应,直至系统故障。
4.解决方案
技术中心不允许使用 select for update 悲观锁,尤其是在大量业务逻辑的情况下,至于原有业务逻辑可以使用其他处理方案进行替代。如必需使用 select for update,须与架构部讨论后才可使用。
最后,关于Oracle AWR 报告的生成和分析请参考博客《Oracle AWR 报告的生成和分析》。
一次 select for update 的悲观锁使用引发的生产事故的更多相关文章
- mysql 多列唯一索引在事务中select for update是不是行锁?
在表中有这么一索引 UNIQUE KEY `customer_id` (`customer_id`,`item_id`,`ref_id`) 问1. 这种多列唯一索引在事务中select for upd ...
- Insert into select语句引发的生产事故
前言 Insert into select请慎用.这天xxx接到一个需求,需要将表A的数据迁移到表B中去做一个备份.本想通过程序先查询查出来然后批量插入.但xxx觉得这样有点慢,需要耗费大量的网络 ...
- Mysql锁机制--乐观锁 & 悲观锁
Mysql 系列文章主页 =============== 从 这篇 文章中,我们知道 Mysql 并发事务会引起更新丢失问题,解决办法是锁.所以本文将对锁(乐观锁.悲观锁)进行分析. 第一部分 悲观锁 ...
- [MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE
一.译文 翻译来自官方文档:Locking Reads If you query data and then insert or update related data within the same ...
- SQL Server 锁机制 悲观锁 乐观锁 实测解析
先引入一些概念,直接Copy其他Blogs中的,我就不单独写了. 一.为什么会有锁 多个用户同时对数据库的并发操作时会带来以下数据不一致的问题: 1.丢失更新 A,B两个用户读同一数据并进行修改,其中 ...
- Spring Boot 整合 MyBatis 实现乐观锁和悲观锁
本文以转账操作为例,实现并测试乐观锁和悲观锁. 完整代码:https://github.com/imcloudfloating/Lock_Demo GitHub Page:http://blog.cl ...
- MySQL学习之——锁(行锁、表锁、页锁、乐观锁、悲观锁等)
转载. https://blog.csdn.net/mysteryhaohao/article/details/51669741 锁,在现实生活中是为我们想要隐藏于外界所使用的一种工具.在计算机中,是 ...
- MySQL锁(行锁、表锁、页锁、乐观锁、悲观锁等)
锁,在现实生活中是为我们想要隐藏于外界所使用的一种工具.在计算机中,是协调多个进程或县城并发访问某一资源的一种机制.在数据库当中,除了传统的计算资源(CPU.RAM.I/O等等)的争用之外,数据也是一 ...
- MySQL中锁详解(行锁、表锁、页锁、悲观锁、乐观锁等)
原文地址:http://blog.csdn.net/mysteryhaohao/article/details/51669741 锁,在现实生活中是为我们想要隐藏于外界所使用的一种工具.在计算机中,是 ...
随机推荐
- PAT 甲级 1036 Boys vs Girls(20)
https://pintia.cn/problem-sets/994805342720868352/problems/994805453203030016 This time you are aske ...
- 怎么设置table(表格)手机端自适应宽度
我们在wordpress文章页面经常会用到表格,有些是从其他网页或者文档复制粘贴过来的,在电脑设备网页上都能很好的展示,但是在移动设备上或者低分辨率设备上却经常撑破列宽,很是影响美观和客户体验.这里就 ...
- Android 实现异步加载图片
麦洛开通博客以来,有一段时间没有更新博文了.主要是麦洛这段时间因项目开发实在太忙了.今天周六还在公司加班,苦逼程序猿都是这样生活的. 今天在做项目的时候,有一个实现异步加载图片的功能,虽然比较简单但还 ...
- Linux中安装apache
一.前言 安装的背景就是公司项目要用,自己在linux安装软件不多,过程比较曲折,需要记录一下(最近几篇博客好像都会有这种高大上的背景)~先说下笔者安装环境以及相关软件版本: 操作系统:RedHat ...
- 【题解】[USACO12JAN]视频游戏的连击Video Game Combos
好久没有写博客了,好惭愧啊……虽然这是一道弱题但还是写一下吧. 这道题目的思路应该说是很容易形成:字符串+最大值?自然联想到学过的AC自动机与DP.对于给定的字符串建立出AC自动机,dp状态dp[i] ...
- 【BZOJ 3144】 [Hnoi2013]切糕 真·最小割
一开始一脸懵逼后来发现,他不就是割吗,我们只要满足条件就割就行了,于是我们把他连了P*Q*R条边,然而我们要怎样限制D呢?我们只要满足对于任意相邻的两条路,只要其有个口大于D就不行就好了因此我们只要把 ...
- [COGS 2421] [HZOI 2016] 简单的Treap 笛卡尔树
笛卡尔树就是你给两维限制,一维堆R,一维二叉搜索树K,平地拔起一棵Treap,最广范的应用:用LCA求区间最值,建Treap,还有个什么范围top k我表示并不会查都查不到.它最妙最高的地方在于用栈来 ...
- Android-使用ViewFlipper实现轮番切换广告栏
所谓的轮番切换广告栏,指的是下面这个东西,笔主不知道该怎么确切描述这货... 笔主没有百度研究过其他大牛是怎么实现这个功能的,在这里笔主充分发挥DIY精神,利用ViewFlipper闭门土制了一个,下 ...
- springboot中 后端跨域的实现配置
在springboot的启动文件中,添加此内容,可以允许跨域
- c#中数据库字符串的连接几种方式
ADO.net 中数据库连接方式(微软提供) 微软提供了以下四种数据库连接方式:System.Data.OleDb.OleDbConnectionSystem.Data.SqlClient.SqlCo ...