扩展:锁优化---全局锁介绍及案例分析

全局锁 Global Read lock
a. 介绍
全局读锁。
加锁方法: FTWRL,flush tables with read lock. (flush tables:把当前系统当中已经打开的表关掉)
表关掉之后,加上锁,阻塞所有事务的提交commit
解锁方法: unlock tables;

FTWRL出现场景:
mysqldump --master-data
xtrabackup(8.0之前早期版本)等备份时。
8.0之后:
属于类型: MDL(matedatalock)层面锁
影响情况: 加锁期间,阻塞所有事务写入,阻塞所有已有事务commit。
MDL,等待时间受 lock_wait_timeout=31536000

场景: 业务反馈所有写入做不了.查询的相关
mysql> show processlist;
mysql> select * from performance_schema.metadata_locks\G
mysql> select * from sys.schema_table_lock_waits;

一个经典故障:5.7 xtrabackup/mysqldump备份时数据库出现hang状态,所有修改查询都不能进行

session1: 模拟一个大的查询或事务
mysql> select id,sleep(100)  from city where id<100  for update ;

session2: 模拟备份时的FTWRL 
mysql> flush tables with read lock;
-- 此时发现命令被阻塞

session3: 发起查询,发现被阻塞
mysql> select * from world.city where id=500 for update;

解决问题的步骤:   

1.查看进程的详细信息
show processlist;

2.查看MDL锁信息
select * from performance_schema.metadata_locks\G

查看  PENDING 被阻塞    GRANTED 阻塞者的owner_therad_ID号
penging:   61 63 64   
GRANTED:   62

3.# 通过SQL线程号找到 SQL语句,分析语句是谁堵塞了谁
select * from performance_schema.events_statements_history;(历史上运行的)   

select * from performance_schema.events_statements_current;(正在运行的)
PENDING:
61:SQL_TEXT: flush tables with read lock
63:SQL_TEXT: select * from world.city where id=1 for update
64:SQL_TEXT: insert into student values(1,'asan')
GRANTED:
62:SQL_TEXT: select id,sleep(100)  from city where id<100  for update(模拟执行了个大事务)

4.查看源头GRANTED:62能不能停(通过therad_ID找到processlist_Id)   找到是哪个用户或人员相连接做的操作,对相关人员询问

mysql>select * from performance_schema.threads where thread_id=62\G
             THREAD_ID: 62
               NAME: thread/sql/one_connection
               TYPE: FOREGROUND
     PROCESSLIST_ID: 22
   PROCESSLIST_USER: root
   PROCESSLIST_HOST: localhost
     PROCESSLIST_DB: world
PROCESSLIST_COMMAND: Query
   PROCESSLIST_TIME: 2130
  PROCESSLIST_STATE: User sleep
   PROCESSLIST_INFO: select id,sleep(100)  from city where id<100  for update
   PARENT_THREAD_ID: NULL
               ROLE: NULL
       INSTRUMENTED: YES
            HISTORY: YES
    CONNECTION_TYPE: Socket
       THREAD_OS_ID: 3098
     RESOURCE_GROUP: USR_default
1 row in set (0.00 sec)

5.如果要立即解决问题,让项目跑起来,通过找到备份(THREAD_ID为61)的连接线程PROCESSLIST_ID为21
mysql> select * from performance_schema.threads where thread_id=61\G
*************************** 1. row ***************************
          THREAD_ID: 61
               NAME: thread/sql/one_connection
               TYPE: FOREGROUND
     PROCESSLIST_ID: 21
   PROCESSLIST_USER: root
   PROCESSLIST_HOST: localhost
     PROCESSLIST_DB: NULL
PROCESSLIST_COMMAND: Query
   PROCESSLIST_TIME: 2581
  PROCESSLIST_STATE: Waiting for global read lock
   PROCESSLIST_INFO: flush tables with read lock
   PARENT_THREAD_ID: 1
               ROLE: NULL
       INSTRUMENTED: YES
            HISTORY: YES
    CONNECTION_TYPE: Socket
       THREAD_OS_ID: 6362
     RESOURCE_GROUP: USR_default
1 row in set (0.00 sec)

6.杀掉进程21

结论: 备份时,一定要选择业务不繁忙期间,否则有可能会阻塞正常业务。

案例2: 
5.7版本  innobackupex备份全库,进程死了,mysql里就是全库读锁,后边insert 全阻塞了
解决步骤和案例1类似

猜你喜欢

转载自blog.csdn.net/xiaoleinb/article/details/112398662
今日推荐