《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 安装并启动 ...
随机推荐
- CF891C Envy【最小生成树】
题目链接 我们知道,根据Kruskal的贪心,对于最小生成树,每一种权值的边数是一样的,而且如果将\(\leq x\)的边做最小生成树,合法方案的联通性是一样的.所以我们可以对于所有边分开考虑. 对于 ...
- Mac 下 安装 Nginx
---恢复内容开始--- Mac 下 安装nginx 首先确定自己有安装homebrew 安装 nginx brew install nginx 启动nginx 1.15版本下 安装是 直接在ngin ...
- vue中封装一个倒计时
<template> <div class="countDownBox"> <div class="row resetStyle" ...
- ROS文件系统级
ROS的安装就不介绍了,官方教程是最好的:点击打开链接 ROS是机器人操作系统,它应该有自己的工程结构,Linux系统的文件系统如下: 而ROS的文件系统级如下: 接下来逐一介绍它们: 1. catk ...
- liunx系统下crontab定时启动Scrapy爬虫程序
定时启动爬虫 # 查看命令得绝对路径 # which scrapy # cd到爬虫得项目目录下 + scrapy命令得绝对路径 + 启动命令 */5 * * * * cd /opt/mafengwo/ ...
- scanf和fgets比较
scanf 长度限制 #include<stdio.h> int main() { char food[5]; printf("Enter food"); scanf( ...
- CSAW Quals CTF 2017-scv
目录 程序基本信息 程序漏洞 整体思路 exp脚本 内容参考 程序基本信息 64位动态链接程序,开启了栈溢出和数据段不可执行保护 程序漏洞 read函数很明显的栈溢出漏洞 整体思路 由于题目给了lib ...
- 性能测试工具gperftools使用
https://blog.csdn.net/10km/article/details/83820080 https://blog.51cto.com/wulingdong/2043898 https: ...
- Linux中强大的top命令
top命令算是最直观.好用的查看服务器负载的命令了.它实时动态刷新显示服务器状态信息,且可以通过交互式命令自定义显示内容,非常强大. 在终端中输入top,回车后会显示如下内容: top - 21: ...
- Linux如何使用shell命令检测PHP木马防止脚本木马的破坏
1.一句话查找PHP木马 代码如下 # find / -name "*.php" |xargs egrep "phpspy|c99sh|milw0rm|eval\(gun ...