26 Matching Annotations
  1. Apr 2025
    1. 死锁检测以及相应开销

      由于事务之间可能产生死锁,因此要么设置最大等待超时时间,要么设置死锁检测。

      死锁检测

      1. 维护等待图(Wait-for Graph)

      InnoDB 内部维护一个有向图,图中的节点表示事务(Transaction),边表示锁的等待关系。

      例如:事务A持有行X的锁,事务B请求行X的锁并被阻塞,则图中有一条边从B指向A(B→A,表示B在等待A释放锁)。

      当某个事务请求锁时,如果锁已被其他事务持有,InnoDB 会更新等待图,添加一条新的边。

      2. 检测环(Cycle)

      每次有事务请求锁失败(进入等待状态)时,InnoDB 会触发死锁检测。

      深度优先搜索(DFS):InnoDB 通过DFS遍历等待图,检查是否存在环。如果发现环,则判定为死锁。

      优化:为了减少性能开销,InnoDB 不会每次都全图遍历,而是从新加入的边出发,仅检查可能形成环的路径。

      3. 选择牺牲者(Victim)

      如果检测到死锁,InnoDB 会选择一个事务作为牺牲者(通常选择回滚成本更低的事务,例如修改数据量较小的事务),强制回滚该事务,并释放其持有的锁。

      回滚后,等待图中对应的边被移除,其他被阻塞的事务可以继续执行。

      死锁的开销

      问题

      因此由于事务的不断加入,图会变得越来越大,进行环检测是O(n)的操作,若n很大则cpu大量消耗。

      解决

      可以通过中间件对操作相同key的事务限流,这样事务虽然也在等待,但是没有增加死锁检测的负担。

  2. Dec 2022
    1. 一个多线程程序的渐次瓦房店过程通常是这样的:开始,熟悉各种锁和内存栅的老手搭了易于维护的高性能架子出来,然后非熟练技工往上增加功能后无法解决神秘的死锁,只得把细粒度锁换成了对象锁,而最后接手的转码小工索性把对象锁全拆了改全局锁,然后破口大骂线程库:啥破玩意为什么只有一颗CPU在工作
  3. Aug 2022
    1. 在InnoDB事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议

      select ... for update是在读的时候加悲观锁