xiaohanliang
Database
Database
  • review
  • MySQL
    • 0. 索引就是树吗
    • 1. 索引是怎么发挥作用的
    • 2. 聊聊怎么估时间
    • 3. 主键玄学
    • 4. 事务的执行过程@ACD
    • 5. MVCC就是用undolog回退
    • 6. 事务如何彼此隔离@I
    • 7. 如何人为的制造死锁
    • 8. 引擎是干什么的
    • 9. 主从复制怎么做到的
    • 10. 寻找同步起始点GTID
    • 11. 预解析Statement
  • Redis
    • 0. Hash@数据结构
    • 1. ZSet@数据结构
    • 2. 场景与玩法@数据结构
    • 3. 可能的风险点
    • 4. Redis的落盘
    • 5. 关于效率的讨论
    • 6. 主从模式@集群化
    • 7. [WIP]Proxy实现@集群化
    • 8. 标准玩法@集群化
  • KV/Distributed
    • 0. 面临的问题
    • 1.Raft@原理
    • 2. LSM@原理
    • 3. [WIP]分布式事务@原理
Powered by GitBook
On this page
  • 如何制造死锁
  • MySQL的锁

Was this helpful?

  1. MySQL

7. 如何人为的制造死锁

Previous6. 事务如何彼此隔离@INext8. 引擎是干什么的

Last updated 4 years ago

Was this helpful?

如何制造死锁

死锁是一种因为加锁而产生的冲突, 简单来说就是我持有资源A, 等你手上的资源B, 而你也在等我的资源A, 这样咱俩等于说就是在这里耗着了. 这种现象不一定出现在数据库上, 操作系统乃至任何包含锁设计的东西都可能会这种问题. 我们举个例子:

在上面的场景中 [事务A已经拿到了id=1的行锁, 等待id=2的行锁] [事务B拿到了id=2的行锁, 等待id=1的行锁]. 在这种情况下, 一个简单的死锁就被制造出来了.

这个问题的出现并不是一个非常刁钻的角度, 似乎也是轻轻松松就能被复现的, 如果这两条记录代表两个人, 俩人互相给对方转一块钱, 这个场景就能被立刻复现出来, 然后两个人就在这耗着了.

MySQL的锁

MySQL不是行锁, 而是任何锁都是存储引擎制造出来的, 因为MySQL的Server层只负责简单的解析并把查询语句传给引擎, 至于你怎么查, 用什么策略完成, 都是存储引擎这边负责的. 你比如MyISAM甚至就没有行锁, 它只有表锁, 可以说是古代人引擎了.

表锁/行锁会让你的查询hang在哪儿, 也许你现在美滋滋的在想自己表设计的多完美, 索引玩的多专业, 一个死锁就能让你的程序回到原点, 而且这一切说实话我觉得不太好预测, 你需要在脑海里模拟出业务发生时的场景, 而业务复杂度一上来就完全没法想象了.

MySQL的行锁会在需要的时刻被加上, 比如在你将更新id=1的时候才会为为id=1加上行锁, 但是释放也并不是用完立刻释放, 而是等事务结束了才会释放, 这个就是二段锁协议.那么死锁的原理你也知道了, 有什么办法处理呢?

  • 如果要一次性更新好几行, 把比较热点的, 争抢性比较高的尽量放在后面争抢性比较高的尽量放在后面, 这样你在拿到锁以后能尽量更快的释放.

  • 把热点行拆一拆, 比如商家账户余额这一栏显然就是热点区, 将商家余额拆成好几行, 随便插入哪一个都行, 最后商家余额就是这几行的和

  • 一个稍hacking的办法是在你的中间件里动手脚, 比如我们做一个proxy承接抢茅台的请求, 所有到访请求会进入queue, 然后排队购买

  • 最后数据库本身也有死锁检测机制, 每次产生了锁等待, 数据库就会开始检测到底是谁抢占了这个锁, 而这个人又在等待什么, 由此展开死锁检测, 但是这种行为本身也是有负担的, 设想有1000个人秒杀, 进入锁等待, 那么1000个线程全都开始遍历, 时间复杂度是一百万