《Mysql 锁 - 概述》
一:锁类型(加锁范围区分类型)
- MySQL里面的锁可以分为:全局锁、表级锁、行级锁。
二:全局锁
- 作用
- 对整个数据库实例加锁。
- 加锁方式
- MySQL提供加全局读锁的方法:Flush tables with read lock(FTWRL)
- 这个命令可以使整个库处于只读状态。
- 使用该命令之后,数据更新语句、数据定义语句和更新类事务的提交语句等操作都会被阻塞。
- 使用场景
- 全库逻辑备份。(加锁的目的是为了在备份时候 保证数据视图的一致性)
- 风险(指的使用全局锁风险)
- 如果在主库备份,在备份期间不能更新,业务暂停。
- 如果在从库备份,备份期间不能执行主库同步的binlog,导致主从延迟。
- 其他方法(可以代替全局锁的方法)
- 官方自带的逻辑备份工具mysqldump
- 当mysqldump使用参数--single-transaction的时候,会启动一个事务,确保拿到一致性视图。
- 而由于MVCC的支持,这个过程中数据是可以正常更新的。
- 一致性读是好,但是前提是引擎要支持这个隔离级别。
- 如果要全库只读,为什么不使用set global readonly=true的方式?
- 在有些系统中,readonly的值会被用来做其他逻辑,比如判断主备库。所以修改global变量的方式影响太大。
- 在异常处理机制上有差异。如果执行FTWRL命令之后由于客户端发生异常断开,那么MySQL会自动释放这个全局锁,整个库回到可以正常更新的状态
- 而将整个库设置为readonly之后,如果客户端发生异常,则数据库就会一直保持readonly状态,这样会导致整个库长时间处于不可写状态,风险较高。
三:表级锁
- MySQL里面表级锁有两种
- 表锁(lock table)
- 元数据锁(meta data lock,MDL)
- 表锁
- 作用
- 防止 DDL 之间的冲突
- 加锁方式
- lock tables ... read/write
- 可以用unlock tables主动释放锁,也可以在客户端断开的时候自动释放。
- 注意
- lock tables 语法除了会限制别的线程的读写外,也限定了本线程接下来的操作对象。
- 例如:线程 A 执行了 lock tables t1 read, t2 write;
- 则其他线程写 t1、读写 t2 的语句都会被阻塞。
- 同时,线程 A 在执行 unlock tables 之前,也只能执行读 t1、读写 t2 的操作。
- 连写 t1 都不允许,自然也不能访问其他表。
- 元数据锁(MDL)
- 作用
- MDL作用是防止DDL和DML并发的冲突。
- 加锁方式
- 不需要显式使用,在访问一个表的时候会被自动加上。
- 在对一个表做增删改查操作的时候,加MDL读锁。(可并发读)
- 当要对表做结构变更操作的时候,加MDL写锁。(堵塞读写)
- 可能产生的问题
- 以下面的事务举例子
-
- 分析一下上面事务可能产生的问题
- session A 先启动,这时候会对表 t 加一个 MDL 读锁。
- session B 需要的也是 MDL 读锁,因此可以正常执行。
- session C 会被 blocked(阻塞),是因为 session A 的 MDL 读锁还没有释放,而 session C 需要 MDL 写锁,因此只能被阻塞。
- 问题
- 如果只有 session C 自己被阻塞还没什么关系,但是之后所有要在表 t 上新申请 MDL 读锁的请求也会被 session C 阻塞。
- 因为 DML 的特性,所有对表的增删改查操作都需要先申请 MDL 读锁,就都被锁住,等于这个表现在完全不可读写了。
- 如果某个表上的查询语句频繁,而且客户端有重试机制,也就是说超时后会再起一个新 session 再请求的话,这个库的线程很快就会爆满。
- 原因
- 事务中的 MDL 锁,在语句执行开始时申请,但是语句结束后并不会马上释放,而会等到整个事务提交后再释放。
- 解决热点更新表的字段添加问题?(知道 MDL 可能产生的问题,我们要尝试解决在热点表添加字段,同时避免 MDL 锁的问题)
- 应当尽量避免在业务高峰时,执行 DDL 语句
- 解决长事务 (事务不提交,就会一直占着 MDL 锁。)
- 在 MySQL 的 information_schema 库的 innodb_trx 表中,你可以查到当前执行中的事务。
- 如果你要做 DDL 变更的表刚好有长事务在执行,要考虑先暂停 DDL,或者 kill 掉这个长事务。
- 但是如果是热点表,请求频繁,而不得不加字段
- 这时候 kill 可能未必管用,因为新的请求马上就来了。
- 比较理想的机制是,在 alter table 语句里面设定等待时间,如果在这个指定的等待时间里面能够拿到 MDL 写锁最好,拿不到也不要阻塞后面的业务语句,先放弃。
- 之后开发人员或者 DBA 再通过重试命令重复这个过程。
四:行级锁
- 行级锁
- 是在各个 存储引擎里自己实现的。
- 两阶段锁的概念是什么? 对事务使用有什么帮助?
- 概念
- 在 InnoDB 事务中,行锁是在需要的时候才加上的(一段)。
- 但并不是不需要了就立刻释放, 而是要等到事务结束时才释放(二段)。
- 帮助
- 数据视图的一致性,保证隔离性。
- 死锁的概念是什么? 举例说明出现死锁的情况.
- 概念
- 事务 A 和事务 B 在互相等待对方的资源释放,就是进入了死锁状态。
- 死锁(A/B 事务相互等待)
A 事务 B 事务
update A = (A 加锁)
update B = (B 加锁)
update B = (等待B事务释放锁)
update A = (等待A事务释放锁)
死锁
- 死锁的处理策略?
- 死锁等待
- 当事务遇到死锁时候,会一直等待,直到超时。
- 参数 innodb_lock_wait_timeout 设置死锁等待时间(InnoDB默认是50s)。
- 死锁检测
- 当发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。
- 将参数 innodb_deadlock_detect 设置为 on,表示开启这个逻辑(默认是开启状态)。
- 等待超时处理死锁的机制什么?有什么局限?
- 机制
- 出现死锁后,事务双方相互等待,直到有一个事务超时,另一个事务获得锁,继续执行。
- 局限
- 业务中出现大量的超时事务,而等待锁的过程中也会导致业务等待。
- 死锁检测处理死锁的机制是什么? 有什么局限?
- 机制
- 每当一个事务被锁的时候。就要看看它所依赖的线程有没有被别人锁住,如此循环,最后判断是否出现了循环等待,也就是死锁。
- 局限
- 每个新来的被堵住的线程,都要判断会不会由于自己的加入导致了死锁,这是一个时间复杂度是 O(n) 的操作。
- 假设有 1000 个并发线程要同时更新同一行,那么死锁检测操作就是 100 万这个量级的。
- 虽然最终检测的结果是没有死锁,但是这期间要消耗大量的 CPU 资源。因此,你就会看到 CPU 利用率很高,但是每秒却执行不了几个事务。
- 有哪些思路可以解决热点更新导致的并发问题?(知道了死锁的机制处理之后)
- 如果你能确保这个业务一定不会出现死锁,可以临时把死锁检测关闭掉。
- 可能产生大量的超时事务,一般不建议采用
- 控制并发
- 根据上面的分析,你会发现如果并发能够控制住,比如同一行同时最多只有 10 个线程在更新,那么死锁检测的成本很低,就不会出现这个问题。
- 通过中间件或者其他方式,控制并发度,对应相同行的更新,在进入引擎之前排队。这样在InnoDB内部就不会有大量的死锁检测工作了。
- 业务拆分
- 比如把账单的一条数据,拆分成10条,最后求和。更新时候,选择一条进行操作。
- 这样可以减少锁冲突,并发度也会提高,但是业务复杂度可能会大大提高。
《Mysql 锁 - 概述》的更多相关文章
- 简单物联网:外网访问内网路由器下树莓派Flask服务器
最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...
- 利用ssh反向代理以及autossh实现从外网连接内网服务器
前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...
- 外网访问内网Docker容器
外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...
- 外网访问内网SpringBoot
外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...
- 外网访问内网Elasticsearch WEB
外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...
- 怎样从外网访问内网Rails
外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...
- 怎样从外网访问内网Memcached数据库
外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...
- 怎样从外网访问内网CouchDB数据库
外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...
- 怎样从外网访问内网DB2数据库
外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...
- 怎样从外网访问内网OpenLDAP数据库
外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...
随机推荐
- 贾扬清牛人(zz)
贾扬清加入阿里巴巴后,能否诞生出他的第三个世界级杰作? 文 / 华商韬略 张凌云 本文转载,著作权归原作者所有 贾扬清加入阿里巴巴后,能否诞生出他的第三个世界级杰作? 2017年1月11日,美国 ...
- elasticsearch update方法报错: Too many dynamic script compilations within, max: [75/5m]
PUT _cluster/settings { "transient" : { "script.max_compilations ...
- Why use swap when there is more than enough RAM.
Swappiness is a property of the Linux kernel that changes the balance between swapping out runtime m ...
- java一周学习回顾
快速阅读 本周在学习java过程中主要是快马观花,对java的常用框架进行相关配置 ,进行简单的调用 .包括kafka,dubbo ,zookeeper.centos配置java环境.如何打war ...
- spring boot + vue 前后分离实现登录功能(二)
安装 axios 进行路由转发 npm install axios --save-dev 或者 cnpm install axios --save-dev 修改 Main.js 新增 var axio ...
- [软工]Github的使用
注册 修改个人信息 fork项目 使用github客户端 commit项目 发送PR 注意事项 不要使用上述项目进行试验 建议Github用户名有规律,好记忆
- libmidas.so.2
libmidas.so.2 libmidas.so.2文件,使DATASNAP FOR LINUX中间件,支持OleVariant格式的序列,使TDataSetProvider+TClientData ...
- .prop() vs .attr()
.prop() vs .attr() Update 1 November 2012 My original answer applies specifically to jQuery 1.6. My ...
- jQuery Ajax calls and the Html.AntiForgeryToken()
jQuery Ajax calls and the Html.AntiForgeryToken() https://stackoverflow.com/a/4074289/3782855 I use ...
- Java设计模式: 单例模式
1.需要传递参数: public class Singleton{ private volatile static Singleton instance = null; private int val ...