如何清除mysql的binlog
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何清除mysql的binlog相关的知识,希望对你有一定的参考价值。
mysql 的 Binlog 记录着 MySQL 数据库的所有变更信息,了解 Binlog 的结构可以帮助我们解析Binlog,甚至对 Binlog 进行一些修改,或者说是“篡改”,例如实现类似于 Oracle 的 flashback 的功能,恢复误删除的记录,把 update 的记录再还原回去等。本文将带您探讨一下这些神奇功能的实现,您会发现比您想象地要简单得多。本文指的 Binlog 是 ROW 模式的 Binlog,这也是 MySQL 8 里的默认模式,STATEMENT 模式因为使用中有很多限制,现在用得越来越少了。Binlog 由事件(event)组成,请注意是事件(event)不是事务(transaction),一个事务可以包含多个事件。事件描述对数据库的修改内容。
现在我们已经了解了 Binlog 的结构,我们可以试着修改 Binlog 里的数据。例如前面举例的 Binlog 删除了一条记录,我们可以试着把这条记录恢复,Binlog 里面有个删除行(DELETE_ROWS_EVENT)的事件,就是这个事件删除了记录,这个事件和写行(WRITE_ROWS_EVENT)的事件的数据结构是完全一样的,只是删除行事件的类型是 32,写行事件的类型是 30,我们把对应的 Binlog 位置的 32 改成 30 即可把已经删除的记录再插入回去。从前面的 “show binlog events” 里面可看到这个 DELETE_ROWS_EVENT 是从位置 378 开始的,这里的位置就是 Binlog 文件的实际位置(以字节为单位)。从事件(event)的结构里面可以看到 type_code 是在 event 的第 5 个字节,我们写个 Python 小程序把把第383(378+5=383)字节改成 30 即可。当然您也可以用二进制编辑工具来改。
找出 Binlog 中的大事务
由于 ROW 模式的 Binlog 是每一个变更都记录一条日志,因此一个简单的 SQL,在 Binlog 里可能会产生一个巨无霸的事务,例如一个不带 where 的 update 或 delete 语句,修改了全表里面的所有记录,每条记录都在 Binlog 里面记录一次,结果是一个巨大的事务记录。这样的大事务经常是产生麻烦的根源。我的一个客户有一次向我抱怨,一个 Binlog 前滚,滚了两天也没有动静,我把那个 Binlog 解析了一下,发现里面有个事务产生了 1.4G 的记录,修改了 66 万条记录!下面是一个简单的找出 Binlog 中大事务的 Python 小程序,我们知道用 mysqlbinlog 解析的 Binlog,每个事务都是以 BEGIN 开头,以 COMMIT 结束。我们找出 BENGIN 前面的 “# at” 的位置,检查 COMMIT 后面的 “# at” 位置,这两个位置相减即可计算出这个事务的大小,下面是这个 Python 程序的例子。
切割 Binlog 中的大事务
对于大的事务,MySQL 会把它分解成多个事件(注意一个是事务 TRANSACTION,另一个是事件 EVENT),事件的大小由参数 binlog-row-event-max-size 决定,这个参数默认是 8K。因此我们可以把若干个事件切割成一个单独的略小的事务
ROW 模式下,即使我们只更新了一条记录的其中某个字段,也会记录每个字段变更前后的值,这个行为是 binlog_row_image 参数控制的,这个参数有 3 个值,默认为 FULL,也就是记录列的所有修改,即使字段没有发生变更也会记录。这样我们就可以实现类似 Oracle 的 flashback 的功能,我个人估计 MySQL 未来的版本从可能会基于 Binlog 推出这样的功能。
了解了 Binlog 的结构,再加上 Python 这把瑞士军刀,我们还可以实现很多功能,例如我们可以统计哪个表被修改地最多?我们还可以把 Binlog 切割成一段一段的,然后再重组,可以灵活地进行 MySQL 数据库的修改和迁移等工作。 参考技术A (1):执行“reset master;”命令,该命令将删除所有二进制日志,新日志的编号从“000001”开始,命令如下Mysql>reset master;(2):执行“Purge master logs to ‘mysql-bin.*****’”命令,该命令将删除“*****”编号之前的所有日志,下列中删除了“mysql-bin之前编号的所有日志Mysql>purge master logs to ‘mysql-bin.000015;从结果中发现,编号000015之前的所有日志都已经删除(3):执行“purge master logs before ‘yyyy-mm-dd hh24:min:ss’”命令,该命令将删除日期为“yyyy-mm-dd hh24:mi:ss”之前产生的所有日志,下列中删除了日期在“2010-05-22 01:00:之前的所有日志Mysql>purge master logs before ‘ 01:00:’;(4):设置参数—expire_logs_days=#(days),此参数的含义是设置日志的过期天数,过来指定的天数后日志将会被自动删除,这样将有利于减少DBA管理日志的工作量。#vi /etc/my.cnf[mysqld]--expire_logs_days=3这样,3天前的日志都会被删除,系统自动删除本回答被提问者采纳
Mysql日志---binlog
Mysql日志---binlog
背景
MySQL中到底有多少种log?你是否经常听别人说什么binlog、binary log、redo log、undo log、回滚日志、重做日志、中继日志、错误日志、慢查询日志、一般日志等等。这些概念都分别是什么?MySQL生成这些日志的目的都是什么?
接下来我们一起来分析一下MySQL中到底有哪些log吧。
MySQL中的日志分类
MySQL中经常遇到的日有以下几种:
- Binlog:全称是binary log,简称为binlog,就是我们平时说的二进制日志,
- Relay log:中继日志
- Redo log:重做日志
- Undo log:回滚日志
- Slow query log: 慢查询日志
- General log:一般日志
- Error log:错误日志
接下来,我们一个一个分别了解一下它们。今天这篇文章主要是分析一些binlog日志,其他的日志会在后续的文章中逐个分析。
Binlog
binlog是大家学习MySQL中经常遇到的,也是必须要了解的。它在MySQL中所起到的作用可是举足轻重的。
binlog在MySQL中默认是不开启的,因为开启它需要消耗一定的性能。如果我们需要使用到binlog则可以选择性的开启它。比如我们需要做主从同步的集群环境的时候,master主库上面的binlog是必须要打开的。这也是binlog存在的一个重要的功能,为主从同步提供支撑。
在做增量恢复的时候,binlog日志也起着至关重要的作用。比如:我们在今天凌晨零点的时候有一次全量的备份,然后今天上午有一个误操作把数据库给删除了。此时如果我们想要恢复数据库,则可以先恢复今天凌晨零担的全量备份文件,然后再基于还原后的数据库,再使用凌晨零点之后到当前删除数据库的时间点为止,这一段时间内的binlog做增量恢复,这样的数据库在还原之后,就是我们一个完整的数据库。
验证binlog日志是否开启
验证我们的MySQL数据库是否开启binlog可以使用show variables like '%log_bin%';
命令,下面分别是在一个没有开启binlog和开启binlog日志的MySQL实例上验证的效果。
下面是在没有开启binlog日志的MySQL实例上验证的效果:
mysql> show variables like '%log_bin%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| log_bin | OFF |/*这里显示OFF,表示没有开启binlog日志。*/
| log_bin_basename | |
| log_bin_index | |
| log_bin_trust_function_creators | OFF |
| log_bin_use_v1_row_events | OFF |
| sql_log_bin | ON |
+---------------------------------+-------+
6 rows in set (0.02 sec)
下面是在开启了binlog日志的MySQL实例上验证的效果:
mysql> show variables like '%log_bin%';
+---------------------------------+--------------------------------+
| Variable_name | Value |
+---------------------------------+--------------------------------+
| log_bin | ON |/*这显示ON,表示已经开启binlog*/
| log_bin_basename | /var/lib/mysql/mysql-bin |/*这是binlog日志文件存放的目录和名称*/
| log_bin_index | /var/lib/mysql/mysql-bin.index |/*这是binlog日志文件的索引文件目录和名称*/
| log_bin_trust_function_creators | OFF |
| log_bin_use_v1_row_events | OFF |
| sql_log_bin | ON |
+---------------------------------+--------------------------------+
6 rows in set (0.02 sec)
需要我们注意其中的两个参数:
- log_bin_basename:这里是配置的binlog日志文件的存放的目录和名称,可以从上面查看的结果中看出,这里的没有配置binlog日志文件的后缀名。因为binlog日志是一个一直滚动追加的日志文件,当超过一个指定的默认值(通常是1GB大小)之后,他会自动切分为一个新的binlog日志文件。文件的后缀名就是它滚动增长的标识符。它是一个有规律增长的序列,000001,000002,000003…999999
- log_bin_index:这个参数配置的是binlog日志的索引文件存储目录和名称,这里面记录了MySQL目前所有的有效的binlog日志文件列表。每一个binlog日志文件一行,按照binlog日志生成的时间顺序,依次排列下来。
开启和关闭binlog日志
如果我们想开启binlog日志,该如何开启呢?我们可以通过修改MySQL的my.cnf配置文件来开启。在MySQL的my.cnf配置文件中增加如下的配置即可开启binlog:
[mysqld]
# 启用二进制日志
log-bin=mysql-bin
# 主服务器唯一ID,可以使用主机IP地址的最后一个域值来作为MySQL集群中的serverid,5.7版本之后,在启用binlog的时候,这个参数也需要一并指定。否则启动MySQL服务失败。
server-id=100
# 设置binlog日志的格式
binlog_format=row
binlog_row_image=minimal
开启binlog之后,它会记录我们的哪些操作呢?我们平时对MySQL的操作有增、删、改、查,这些操作都会被记录在MySQL的binlog日志文件中吗?其实它只会记录我们的增、删、改的操作,查询的操作它是不会记录的。也就是说,它只记录对数据库有变更的操作,如果没有变更则不会记录在binlog日志文件中。
对于平时我们的一些DDL操作也会被记录在binlog日志文件中。比如我们删除一个表、增加一个列、创建一个索引、删除一个索引等这样的操作,也会被记录在binlog日志文件中。
我们知道,一个MySQL数据库实例下面可以有多个schema,也就是我们平时说的数据库。对于一个实例下面所有的数据库的操作的SQL语句,它们不会分开来存储在binlog日志文件中的。在binlog日志文件还没有切换新的文件的时候,在一定时间段内,所有的schema的操作语句都会记录在同一个binlog日志文件中。
如果我们要关闭binlog日志功能,可以把上面的参数log-bin=mysql-bin使用#注释掉这一行配置,然后重启MySQL实例就可以关闭binlog了。
如何选择性的开启binlog
如果一个MySQL数据库实例开启了binlog日志功能,那么能否做到只针对某几个schema(数据库)的操作才记录binlog日志,对其他schema(数据库)的操作不记录呢?
对于有些主从同步的业务场景下可能存在这样的业务需求。MySQL中可以使用两个参数binlog_do_db和binlog_ignore_db来满足这样的需求,如果不配置这两个参数,默认是会记录所有数据库的变更操作到binlog日志中。具体配置可以在my.cnf配置文件中参考如下的配置:
[mysqld]
# 此参数表示只记录制定数据库的二进制日志,下面配置的是只记录mydb1,mydb2,mydb3,mydb4着四个数据库的binlog日志,其他数据库的binlog日志不记录。
binlog_do_db=mydb1,mydb2,mydb3,mydb4
# 此参数标示不记录指定的数据库的二进制日志,下面的配置是忽略MySQL自带的几个数据库的binlog日志。
binlog_ignore_db=mysql,sys,information_schema,performance_schema
上面我们已经可以通过参数来为指定的数据库开启记录binlog日志,那么我们再细粒度分析一下,对于一个已经配置为需要记录binlog日志的schema(数据库)来说,难道对这个数据库所有有变更操作的SQL,都要被记录在binlog中吗?有没有办法让某一些操作不被记录在二进制日志中呢?
答案是肯定的。我们可以通过参数sql_log_bin参数来控制某些有变更的SQL语句是否可以被记录在binlog中。
该参数在配置开启binlog之后是默认为on的状态,表示所有有变更的SQL语句都会被记录在binlog中。如果不想记录某些SQL语句,只要在执行对应的SQL语句之前将这个参数设置为off就可以避免接下来执行的SQL语句被记录在binlog日志中。
下面是使用sql_log_bin参数来控制是否记录某些SQL语句到binlog日志中的实验示例,因为我没有在my.cnf配置文件中配置binlog_do_db和binlog_ignore_db参数,所以,对于MySQL中所有的数据库的变更操作都会别记录在binlog日志文件中。实验步骤和结果如下:
- 先检查当前session级别的sql_log_bin参数的值。
- 将参数sql_log_bin的值设置为OFF。
- 查看设置的结构是否为OFF。
- 当前binlog日志文件的名称和位置。
- 创建一个表t。
- 再次检查binlog日志文件的名称和位置,看是否发生变化。
- 查看binlog日志文件的具体内容,查看是否有记录前面创建表t的DDL语句。
- 把当前session级别的sql_log_bin参数设置为ON。
- 检查设置的结果是否为ON。
- 检查当前binlog日志的文件名称和位置。
- 创建一个表a。
- 再次检查当前binlog日志的文件名称和位置,看是否发生变化。
- 检查binlog日志的具体内容,看是否包含创建表a的DDL语句。
mysql> show variables like 'sql_log_bin';/*查看当前sql_log_bin参数的值为on,表示会记录所有当前session操作的SQL语句。*/
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sql_log_bin | ON |
+---------------+-------+
1 row in set (0.01 sec)
mysql> set session sql_log_bin=off;/*关闭当前session记录binlog的功能*/
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like 'sql_log_bin';/*查看后,确实关闭的session的binlog记录功能。*/
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sql_log_bin | OFF |
+---------------+-------+
1 row in set (0.01 sec)
mysql> show master status;/*查看当前binlog日志的文件名称和位置。*/
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000013 | 632 | | mysql | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.01 sec)
mysql> create table t(id int);/*创建了一个表t,这个DDL语句应该不会被记录在binlog日志中。*/
Query OK, 0 rows affected (0.03 sec)
mysql> show master status;/*再次查看当前binlog日志的文件名称和位置,和创建表t之前的文件名称和位置是相同的,就是说binlog日志并没有向后滚动增加。*/
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000013 | 632 | | mysql | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.01 sec)
mysql> show binlog events in 'mysql-bin.000013';/*查看binlog日志文件中内容,确实没有看到关于创建表t的SQL语句,证明我们的操作是正确的。*/
+------------------+-----+----------------+-----------+-------------+----------------------------------------------------------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------+-----+----------------+-----------+-------------+----------------------------------------------------------------------------------------+
| mysql-bin.000013 | 4 | Format_desc | 100 | 123 | Server ver: 5.7.24-log, Binlog ver: 4 |
| mysql-bin.000013 | 123 | Previous_gtids | 100 | 154 | |
| mysql-bin.000013 | 154 | Anonymous_Gtid | 100 | 219 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| mysql-bin.000013 | 219 | Query | 100 | 367 | use `feng`; create table test(id int primary key auto_increment, a varchar(16), b int) |
| mysql-bin.000013 | 367 | Anonymous_Gtid | 100 | 432 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| mysql-bin.000013 | 432 | Query | 100 | 504 | BEGIN |
| mysql-bin.000013 | 504 | Table_map | 100 | 555 | table_id: 115 (feng.test) |
| mysql-bin.000013 | 555 | Write_rows | 100 | 601 | table_id: 115 flags: STMT_END_F |
| mysql-bin.000013 | 601 | Xid | 100 | 632 | COMMIT /* xid=30 */ |
+------------------+-----+----------------+-----------+-------------+----------------------------------------------------------------------------------------+
9 rows in set (0.00 sec)
mysql> set session sql_log_bin=on;/*开启当前session,记录binlog日志的功能。*/
Query OK, 0 rows affected (0.01 sec)
mysql> show variables like 'sql_log_bin';/*验证是否真正的开启,下面结果为ON,表示确实开启了session级别记录binlog日志的功能。*/
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sql_log_bin | ON |
+---------------+-------+
1 row in set (0.01 sec)
mysql> show master status;/*查看当前binlog日志文件的名称和位置。*/
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000013 | 632 | | mysql | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.01 sec)
mysql> create table a(id int);/*创建一个表a,这个创建表a的DDL语句应该被记录在binlog日志文件中。*/
Query OK, 0 rows affected (0.05 sec)
mysql> show master status;/*创建完表a之后,再次查看binlog日志文件的名称和位置,发现位置比之前增加了一些。从632变成了793。*/
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000013 | 793 | | mysql | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
mysql> show binlog events in 'mysql-bin.000013';/*查看binlog日志文件中的内容。发现里面确实记录了创建表a的DDL语句*/
+------------------+-----+----------------+-----------+-------------+----------------------------------------------------------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------+-----+----------------+-----------+-------------+----------------------------------------------------------------------------------------+
| mysql-bin.000013 | 4 | Format_desc | 100 | 123 | Server ver: 5.7.24-log, Binlog ver: 4 |
| mysql-bin.000013 | 123 | Previous_gtids | 100 | 154 | |
| mysql-bin.000013 | 154 | Anonymous_Gtid | 100 | 219 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| mysql-bin.000013 | 219 | Query | 100 | 367 | use `feng`; create table test(id int primary key auto_increment, a varchar(16), b int) |
| mysql-bin.000013 | 367 | Anonymous_Gtid | 100 | 432 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| mysql-bin.000013 | 432 | Query | 100 | 504 | BEGIN |
| mysql-bin.000013 | 504 | Table_map | 100 | 555 | table_id: 115 (feng.test) |
| mysql-bin.000013 | 555 | Write_rows | 100 | 601 | table_id: 115 flags: STMT_END_F |
| mysql-bin.000013 | 601 | Xid | 100 | 632 | COMMIT /* xid=30 */ |
| mysql-bin.000013 | 632 | Anonymous_Gtid | 100 | 697 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| mysql-bin.000013 | 697 | Query | 100 | 793 | use `feng`; create table a(id int) /*这里就是记录的表a的DDL语句*/ |
+------------------+-----+----------------+-----------+-------------+----------------------------------------------------------------------------------------+
11 rows in set (0.01 sec)
参数sql_log_bin在某些时候很有好用,比如在主从同步读写分离的情况下,为了避免在执行某些DDL语句而导致主从同步延迟的问题发生,我们会在主和从上分别执行我们的DDL语句,这个时候,我们是不希望在主上执行的DDL语句被记录在binlog日志文件中,因为我们不想通过组从同步的方式在从节点上执行DDL,我们想自己在从节点上执行DDL,此时参数sql_log_bin就可以满足我们的这个需求。
只要我们在主节点上执行DDL之前,把参数sql_log_bin设置为OFF,然后再去执行我们的DDL语句,这样这个DDL语句就不会被记录在binlog日志中,也就不会被同步到从节点上。
开启binlog日志后的效果
开启binlog日志文件之后,我们可以在对应的日志文件目录下面看到binlog日志,如下所示:
root@test:/var/lib/mysql# pwd
/var/lib/mysql
root@test:/var/lib/mysql# ls -lsr mysql-bin*
4 -rw-r----- 1 mysql mysql 133 Dec 30 18:00 mysql-bin.index
4 -rw-r----- 1 mysql mysql 154 Dec 30 18:00 mysql-bin.000007
4 -rw-r----- 1 mysql mysql 177 Dec 30 18:00 mysql-bin.000006
4 -rw-r----- 1 mysql mysql 177 Dec 30 17:56 mysql-bin.000005
8 -rw-r----- 1 mysql mysql 5703 Dec 30 17:39 mysql-bin.000004
4 -rw-r----- 1 mysql mysql 177 Dec 29 15:00 mysql-bin.000003
4 -rw-r----- 1 mysql mysql 177 Dec 28 15:45 mysql-bin.000002
4 -rw-r----- 1 mysql mysql 177 Dec 28 15:45 mysql-bin.000001
root@test:/var/lib/mysql# cat mysql-bin.index
./mysql-bin.000001
./mysql-bin.000002
./mysql-bin.000003
./mysql-bin.000004
./mysql-bin.000005
./mysql-bin.000006
./mysql-bin.000007
root@test:/var/lib/mysql#
从上面我们可以看到,binlog日志文件的索引文件中记录的是当前有效的binlog日志文件列表。当binlog文件的编号到达999999之后,它会再次从000001开始。
除了去服务器对应的日志文件目录上去查看binlog有哪些之外,我们可以直接在MySQL客户端工具或命令行中使用show binary logs;命令来查看当前有哪些binlog日志文件。如下所示:
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000011 | 177 |
| mysql-bin.000012 | 201 |
| mysql-bin.000013 | 154 |
+------------------+-----------+
7 rows in set (0.00 sec)
如果是在一个主从同步、读写分离集群环境中的主节点上,我们还可以使用下面的命令来查看binlog日志文件有哪些,已经查看当前使用的binlog日志文件名称和日志的偏移量是多少。
mysql> show master logs;
+------------------+-----------+
| Log_name | File_size |
| mysql-bin.000011 | 177 |
| mysql-bin.000012 | 201 |
| mysql-bin.000013 | 793 |
+------------------+-----------+
7 rows in set (0.00 sec)
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000013 | 793 | | mysql | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
binlog日志文件记录的格式
我们知道在MySQL主从同步的时候,从库是靠读取主库的binlog日志的内容来同步主库的数据的。那么在binlog日志文件中,记录的SQL语句的方式可能会导致从库中的数据和主库不一致。
举例说明一下:假如我们在主库上有一个表t1,他们表结构如下,此时我们向表t1中执行一个insert语句:
mysql> desc t1;
+-------+----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+----------------+------+-----+---------+----------------+
| c1 | int(11) | NO | PRI | NULL | auto_increment |
| c2 | varchar(16) | YES | | NULL | |
| c3 | decimal(16,16) | YES | | NULL | |
+-------+----------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
mysql如何配置mysql的binlog