行锁功过:怎么减少行锁对性能的影响?


行锁就是针对数据表中行记录的锁。这很好理解,比如事务 A 更新了一行,而这时候事务 B 也要更新同一行,则必须等事务 A 的操作完成后才能进行更新。

两阶段锁协议

  • 在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议
  • 如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。

死锁

  • 当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态。
    死锁

死锁解决方案

  • 通过参数 innodb_lock_wait_timeout 根据实际业务场景来设置超时时间,InnoDB 引擎默认值是 50s。
    • 如果设置过长被锁住的线程要等待很长时间才会退出,设置超时时间如果过短又会出现误伤,所以一般会采用第二种策略。
  • 主动死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数 innodb_deadlock_detect 设置为 on,表示开启这个逻辑(默认是开启状态)。
    • 但它也是有额外负担的,可以想象一下这个过程:每当一个事务被锁的时候,就要看看它所依赖的线程有没有被别人锁住,如此循环,最后判断是否出现了循环等待,也就是死锁。

如何解决热点行更新导致的性能问题?

  • 如果你能确保这个业务一定不会出现死锁,可以临时把死锁检测关闭掉,但一般不建议这么做。
  • 控制并发度,对应相同行的更新,在进入引擎之前排队,这样在 InnoDB 内部就不会有大量的死锁检测工作了。
    • 一个直接的想法就是,在客户端做并发控制。但是,你会很快发现这个方法不太可行,因为客户端很多。我见过一个应用,有 600 个客户端,这样即使每个客户端控制到只有 5 个并发线程,汇总到数据库服务端以后,峰值并发数也可能要达到 3000。
    • 因此,这个并发控制要做在数据库服务端。如果你有中间件,可以考虑在中间件实现;如果你的团队有能修改 MySQL 源码的人,也可以做在 MySQL 里面。基本思路就是,对于相同行的更新,在进入引擎之前排队。这样在 InnoDB 内部就不会有大量的死锁检测工作了。
  • 将热更新的行数据拆分成逻辑上的多行来减少锁冲突,但是业务复杂度可能会大大提高。
  • InnoDB 行级锁是通过锁索引记录实现的,如果更新的列没建索引是会锁住整个表的。

问题总结

  • 两阶段锁的概念是什么?对事务使用有什么帮助?
  • 死锁的概念是什么?举例说明出现死锁的情况。
  • 死锁的处理策略有哪两种?
  • 等待超时处理死锁的机制是什么?有什么局限?
  • 死锁检测处理死锁的机制是什么?有什么局限?
  • 有哪些思路可以解决热点更新导致的并发问题?

笔记来源于《极客时间:MySQL实战45讲:行锁功过:怎么减少行锁对性能的影响?》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

✦昨夜星辰✦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值