Backup Locks
Percona Server在5.6.16-64.0中实现了这一功能,以作为用于物理和逻辑备份的FLUSH TABLES WITH READ LOCK
的轻量级替代。现在有三个新的语句可供使用:LOCK TABLES FOR BACKUP
, LOCKBINLOG FOR BACKUP
and UNLOCK BINLOG
.
Flush Tables with read lock
Closes all open tables and locks all tables for all databases with a global read lock. This is a very convenient way to get backups if you have a file system such as Veritas or ZFS that can take snapshots in time. Use UNLOCK TABLES to release the lock.
LOCK TABLES FOR BACKUP
LOCK TABLES FOR BACKUP
使用新的MDL锁类型来阻止更新非事务表和所有表的和DDL语句. 更具体地说,如果有一个活动的LOCK TABLES FOR BACKUP锁,所有DDL语句以及对MyISAM,CSV,MEMORY和ARCHIVE表的所有更新将被阻止,并在PERFORMANCE_SCHEMA或PROCESSLIST以Waiting for backup lock
的状态显示. 针对所有表的SELECT查询和针对InnoDB,Blackhole和Federated表的INSERT / REPLACE / UPDATE / DELETE不受LOCK TABLES FOR BACKUP
的影响。Blackhole表显然与备份无关,并且Federated表被逻辑和物理备份工具忽略。
与FLUSH TABLES WITH READ LOCK
不同,LOCK TABLES FOR BACKUP
不会刷新表,即存储引擎不会强制关闭表,并且表不会从表缓存中排出. 因此,LOCK TABLES FOR BACKUP
仅等待冲突的语句完成(即DDL和更新到非事务性表)。例如,它从不等待SELECT或更新InnoDB表来完成。
如果在持有LOCK TABLES FOR BACKUP锁的同一连接中执行“不安全”语句,则会失败,并显示以下错误:
ERROR 1880 (HY000): Can't execute the query because you have a conflicting backup lock
UNLOCK TABLES releases the lock acquired by LOCK TABLES FOR BACKUP.
个人理解这个锁的目的是为了避免mysqldump与innobackupex备份过程知多少(三)中的坑2. 也就是使用mysqldump备份innodb表时, 使用start transaction with consistent snapshot语句显式开启一个事务之后,该事务执行select之前,该表被其他会话执行了DDL之后无法查询数据
A会话
root@localhost 10:52: [test1]> show create table fan;
+-------+------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+------------------------------------------------------------------------------------------+
| fan | CREATE TABLE `fan` (
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |
+-------+------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
root@localhost 10:52: [test1]> START TRANSACTION /*!40100 WITH CONSISTENT SNAPSHOT */;
Query OK, 0 rows affected (0.00 sec)
B会话 指定DDL加一列
root@localhost 10:53: [test1]> alter table fan add col1 varchar(10);
Query OK, 0 rows affected (0.34 sec)
Records: 0 Duplicates: 0 Warnings: 0
A会在 查询失败
root@localhost 10:52: [test1]> select * from fan;
ERROR 1412 (HY000): Table definition has changed, please retry transaction
如果非Percona版本使用mysqldump备份时发生这种情况, 那么会导致fan表备份中没数据
根据 mysqldump与innobackupex备份过程知多少(完结篇)中所说
innobackupex在备份事务表时,是没有对数据库加锁的,so..这个时候,其实DDL是允许执行的,innobackupex持续在备份innodb事务表期间,如果被执行DDL的表是在innobackupex备份完成之后发起,那么在下一次scan lsn的时候innobackupex将发现DDL更改,报错终止,如果是在备份非事务表期间发起的DDL,那么将被FLUSH TABLE WITH READ LOCK语句阻塞。所以,对于使用innobackupex备份的生产环境,要执行DDL语句,也需要避开备份时间
可以看出在非Percona版本使用innobackupex备份时发生这种情况不会出现数据不一致的问题,但是可能会导致备份失败,要重跑备份
LOCK BINLOG FOR BACKUP
LOCK BINLOG FOR BACKUP
使用另一种新的MDL锁定类型来阻止所有可能会更改二进制日志位置或Exec_Master_Log_Po
或Exec_Gtid_Set
的操作(即主库日志坐标对应于从库上的当前SQL线程状态i.e. master binary log coordinates corresponding to the current SQL thread state on a replication slave),如SHOW MASTER / SLAVE状态。更具体地说,如果启用二进制日志(全局和与启用sql_log_bin的连接),或者,如果提交被由从线程执行和将推进Exec_Master_Log_Pos
或Executed_Gtid_Set
,则只会阻止提交。在全局二进制日志锁定上当前被阻止的连接可以通过PROCESSLIST中的Waiting for binlog lock
状态来识别。
从Percona Server 5.6.26-74.0开始用于备份的LOCK TABLES FOR BACKUP
将当前的二进制日志坐标刷新到InnoDB。因此,在活动的LOCK TABLES FOR BACKUP
下,InnoDB中的二进制日志坐标与其重做日志和任何非事务更新(因为后者被LOCK TABLES FOR BACKUP阻止)一致。据计划,这种改变将使Percona XtraBackup在某些情况下避免发布更具侵入性的LOCK BINLOG FOR BACKUP命令。
innobackupex
innobackupex --defaults-file=/data/mysqldata/3307/my.cnf --user=root --password="" --socket=/data/mysqldata/3307/mysql.sock --databases="test1" .
Oracle
2018-04-27T12:45:35.635689+08:00 15888 Query SET SESSION lock_wait_timeout=31536000
2018-04-27T12:45:35.635943+08:00 15888 Query FLUSH NO_WRITE_TO_BINLOG TABLES
2018-04-27T12:45:35.694930+08:00 15888 Query FLUSH TABLES WITH READ LOCK
2018-04-27T12:45:35.751889+08:00 15888 Query SHOW MASTER STATUS
2018-04-27T12:45:35.909818+08:00 15888 Query SHOW VARIABLES
2018-04-27T12:45:35.928558+08:00 15888 Query FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS
2018-04-27T12:45:36.147720+08:00 15888 Query UNLOCK TABLES
2018-04-27T12:45:36.211938+08:00 15888 Query SELECT UUID()
2018-04-27T12:45:36.212329+08:00 15888 Query SELECT VERSION()
======
innobackupex --defaults-file=/data/mysqldata/3306/my.cnf --user=root --password="" --socket=/data/mysqldata/3306/mysql.sock --databases="test1" .
Percona
2018-04-27T12:50:30.506501+08:00 9816 Query SET SESSION lock_wait_timeout=31536000
2018-04-27T12:50:30.506795+08:00 9816 Query LOCK TABLES FOR BACKUP
2018-04-27T12:50:30.716122+08:00 9816 Query LOCK BINLOG FOR BACKUP
2018-04-27T12:50:30.716250+08:00 9816 Query SHOW MASTER STATUS
2018-04-27T12:50:30.716453+08:00 9816 Query SHOW VARIABLES
2018-04-27T12:50:30.724478+08:00 9816 Query FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS
2018-04-27T12:50:30.933091+08:00 9816 Query UNLOCK BINLOG
2018-04-27T12:50:30.933255+08:00 9816 Query UNLOCK TABLES
2018-04-27T12:50:30.964040+08:00 9816 Query SELECT UUID()
2018-04-27T12:50:30.964217+08:00 9816 Query SELECT VERSION()
mydumper
mydumper --user=root --password="" --socket=/data/mysqldata/3307/mysql.sock --database=test1 -o . --verbose=3
Oracle
2018-04-27T13:14:47.487252+08:00 15889 Connect root@localhost on test1 using Socket
2018-04-27T13:14:47.489782+08:00 15889 Query SET SESSION wait_timeout = 2147483
2018-04-27T13:14:47.489938+08:00 15889 Query SET SESSION net_write_timeout = 2147483
2018-04-27T13:14:47.492580+08:00 15889 Query SHOW PROCESSLIST
2018-04-27T13:14:47.492723+08:00 15889 Query FLUSH TABLES WITH READ LOCK
2018-04-27T13:14:47.492886+08:00 15889 Query START TRANSACTION /*!40108 WITH CONSISTENT SNAPSHOT */
2018-04-27T13:14:47.493005+08:00 15889 Query /*!40101 SET NAMES binary*/
2018-04-27T13:14:47.555917+08:00 15889 Query SHOW MASTER STATUS
2018-04-27T13:14:47.556229+08:00 15889 Query SHOW SLAVE STATUS
======
mydumper --user=root --password="" --socket=/data/mysqldata/3306/mysql.sock --database=test1 -o . --verbose=3
Percona
2018-04-27T13:18:29.825869+08:00 9818 Connect root@localhost on test1 using Socket
2018-04-27T13:18:29.826214+08:00 9818 Query SET SESSION wait_timeout = 2147483
2018-04-27T13:18:29.826369+08:00 9818 Query SET SESSION net_write_timeout = 2147483
2018-04-27T13:18:29.826869+08:00 9818 Query SHOW PROCESSLIST
2018-04-27T13:18:29.827077+08:00 9818 Query SELECT @@have_backup_locks
2018-04-27T13:18:29.827284+08:00 9818 Query LOCK TABLES FOR BACKUP
2018-04-27T13:18:29.827923+08:00 9818 Query LOCK BINLOG FOR BACKUP
2018-04-27T13:18:29.828049+08:00 9818 Query SELECT @@tokudb_version
2018-04-27T13:18:29.828272+08:00 9818 Query CREATE TABLE IF NOT EXISTS mysql.tokudbdummy (a INT) ENGINE=TokuDB
2018-04-27T13:18:29.828412+08:00 9818 Query START TRANSACTION /*!40108 WITH CONSISTENT SNAPSHOT */
2018-04-27T13:18:29.828618+08:00 9818 Query SELECT /*!40001 SQL_NO_CACHE */ * FROM mysql.tokudbdummy
2018-04-27T13:18:29.829089+08:00 9818 Query /*!40101 SET NAMES binary*/
2018-04-27T13:18:29.829206+08:00 9818 Query SHOW MASTER STATUS
2018-04-27T13:18:29.829466+08:00 9818 Query SHOW SLAVE STATUS
Percona版本使用LOCK TABLES FOR BACKUP
和LOCK BINLOG FOR BACKUP
替换了FLUSH TABLES WITH READ LOCK
UNLOCK BINLOG
UNLOCK BINLOG
释放当前链接获取的LOCK BINLOG FOR BACKUP
锁. Percona XtraBackup的预期用例是:
LOCK TABLES FOR BACKUP
... copy .frm, MyISAM, CSV, etc. ...
LOCK BINLOG FOR BACKUP
UNLOCK TABLES
... get binlog coordinates ...
... wait for redo log copying to finish ...
UNLOCK BINLOG
权限
LOCK TABLES FOR BACKUP
和LOCK BINLOG FOR BACKUP
都需要RELOAD
权限.其原因是与FLUSH TABLES WITH READ LOCK具有相同的要求。
与其他全局锁的交互
如果当前连接已经拥有FLUSH TABLES WITH READ LOCK
锁,LOCK TABLES FOR BACKU
P和LOCK BINLOG FOR BACKUP
都不起作用,因为它(FTWRL)是一个更严格的锁。 如果FLUSH TABLES WITH READ LOCK
在已获取LOCK TABLES FOR BACKUP
或LOCK BINLOG FOR BACKU
P的连接中执行,则FLUSH TABLES WITH READ LOCK
将失败并显示错误。
如果服务器以只读模式运行(即read_only设置为1),则对于备份不安全的语句将被阻塞或失败,并显示错误,取决于它们是否在拥有LOCK TABLES FOR BACKUP锁的相同连接或其他连接中执行.
MyISAM索引和数据缓冲
MyISA key buffering is normally write-through,即每次更新MyISAM表完成时,所有索引更新都写入磁盘。唯一的例外是延迟键写入功能,该功能在默认情况下被禁用。
当全局系统变量delay_key_write
设置为ALL
时,所有MyISAM表的key buffers在更新是不会刷新数据到磁盘,因此这些表的物理备份可能会导致MyISAM索引损坏。为防止这种情况发生,如果delay_key_write设置为ALL,LOCK TABLES FOR BACKUP
将失败,并显示错误。当存在活动的备份锁时,尝试将delay_key_write设置为ALL也会失败并显示错误。
涉及延迟键写入的另一个选项是使用DELAY_KEY_WRITE
选项创建MyISAM表,并将delay_key_write
变量设置为ON
(这是默认值)。在这种情况下,LOCK TABLES FOR BACKUP
将无法防止陈旧的索引文件出现在备份中。我们鼓励用户在配置文件my.cnf中将delay_key_writes
设置为OFF
,或者在使用备份锁创建的物理备份恢复后修复MyISAM索引。
MyISAM也可以缓存批量插入的数据,例如当执行多行INSERT或LOAD DATA语句时。但是,这些高速缓存会在语句之间刷新,因此只要更新MyISAM表的所有语句都被阻止,就不会影响物理备份。
mysqldump
mysqldump
也因此被扩展出一个新的选项,lock-for-backup (默认禁用)。当与--single-transaction
选项一起使用时,该选项会使mysqldump在启动转储操作之前发出LOCK TABLES FOR BACKUP,以防止通常会导致不一致备份的不安全语句。(应该指的是不锁(non-innodb/非事务?)表)
如果在没有single-transaction
选项的情况下使用,则lock-for-backup
将自动转换为lock-all-tables
。
选项lock-for-backup
与lock-all-tables
是互斥的,即在命令行上同时指定两个参数会导致错误。
如果目标服务器不支持备份锁定功能,但在命令行上指定了lock-for-backup
,则mysqldump会中止并返回错误。
如果--master-data
和--single-transaction
一起使用,lock-for-backup
没有任何效果,即FLUSH TABLES WITH READ LOCK
仍然会用来获取二进制日志坐标。通过使用一致的快照功能实现开始事务,Percona Server 5.6.17-66.0中的此限制已被删除。https://www.percona.com/doc/percona-server/5.6/management/start_transaction_with_consistent_snapshot.html#start-transaction-with-consistent-snapshot
mydumper
if (!no_locks) {
// Percona Backup Locks
if(!no_backup_locks){
mysql_query(conn,"SELECT @@have_backup_locks");
MYSQL_RES *rest = mysql_store_result(conn);
if(rest != NULL && mysql_num_rows(rest)){
mysql_free_result(rest);
g_message("Using Percona Backup Locks");
have_backup_locks=1;
}
}
if(have_backup_locks){
if(mysql_query(conn, "LOCK TABLES FOR BACKUP")) {
g_critical("Couldn't acquire LOCK TABLES FOR BACKUP, snapshots will not be consistent: %s",mysql_error(conn));
errors++;
}
if(mysql_query(conn, "LOCK BINLOG FOR BACKUP")) {
g_critical("Couldn't acquire LOCK BINLOG FOR BACKUP, snapshots will not be consistent: %s",mysql_error(conn));
errors++;
}
可以看到mydumper会查看have_backup_locks
参数,并根据此参数觉得是否使用LOCK BINLOG FOR BACKUP