zoukankan      html  css  js  c++  java
  • 《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 = 1(A 加锁)
                                        update B = 1(B 加锁)
          update B = 2(等待B事务释放锁)
                                        update A = 2(等待A事务释放锁)
          死锁

      - 死锁的处理策略?

        - 死锁等待

          - 当事务遇到死锁时候,会一直等待,直到超时

          - 参数 innodb_lock_wait_timeout 设置死锁等待时间(InnoDB默认是50s)。

        - 死锁检测

          - 当发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。     

          - 将参数 innodb_deadlock_detect 设置为 on,表示开启这个逻辑(默认是开启状态)。

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

        - 机制

          - 出现死锁后,事务双方相互等待,直到有一个事务超时,另一个事务获得锁,继续执行。

        - 局限

          - 业务中出现大量的超时事务,而等待锁的过程中也会导致业务等待。

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

        - 机制

          - 每当一个事务被锁的时候。就要看看它所依赖的线程有没有被别人锁住,如此循环,最后判断是否出现了循环等待,也就是死锁。

        - 局限

          - 每个新来的被堵住的线程,都要判断会不会由于自己的加入导致了死锁,这是一个时间复杂度是 O(n) 的操作。

          - 假设有 1000 个并发线程要同时更新同一行,那么死锁检测操作就是 100 万这个量级的。

          - 虽然最终检测的结果是没有死锁,但是这期间要消耗大量的 CPU 资源。因此,你就会看到 CPU 利用率很高,但是每秒却执行不了几个事务。

      - 有哪些思路可以解决热点更新导致的并发问题?(知道了死锁的机制处理之后)

        - 如果你能确保这个业务一定不会出现死锁,可以临时把死锁检测关闭掉。

          - 可能产生大量的超时事务,一般不建议采用

        - 控制并发

          - 根据上面的分析,你会发现如果并发能够控制住比如同一行同时最多只有 10 个线程在更新,那么死锁检测的成本很低,就不会出现这个问题。

          - 通过中间件或者其他方式,控制并发度对应相同行的更新,在进入引擎之前排队。这样在InnoDB内部就不会有大量的死锁检测工作了。

        - 业务拆分

          - 比如把账单的一条数据,拆分成10条,最后求和。更新时候,选择一条进行操作。

          - 这样可以减少锁冲突,并发度也会提高,但是业务复杂度可能会大大提高

  • 相关阅读:
    nslookup查询结果详解
    【Web页面测试】测试点和测试用例
    【CloverETL培训】题目
    VirtualBox虚拟机网络设置(四种方式)
    Web系统测试Web安全性测试
    sqlserver字段类型详解
    详解SVN 的使用
    Javascript闭包——懂不懂由你,反正我是懂了
    Javascript的console.log()用法
    [ JS 进阶 ] test, exec, match, replace
  • 原文地址:https://www.cnblogs.com/25-lH/p/10954326.html
Copyright © 2011-2022 走看看