6.更新行时候的行锁

2019-01-18  本文已影响0人  胖达_4b7e

行锁在引擎层由各个引擎自己实现的,MyISAM 引擎就不支持行锁

调整语句顺序,使某行锁时间尽量短


事务B 的更新操作会被阻塞, 直到事务A提交,
事务A依次得到了id为1,2 共2行的锁, 提交后才释放 ,
如果事务A的2条更新语句反一下, 先锁id=2 再锁id=1 ,那么id=1这行被锁住的时间就会短一些

如下一个事务:
1.从顾客 A 账户余额中扣除电影票价;

2.给影院 B 的账户余额增加这张电影票价;

3.记录一条交易日志。

如果同时有另外一个顾客 C 要在影院 B 买票,那么这两个事务冲突的部分就是语句 2 了, 都要改影院B,需要影院B这行被锁的时间尽量短, 需要把语句2尽量靠后,如312 ,132

死锁

事务A:有第一行,等第二行
事务B:有第二行,等第一行

办法
1.innodb_lock_wait_timeout 设最大等待时间, 但是不好把握到达设多少时长
2.死锁检测:一般是用这个, innodb_deadlock_detect 的默认值本身就是 on。主动死锁检测在发生死锁的时候,是能够快速发现并进行处理的

死锁检测的负担

每当一个事务被锁(进入堵塞)的时候,就要看看它所依赖的线程(有我等待的那行锁的事务)有没有被别人锁住,如此循环,判断是否出现了循环等待(死锁)

如:
事务A得到第一行的锁, 堵塞在等待第二行的锁, 发现第二行的锁是被事务B拥有, 接着检查事务B有没有也在阻塞着等某行的锁, 发现事务B在等第一行的锁, 循环等待了

所有事务都要更新同一行的场景:
每个新来的被堵住的线程,都要判断会不会由于自己的加入导致了死锁(已经堵住的其他事务的线程,有没有需要新来的已有的锁的),这是一个时间复杂度是 O(n) 的操作。
假设有 1000 个并发线程要同时更新同一行,那么死锁检测操作就是 100 万这个量级的。虽然最终检测的结果是没有死锁,但是这期间要消耗大量的 CPU 资源。因此,你就会看到 CPU 利用率很高,但是每秒却执行不了几个事务。

解决方法

  1. 能确保这个业务一定不会出现死锁,可以临时把死锁检测关掉。

  2. 控制并发度。根据上面的分析,比如同一行同时最多只有 10 个线程在更新,那么死锁检测的成本很低,就不会出现这个问题。
    一个直接的想法就是,在客户端做并发控制。但是,你会很快发现这个方法不太可行,因为客户端很多。我见过一个应用,有 600 个客户端,这样即使每个客户端控制到只有 5 个并发线程,汇总到数据库服务端以后,峰值并发数也可能要达到 3000。
    并发控制要做在数据库服务端。如果你有中间件,可以考虑在中间件实现

  3. 将一行改成逻辑上的多行来减少锁冲突。

上一篇下一篇

猜你喜欢

热点阅读