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

MySQL的行锁时在引擎层有各个引擎自己实现的,但是并不是所有的引擎都支持行锁,比如MyISAM引擎就不支持行锁。不支持行锁意味着只能使用表锁。

InnoDB是支持行锁的,这也是MyISAM被InnoDB替代的重要原因之一。

两阶段锁

在InnoDB事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放,这就是两阶段锁协议。

对我们的帮助就是,如果事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。

死锁和死锁检测

出现死锁后有两种策略:

1、直接进入等待,直到超时。这个超时时间可以通过参数innodb_lock_wait_timeout来设置。

2、另一种策略是,发起死锁检测,发现死锁后主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数innodb_deadlock_detect设置为on,表示开启这个逻辑。

在InnoDB中,innodb_lock_wait_timeout的默认值是50s。一方面50s的等待时间往往是无法接受的,但是也不可能把这个值设置的很小,这样可能会影响到正常的事务,造成误伤。

所以正常情况下还是要采用第二种策略,即:主动检测死锁,但是也是有额外负担的(每当一个事务被锁的时候就要检测它锁依赖的线程有没有被别人锁住,如此循环)。  

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

在此就需要考虑一个问题:怎么解决有热点行的更新导致的性能问题?问题的关键在于死锁检测要耗费大量的CPU资源。

方法一:如果能确保这个业务一定不会出现死锁,可以临时把死锁检测关掉。有一定风险,业务本身不会把死锁当做一个严重的错误,是业务无损的;但是关掉,就可能会出现大量的超时,这是业务有损的。

方法二:控制并发思路。比如在客户端做并发控制,但是如果客户端很多的话,也不太可行。

可以考虑使用中间件实现,或者MySQL大神可以修改MySQL源码,对于相同的更新,在进入引擎之前排队。

还可以考虑将一行改成逻辑上的多行来减少锁冲突。比如一个账户字段可以分成多个字段,账户余额就是这多个字段的和。  业务以及代码要有特殊的处理。

上一篇:06 | 全局锁和表锁 :给表加个字段怎么有这么多阻碍?

下一篇:08 | 事务到底是隔离的还是不隔离的?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值