上周对测试环境的MySQL进行了一次迁移,学习了一些MySQL数据备份相关的知识。主要的操作步骤有4步,使用到了mysqldump、mysqlbinlog和binlog2sql这三个工具。
mysqldump -uroot -proot --lock-all-tables --flush-logs --databases test > /mysqlbackup/test_`date`.sql
--lock-all-tables:备份时为所有的表加锁
--flush-logs:备份前刷新日志
以下是mysqldump的常用操作
#导出所有数据库
mysqldump -uroot -proot --all-databases >/tmp/all.sql
#导出指定数据库
mysqldump -uroot -proot --databases db1 db2 >/tmp/user.sql
#导出一个数据库的指定表
mysqldump -uroot -proot --databases db1 --tables a1 a2 >/tmp/db1.sql
#条件导出,如果多个表条件相同可以一次导出多个表
mysqldump -uroot -proot --databases db1 --tables a1 --where='id=1' >/tmp/a1.sql
#只导出表结构, --no-data
mysqldump -uroot -proot --no-data --databases db1 >/tmp/db1.sql
#导出其他服务器上的数据
mysqldump --host=h1 -uroot -proot --databases db1 >/tmp/db1.sql
#将h1服务器中的db1数据库的所有数据导入到h2中的db2数据库中,db2的数据库必须存在否则会报错
mysqldump --host=h1 -uroot -proot --databases db1 |mysql --host=h2 -uroot -proot db2
修改my.cnf并且将以下参数加入其中,重启mysql实例
server-id=1 #由于bug,所以需要设置该参数.否则无法启动mysql实例
log-bin = mysql-bin #其中mysql-bin代表的是basename就是生成二进制日志文件的前缀部分,默认的位置在datadir目录下,也可以设置为其他的路径
mysql> show variables like '%log_bin%';
+---------------------------------+---------------------------------+
| Variable_name | Value |
+---------------------------------+---------------------------------+
| log_bin | ON |
| log_bin_basename | /opt/mysql/data/mysql-bin |
| log_bin_index | /opt/mysql/data/mysql-bin.index |
| log_bin_trust_function_creators | ON |
| log_bin_use_v1_row_events | OFF |
| sql_log_bin | ON |
+---------------------------------+---------------------------------+
log_bin:binlog开启
log_bin_basename:binlog文件的前缀
log_bin_index:该文件记录所有的binlog文件的地址
log_bin_trust_function_creators:默认值为False,只有置为true时,用户才可以创建或修改存储函数
log_bin_use_v1_row_events:控制binlog中Rows_log_event的格式,默认是OFF,即使用v2版本的格式
sql_log_bin:动态变量,可以全局设置也可以针对当前的会话,置为OFF时会关闭binlog
mysql> show variables like '%binlog%';
+-----------------------------------------+----------------------+
| Variable_name | Value |
+-----------------------------------------+----------------------+
| binlog_cache_size | 1048576 |
| binlog_checksum | CRC32 |
| binlog_direct_non_transactional_updates | OFF |
| binlog_error_action | IGNORE_ERROR |
| binlog_format | MIXED |
| binlog_gtid_simple_recovery | OFF |
| binlog_max_flush_queue_time | 0 |
| binlog_order_commits | ON |
| binlog_row_image | FULL |
| binlog_rows_query_log_events | OFF |
| binlog_stmt_cache_size | 32768 |
| binlogging_impossible_mode | IGNORE_ERROR |
| innodb_api_enable_binlog | OFF |
| innodb_locks_unsafe_for_binlog | OFF |
| max_binlog_cache_size | 18446744073709547520 |
| max_binlog_size | 524288000 |
| max_binlog_stmt_cache_size | 18446744073709547520 |
| simplified_binlog_gtid_recovery | OFF |
| sync_binlog | 0 |
+-----------------------------------------+----------------------+
binlog_cache_size:binlog使用的内存大小
binlog_format:格式
max_binlog_size:binlog的最大值,默认值为1GB
sync_binlog:事务提交后写到binlog文件,不强制刷新到磁盘。性能最好,但风险最高。一旦系统崩溃,在文件系统缓存中的所有Binlog信息都会丢失
binlog有三种格式:Statement、Row以及Mixed。
基于SQL语句的复制(statement-based replication,SBR),
基于行的复制(row-based replication,RBR),
混合模式复制(mixed-based replication,MBR)。
a. Statement
每一条会修改数据的sql都会记录在binlog中。
优点:不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能。
缺点:由于记录的只是执行语句,为了这些语句能在slave上正确运行,因此还必须记录每条语句在执行的时候的一些相关信息,以保证所有语句能在slave得到和在master端执行时候相同 的结果。另外mysql 的复制,像一些特定函数功能,slave可与master上要保持一致会有很多相关问题。
b. Row
5.1.5版本的MySQL才开始支持row level的复制,它不记录sql语句上下文相关信息,仅保存哪条记录被修改。
优点: binlog中可以不记录执行的sql语句的上下文相关的信息,仅需要记录那一条记录被修改成什么了。所以rowlevel的日志内容会非常清楚的记录下每一行数据修改的细节。而且不会出现某些特定情况下的存储过程,或function,以及trigger的调用和触发无法被正确复制的问题.
缺点:所有的执行的语句当记录到日志中的时候,都将以每行记录的修改来记录,这样可能会产生大量的日志内容。
c. Mixed
从5.1.8版本开始,MySQL提供了Mixed格式,实际上就是Statement与Row的结合。
在Mixed模式下,一般的语句修改使用statment格式保存binlog,如一些函数,statement无法完成主从复制的操作,则采用row格式保存binlog,MySQL会根据执行的每一条具体的sql语句来区分对待记录的日志形式,也就是在Statement和Row之间选择一种。
查看目前的binlog文件信息
mysql> show variables like 'binlog_format';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | MIXED |
+---------------+-------+
3.1 查看当前正在写入的binlog文件
mysql> show master status;
+------------------+-----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+-----------+--------------+------------------+-------------------+
| mysql-bin.000034 | 382465243 | | | |
+------------------+-----------+--------------+------------------+-------------------+
#当前正在写入的文件为mysql-bin.000034,位置为382465243
3.2 导出binlog
/opt/mysql/bin/mysqlbinlog --no-defaults --base64-output=decode-rows -v /opt/mysql/data/mysql-bin.000368 > /opt/dump_`date`.sql
默认情况下binlog日志是二进制格式,无法直接查看。
a. 使用show binlog events
#查看binlog文件内容
SHOW BINLOG EVENTS [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count]
1、查看一个二进制文件中的全部事务
注:binlog文件实际上是由一连串的event组成的一个组,即事务组。
mysql> show binlog events in 'mysql-bin.000001' \G;
*************************** 1. row ***************************
Log_name: mysql-bin.000001
Pos: 4
Event_type: Format_desc //事件类型
Server_id: 1
End_log_pos: 120 //结束pos点
Info: Server ver: 5.6.29-log, Binlog ver: 4
*************************** 2. row ***************************
Log_name: mysql-bin.000001
Pos: 120
Event_type: Rotate
Server_id: 1
End_log_pos: 167
Info: mysql-bin.000002;pos=4
2、对二进制文件做过滤查询
#从194节点开始,查找两条事务信息
mysql> SHOW BINLOG EVENTS IN 'mysql-bin.000005' FROM 194 LIMIT 2 \G;
*************************** 1. row ***************************
Log_name: mysql-bin.000005
Pos: 194
Event_type: Query
Server_id: 1
End_log_pos: 319
Info: use `tpcc`; UPDATE warehouse SET w_ytd = w_ytd + 3232 WHERE w_id = 1
*************************** 2. row ***************************
Log_name: mysql-bin.000005
Pos: 319
Event_type: Query
Server_id: 1
End_log_pos: 458
Info: use `tpcc`; UPDATE district SET d_ytd = d_ytd + 3232 WHERE d_w_id = 1 AND d_id = 3
2 rows in set (0.00 sec)
b.使用mysqlbinlog查看binlog
1、查看指定的binlog日志
shell> mysqlbinlog mysql-bin-000005
上述命令可以会报一些异常:
a.
ERROR: Error in Log_event::read_log_event(): ‘Sanity check failed’, data_len: 171, event_type: 30
这是当前环境变量下的mysqlbinlog的版本和当前MySQL的版本不一样导致的。加上全局路径就可以。
如:/opt/mysql/bin/mysqlbinlog mysql-bin-000005
b.
mysqlbinlog: unknown variable ‘default-character-set=utf8’
原因是mysqlbinlog这个工具无法识别binlog中的配置中的default-character-set=utf8这个指令。有两种方法可以解决:
一是my.cnf中将default-character-set=utf8 修改为 character-set-server = utf8,这需要重启MySQL
二是加上–no-defaults参数,如:mysqlbinlog --no-defaults mysql-bin.000004,注意–no-defaults参数要放在其余参数之前
2、提取指定position位置的binlog日志
shell> mysqlbinlog --start-position="120" --stop-position="332" mysql-bin-000005
3、提取指定时间段的binlog日志
shell> mysqlbinlog --start-datetime="2014-12-15 20:15:23" --stop-datetime="2014-12-15 22:15:23" mysql-bin-000005
4、提取binlog后直接导入mysql数据库
shell> mysqlbinlog mysql-bin-000005 | mysql -uroot -p
5、提取binlog并输出到日志文件
shell> mysqlbinlog mysql-bin-000005 > /opt/dump.sql
6、远程提取binlog并输出到文件
shell> mysqlbinlog -h192.168.1.116 -uroot -p mysql-bin-000005 > /opt/dump.sql
c. mysqlbinlog解析binlog
# row格式的binlog直接输出完全看不懂
shell> mysqlbinlog mysql-bin-000005
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#190122 0:10:26 server id 1 end_log_pos 120 CRC32 0x47610ace Start: binlog v 4, server v 5.6.29-log created 190122 0:10:26 at startup
ROLLBACK/*!*/;
BINLOG '
8u5FXA8BAAAAdAAAAHgAAAAAAAQANS42LjI5LWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAADy7kVcEzgNAAgAEgAEBAQEEgAAXAAEGggAAAAICAgCAAAACgoKGRkAAc4K
YUc=
'/*!*/;
# at 120
#700101 8:00:00 server id 1 end_log_pos 167 CRC32 0x1b09d2ba Rotate to mysql-bin.000002 pos: 4
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
这时候需要添加参数:
–base64-output=DECODE-ROWS: 解析row模式的sql
-v :显示statement模式的sql语句
shell> mysqlbinlog --base64-output=DECODE-ROWS -v mysql-bin-000005
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 467789453
#190122 0:30:00 server id 1 end_log_pos 467789541 CRC32 0xbd79c3d0 Table_map: `test`.`test_table` mapped to number 2026876
# at 467789541
#190122 0:30:00 server id 1 end_log_pos 467789726 CRC32 0x64e584b7 Delete_rows: table id 2026876 flags: STMT_END_F
### DELETE FROM `test`.`test_table`
### WHERE
### @1=37455
### @2=127365882
### @3='20180911002167430018010000053'
### @4=1
### @5=1548002434542
### @6='2019-01-21 00:30:04'
### @7=63
### @8='1'
### @9='20180911002167430018010000053'
### @10='20180911002167430018010000053'
### @11='2019-01-21 00:30:04'
### @12='2019-01-21 00:30:04'
# at 467789726
#190122 0:30:00 server id 1 end_log_pos 467789757 CRC32 0x88070c7f Xid = 596669085
COMMIT/*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
在上述操作中,我们可以看到,打印出来的binlog信息是被注释掉的,无法直接执行。
有非常多针对binlog的开源工具,我找到的是 binlog2sql。它提供的功能很多,根据不同的选项,可以得到原始SQL、回滚SQL、去除主键的INSERT SQL等。
首先要安装python环境:centos安装python2.7 。然后下载服务并安装依赖
shell> git clone https://github.com/danfengcao/binlog2sql.git && cd binlog2sql
shell> pip install -r requirements.txt
解析出标准sql
python binlog2sql.py -h192.168.150.151 -P3306 -uroot -p'root' --start-file='/opt/mysql/data/mysql-bin.000368' --start-position="467789453" --stop-position="467789757" > binlog.sql
mysql> souce binlog.sql;