【Mysql】FLUSH TABLES WITH READ LOCK


1. 对于myisam存储引擎,从数据库外部拷贝.frm,.fyd,.fyi文件后,执行FLUSH TABLES/FLUSH TABLES WITH READ LOCK后,就可以使用新表了,这个开发云主机域名功能非常有用,备份变得格外简单
2. mysqldump中从主库中拉出一个副本后通过change master后就可以快速搭建slave,为了获得一个一致性点,一般会使用参数–single-transaction和–master-data,它会使用FLUSH TABLES WITH READ LOCK阻塞事务commit写binlog来获得transaction开始时主库binlog位置
3. 与FLUSH TABLES相似,清空table_cache

除了这几个重要作用外,目前还没有发现其他用处,而且对于InnoDB存储引擎,第一条就没用了

1. 后面多了 WITH READ LOCK使得这两个SQL命令差很大,FLUSH TABLES WITH READ LOCK会在global read lock上加S锁,这会导致整个系统变得只读
2. FLUSH TABLES WITH READ LOCK后必须显示执行UNLOCK TABLES,否则整个系统会一直处于只读状态,这个问题非常隐晦,因为FLUSH TABLES WITH READ LOCK完成后在“show processlist”中无法被观察到,除非这个session自己执行unlock tables或者拥有root权限用户kill这个session,重复一次:FLUSH TABLES WITH READ LOCK后一定要UNLOCK TABLES,除非你想让系统只读!
3. FLUSH TABLES在以上三点都被用到,对于1和3很好理解,2中怎么会用到呢?查看mysqldump.c的代码及注释:

解释很清楚:FLUSH TABLES WITH READ LOCK开始后整个系统就是read only状态了,为了使影响最小,先使用FLUSH TABLES “尝试一次”,假设在FLUSH TABLES和FLUSH TABLES WITH READ LOCK之间存在DML/DDL的可能性较小,FLUSH TABLES WITH READ LOCK执行时间会很短,若不幸一个大DML/DDL正好在这之间发生了,事情就会变得很糟糕了:FLUSH TABLES WITH READ LOCK需要等待DML/DDL执行完,之后开启的DML/DDL需要等待FLUSH TABLES WITH READ LOCK对应的UNLOCK TABLES被执行

实现分三步:(函数:reload_acl_and_cache)

注:
1. 对于任何DDL/DML,会首先申请MDL_INTENTION_EXCLUSIVE类型的global read lock:
–> mdl_request.init(MDL_key::GLOBAL, “”, “”,MDL_INTENTION_EXCLUSIVE, MDL_EXPLICIT); 然后申请对应表上的相应元数据
2. 对于任何DDL/DML,提交时会申请MDL_INTENTION_EXCLUSIVE类型的global commit lock:
–> mdl_request.init(MDL_key::COMMIT, “”, “”,MDL_INTENTION_EXCLUSIVE, MDL_EXPLICIT);(代码见:ha_commit_trans)
3. select操作不会申请任何类型的global read lock或者global commit lock

因此FLUSH TABLES WITH READ LOCK的三个步骤中:
1 会等待DDL/DML结束后才会开始,并且一旦开始后,整个系统变成只读
2 这个步骤可能很长,因为会等待所有的表被关闭,如果系统中有大查询,会一直等待…
3 会阻塞系统中已经开始的事务提交,从而保证binlog不增长,通过show master status就可以获取当前的binlog file和binglog pos

lock_global_read_lock被两处调用:reload_acl_and_cache 和 fix_read_only,fix_read_only做的事情和FLUSH TABLES WITH READ LOCK基本一样,lock_global_read_lock(同样的,MDL_SHARED类型的global read lock)–>close_cached_tables–>make_global_read_lock_block_commit,除此之外,设置全局变量read_only=1,由于它们在global read lock上加的都是MDL_SHARED锁,因此这两个命令是兼容的,只是set global read_only=1后,如果有DML会报错:the mysql server is running with the read-only option

线上出现了一个问题,根据show processlist发现:
1. 所有的DML都无法执行,session状态为:Waiting for global read lock
2. set global read_only=1阻塞, session状态为:Waiting for table flush
出现1说明global read lock被某个session获取了或者被某个session等待,比如以下场景:

系统中的global read lock被其它线程获取了(被加上了S锁),因此DML在grl上面加IX锁时会出现Waiting for global read lock,而set read_only在grl上加的是S锁,因此此时是可以grant的,而此时系统中存在大查询,set global read_only=1需要等待表被关闭,因此状态是:Waiting for table flush

因此原因可以确定了:系统中存在flush tables with read lock但是没有unlock tables

在手动做FLUSH TABLES WITH READ LOCK/set global read_only=1之前,先执行一下FLUSH TABLES,能够很大概率地减小系统变成只读的时间

参考:http://blog.csdn.net/zbszhangbosen/article/details/7434173

相关推荐: mysql索引的创建和和删除

索引的创建可以在CREATE TABLE语句中进行,也可以单独用CREATE INDEX或ALTER TABLE来给表增加索引。删除索引可以利用ALTER TABLE或DROP INDEX语句来实现。(1)使用ALTER TABLE语句创建索引。语法如下:al…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

(0)
打赏 微信扫一扫 微信扫一扫
上一篇 06/05 19:58
下一篇 06/05 19:58

相关推荐