MySQL锁

  • Post author:
  • Post category:mysql




全局锁

全局锁是对整个数据库实例加锁,MySQL提供了一个加全局读锁的方法,命令是Flush tables with read lock(FTWRL)

业务的更新不只是增删改数据(DML),还有可能是加字段等修改表结构的操作(DDL)

全局锁的典型使用场景是,做全库逻辑备份

风险:

1、如果在在主库备份,备份期间不能更新,业务停摆

2、如果在从库备份,备份期间不能执行主库的binlog,导致主从延迟

官方自带的逻辑备份工具是mysqldump。当mysqldump使用-single-transaction的时候,导数据之前会启动一个事务,来确保拿到一致性视图。由于MVCC的支持,这个过程数据是可以更新的。(前提是引擎支持这个隔离级别)



表级锁

MySQL里的表级锁分为两种:1、表锁 2、元数据锁(meta data lock,MDL)

表锁的语法:lock tables …read/write

可以用unlock tables主动释放锁,也可以在客户端断开的时候自动释放。lock tables除了会限制别的线程的读写外,也限定了本线程接下来的操作对象

对于InnoDB这种支持行锁的引擎,一般不使用lock tables命令来支持并发,因为锁住整个表的影响面太大

MDL:不需要显示的使用,在访问一个表时会自动加上。

MDL的作用:保证读写的正确性

对一个表进行增删改查时,加MDL读锁;要对表结构做变更操作时,加MDL写锁

读锁之间不互斥,读写锁之间,写锁之间互斥,用来保证变更表结构的安全性。

MDL直到事务提交才会释放, 要小心不要导致锁住线上查询和更新。



行锁

MySQL 的行锁是在引擎层由各个引擎自己实现的( 不是所有的引擎都支持行锁,比如 MyISAM 引擎就不支持行锁)。

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

知道了这个设定,我们可以得出:

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

如果一个影院做活动,低价预售一年内所有的电影票,活动只做一天。于是在活动开始的时候,你的MySQL就挂了。你登上服务器一看,CPU消耗接近100%,但整个数据库每秒执行就执行不到100个事务。这是为什么?

这里涉及到死锁和死锁检测了



死锁和死锁检测

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

出现死锁后有

两种策略



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

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

在InnoDB中,innodb_lock_wait_timeout的默认值是50s,即采用第一种策略,死锁以后,第一个被锁住的线程要过50s才会超时退出,然后其他线程才能继续执行。对于在线服务来说,这个时间是无法忍受的。

但如果把这个时间设置的太短,如果不是死锁,只是简单的锁等待,就可能会造成误伤

所以,正常情况下采用第二种策略:主动死锁检测

能快速发现并处理死锁,但有额外的负担。

死锁检测是O(N)操作,如果有1000个并发线程同时更新同一行,那死锁检测就是100万这个量级。这就会导致CPU利用率很高,但每秒执行不了几个事务。

针对这个问题,有以下解决方案:

1、把死锁检测关闭;

可能会出现大量的超时,是业务有损的

2、控制并发度

修改MySQL源码,对相同的更新,在进入引擎之前排队,这样在InnoDB内部就不会有大量的死锁检测操作

3、将热更新的行数据拆分成逻辑上的多行来减少锁冲突,但是业务复杂度会大大提高



问题:

本文涉及的问题

1、两阶段锁的概念是什么? 对事务使用有什么帮助?

2、死锁的概念是什么? 举例说明出现死锁的情况

3、死锁的处理策略有哪两种?

4、等待超时处理死锁的机制什么?有什么局限?

5、死锁检测处理死锁的机制是什么? 有什么局限?

6、有哪些思路可以解决热点更新导致的并发问题?



版权声明:本文为weixin_45397953原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。