春节已过,开始收心,回归学习,努力成长。
两阶段锁
事务A
事务B
begin
update t set k=k+1 where id = 1
update t set k=k+1 where id = 2
begin
update t set k=k+2 where id = 1
commit
思考
如果事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。如果把并发度影响较高的语句放在前面的话,可能会造成事务之间锁等待的时间较长,从而影响并发度。所以要放在操作的最后,这样最大程度减少事务之间的锁等待,提升并发度。
死锁和死锁检测
事务A
事务B
begin
update t set k=k+1 where id = 1
begin
update t set k=k+1 where id = 2
update t set k=k+1 where id = 2
update t set k=k+1 where id = 1
出现死锁后,有两种策略:
第一种:进入等待,直至超时。这个超时时间可以通过参数 innodb_lock_wait_timeout 进行设置。
第二种:发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数innodb_deadlock_detect 设置为 on,表示开启这个逻辑。
思考
假设有1000个并发线程要同时更新同一行,那么死锁检测就是100量级的。为什么是100万量级呢?因为每一个都需要检测其他999个线程,整体消耗是O(N2)级别的。试想一下,单个线程加锁时的死锁检测时间是O(N),N个并发的死锁检测就是O(N2)。
并发更新同一行的1000个线程,整体耗费的死锁检测操作为1000*1000=100万。为什么是个乘法——并发更新此行R1的某单个线程Tx,其所作的死锁检测工作为,Tx会有查看锁持有情况,耗费1000此操作——a.查看自身持有的行锁; b.遍历其他999个线程所持有的行锁,总共为1+999=1000次。为什么会遍历其他999个线程,而不是仅看当前持有R1行锁的这个线程就行了?—— 因为行锁排队。某线程Tm排队获取R1行锁,排在Tx前。如果Tx当前持有行锁R2,过会Tm先于Tx获持R1后,会变成——Tm持有R1,等待R2 && Tx持有R2,等待R1——Tm和Tx成环死锁。因此并发更新同一行的有N个线程,对应的死锁检测耗费代价为O(N2) ! 死锁检测不可避免,为防止死锁检测代价过高引起性能问题——想办法减少同时对同一行的更新的并发并发度。即降低N值。
热点数据性能问题
1、如果能确保业务一定不会出现死锁,可以临时将死锁检测关闭。但是会带来一定的风险,因为业务设计的时候死锁并不是一个严重的错误,出现死锁了就进行回滚,通过业务重试一般就没问题了,对业务是无损的。关掉死锁检测可能导致大量超时,这是业务有损的
2、控制并发度,比如同一行同时最多只有 10 个线程在更新,那么死锁检测的成本很低,就不会出现这个问题。控制并发量不但可以减少死锁的概率,也可以减少死锁检测带来的性能消耗.
小结问题汇总
1、两阶段锁的概念是什么? 对事务使用有什么帮助?
2、死锁的概念是什么? 举例说明出现死锁的情况。
3、死锁的处理策略有哪几种?
4、等待超时处理死锁的机制什么?有什么局限?
5、死锁检测处理死锁的机制是什么? 有什么局限?
6、有哪些思路可以解决热点更新导致的并发问题?
最后,求关注。每天进步一点点,欢迎关注我的公众号「白砂」。
如果我的文章对你有所帮助,还请帮忙点赞、在看、转发一下,非常感谢!
点在看,让更多看见。