复杂的故事简单说,复杂的问题简单做,您好,这里是简露一手,欢迎浏览。
简述
16-7月,一大型在线业务系统服务器突然一个个挂掉,重启后不到撑不到五分钟就牺牲,导致生产系统业务故障oracle锁
定位
因所有应用都有问题,且在未发布版本情况下突然发生,预备进行三个步骤排查定位。
检查数据库情况.
检查服务器日志.
检查服务器网络情况.
数据库情况
这里不说其它的检查项,直奔这次事因:“数据库锁”。
根据经验,我们进行了数据库锁的检查,幸运的是直接找到了问题点。
有一个业务表锁的数量超过100,根据sql_id找出了所有sql,发现了全表锁和锁全表语句,是一条更新全表的update语句。
查询锁:select object_name as 对象名称,s.sid,s.serial#,p.spid as 系统进程号,s.SQL_ID from v$locked_object l , dba_objects o , v$session s , v$process p where l.object_id=o.object_id and l.session_id=s.sid and s.paddr=p.addr;
查询锁表的语句:select * from v$sql where sql_id='65gmqgahz6jp8'
处理
锁一旦出现 ,最简单的办思路就是杀[kill]。
kill 分两种:
oracle 命令kill
ALTER SYSTEM KILL SESSION 'sid,serial#';
后台杀oracle语句kill
kill -9 spid
<small>sid,serial#,spid 取值于 查询锁查询结果。
开始杀
首杀
使用[oracle 命令]kill后 新的锁又多了起来,改用[后台杀]kill后,新的锁仍在继续。
再查
分析锁全部的update语句会话是oracle自己产生的,来源于存储过程的概率比较大,在排查存储过程中找到了它,并根据它找到了一个job,是job的重复执行 导致了全表锁的不断产生。
二杀
删除job后重新kill,第二次杀进程后,情况并没有好转,没有了全表锁,但是行锁仍然多,问题变得更为复杂。
再查
经过漫长的分析百种尝试,最终找到来问题.这是一个大意遗漏的点。生产机器一般做了rac,有多个实例,通过tns连接过去的会话一直在一个实例上,查看锁情况始终只查看了一个实例的锁情况,而oracle的job执行 在两个实例上都有可能存在。修改tns地址为第二个实例后,在第二个实例上找到了好几个全表锁的进程。
三杀
登陆到第二个实例上,kill掉锁的进程后1分钟不到,所有的锁都降下去了,重启应用,恢复正常。
总结
事情错综,所以总结一下为两点来将整体内容再简化一下。
因: 生产业务表在业务繁忙期间执行了全表更新语句,与应用上更新单条记录的进程形成循环锁、阻塞,导致整体应用和数据库问题。所以,生产业务表在业务繁忙期间应禁止执行全表更新语句。碰到必须在业务期间全表执行则需采用分批更新和提交,来减小冲突的产生概率,这里说的全表更新包括更新语句没有where条件和where条件的结果有大量数据的两种情况。
果: 找出所有锁,杀掉所有锁。需要注意的是:Job会不停产生更新任务。生产环境一般都做了rac,需检查数据库的多个实例,都进行kill。
实际上这次事故处理时间有点长,中间停起应用、分析日志这些都有做,还有迁移接口、排查代码这些,处理的内容也相当多。回想起来做的事情就一项是有用的:找到所有锁,然后kill。
作者:georgekaren
链接:https://www.jianshu.com/p/f84a6b7ef195
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。