侧边栏壁纸
博主头像
小小酥心

旧书不厌百回读,熟读精思子自知💪

  • 累计撰写 22 篇文章
  • 累计创建 8 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

MySQL的binlog详解

小小酥心
2022-01-18 / 0 评论 / 0 点赞 / 1,147 阅读 / 10,275 字
温馨提示:
本文最后更新于 2022-01-18,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

1 简介

Binlog日志,即binary log,是二进制日志文件,记录对数据发生或潜在发生更改的SQL语句,并以二进制形式保存在磁盘。有两个作用,一个是增量备份,另一个是主从复制,即主节点维护一个binlog日志文件,从节点从binlog中同步数据,也可以通过binlog日志来恢复数据

2 开启Binlog

2.1 查询当前 MySQL 是否支持 binlog

如下ON代表支持(MySQL5.7默认关闭,MySQL8默认开启):

show variables like '%log_bin%';

+---------------------------------+---------------------------------------------+
| Variable_name                   | Value                                       |
+---------------------------------+---------------------------------------------+
| log_bin                         | ON                                          |
| log_bin_basename                | C:\db\mysql-8.0.17-winx64\data\binlog       |
| log_bin_index                   | C:\db\mysql-8.0.17-winx64\data\binlog.index |
| log_bin_trust_function_creators | OFF                                         |
| log_bin_use_v1_row_events       | OFF                                         |
| sql_log_bin                     | ON                                          |
+---------------------------------+---------------------------------------------+

Binlog日志包括两类文件:第一个是二进制索引文件(后缀名为.index),第二个为日志文件(后缀名为.00000*),记录数据库所有的DDL和DML(除了查询语句select)语句事件。

2.2 修改 my.cnf 文件以支持 binlog

2.2.1 Linux下可以通过以下方式查看my.cnf路径

mysql --help --verbose | grep my.cnf

2.2.2 在/etc 新建文件my.cnf并添加如下内容

  • 注意添加 mysqld 组
[mysqld]
# 日志中的Serverid
server-id = 1
# 开启二进制日志(默认开启)
log_bin = /usr/local/mysql/log/mysql-bin.log
# mysql清除过期日志的时间(天),默认值0,不自动清理,而是使用滚动循环的方式。
expire_logs_days = 3
# 设置binlog清理时间(秒) --8.0新增
binlog_expire_logs_seconds = 3
# 如果二进制日志写入的内容超出给定值,日志就会发生滚动。你不能将该变量设置为大于1GB或小于4096字节。 默认值是1GB。
max_binlog_size = 100m
# 默认是所有记录,可以配置哪些需要记录,哪些不记录
# binlog_do_db = include_database_name
# binlog_ignore_db = include_database_name
# binlog缓存大小
binlog_cache_size = 4m
# 最大binlog缓存大小
max_binlog_cache_size = 512m
# binlog的格式也有三种:STATEMENT,ROW,MIXED。mysql 5.7.7后,默认值从 MIXED 改为 ROW
binlog_format = row
# 默认值N=1,使binlog在每N次binlog写入后与硬盘同步,ps:1最慢
# sync_binlog = 1
# 关闭binlog。也可用disable-log-bin --8.0新增
skip-log-bin
  • 重启 MySQL
net stop mysql
net start mysql

2.3 binlog的三种格式

2.3.1 ROW

针对行记录日志,每行修改产生一条记录。

优点:上下文信息比较全,恢复某条误操作时可以直接在日志中查找到原文信息,对于主从复制支持好。

缺点:输出非常大,如果是Alter语句将产生大量的记录

格式如下:

DELETE FROM `back`.`sys_user` WHERE `deptid`=27 AND `status`=1 AND `account`='admin' AND `name`='张三' AND `phone`='18200000000' AND `roleid`='1' AND `createtime`='2016-01-29 08:49:53' AND `sex`=2 AND `email`='sn93@qq.com' AND `birthday`='2017-05-05 00:00:00' AND `avatar`='girl.gif' AND `version`=25 AND `password`='ecfadcde9305f8891bcfe5a1e28c253e' AND `salt`='8pgby' AND `id`=1 LIMIT 1; #start 4 end 796 time 2018-10-12 17:03:19

2.3.2 STATEMENT

针对sql语句的,每条语句产生一条记录

优点:产生的日志量比较小,主从版本可以不一致

缺点:主从有些语句不能支持,像自增主键和UUID这种类型的

格式如下:

delete from `sys_role`;

2.3.3 MIX

结合了两种的优点,一般情况下都采用STATEMENT模式,对于不支持的语句采用ROW模式。

3 binlog管理命令

3.1 状态相关

3.1.1 show master logs

查看所有Binlog的日志列表。

show master logs; # 或者 show binary logs;
 
+---------------+-----------+-----------+
| Log_name      | File_size | Encrypted |
+---------------+-----------+-----------+
| binlog.000001 |       178 | No        |
| binlog.000002 |       155 | No        |
+---------------+-----------+-----------+

3.1.2 show master status

查看binlog日志状态。查看最后一个Binlog日志的编号名称,及最后一个事件结束的位置( pos )。

show master status;

+---------------+----------+--------------+------------------+-------------------+
| File          | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+-------------------+
| binlog.000008 |      155 |              |                  |                   |
+---------------+----------+--------------+------------------+-------------------+

3.1.3 flush logs

刷新binlog日志文件,刷新之后会创建一个新的Binlog日志文件。

每当mysqld服务重启时,会自动执行刷新binlog日志命令,mysqldump备份数据时加 -F 选项也会刷新binlog日志。

3.1.4 reset master

清空所有的 binlog 日志文件

3.2 事件相关

show binlog events [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count];

3.2.1 查看第一个Binlog日志

show binlog events;

+---------------+-----+----------------+-----------+-------------+-----------------------------------+
| Log_name      | Pos | Event_type     | Server_id | End_log_pos | Info                              |
+---------------+-----+----------------+-----------+-------------+-----------------------------------+
| binlog.000001 |   4 | Format_desc    |         1 |         124 | Server ver: 8.0.17, Binlog ver: 4 |
| binlog.000001 | 124 | Previous_gtids |         1 |         155 |                                   |
| binlog.000001 | 155 | Stop           |         1 |         178 |                                   |
+---------------+-----+----------------+-----------+-------------+-----------------------------------+

3.2.2 查看指定的Binlog日志

show binlog events in 'mysql-bin.000002';

3.2.3 从指定的位置开始,查看指定的Binlog日志

show binlog events in 'mysql-bin.000001' from 666;

3.2.4 从指定的位置开始,查看指定的Binlog日志,限制查询的条数

show binlog events in 'mysql-bin.000001' from 666 limit 2;

3.2.5 从指定的位置开始,带有偏移,查看指定的Binlog日志,限制查询的条数

show binlog events in 'mysql-bin.000001' from 666 limit 1, 2;

3.3 内容相关

mysqlbinlog用于处理二进制的日志文件,如果想要查看这些日志文件的文本内容,就需要使用mysqlbinlog工具。

3.3.1 mysqlbinlog命令的语法

mysqlbinlog [options] logfile1 logfile2 ...

3.3.2 mysqlbinlog的参数

-d, --database=name      仅显示指定数据库的转储内容。
-o, --offset=#           跳过前N行的日志条目。
-r, --result-file=name   将输入的文本格式的文件转储到指定的文件。
-s, --short-form         使用简单格式。
--set-charset=name       在转储文件的开头增加'SET NAMES character_set'语句。
--start-datetime=name    转储日志的起始时间。
--stop-datetime=name     转储日志的截止时间。
-j, --start-position=#   转储日志的起始位置。
--stop-position=#        转储日志的截止位置。

3.3.3 指令示例

3.3.3.1 查看binlog日志文件内容

mysqlbinlog mysql-bin.000002

3.3.3.2 转为文本输出

mysqlbinlog --base64-output=decode-rows -v --start-date='2014-09-16 14:00:00' --stop-date='2014-09-16 14:20:00' mysql-bin.000017 > mysqlbinlogsql_restore_2014091614.sql
  • --no-defaults 为了防止报错:mysqlbinlog: unknown variable 'default_character_set=utf8mb4'

  • --base64-output='decode-rows' 和-v一起使用, 进行base64解码

  • -d=--database 指明数据库名称

    其他有很多用来限定范围的参数,比如数据库,起始时间,起始位置等等。这些参数在查找误操作的时候非常有用

3.3.3.3 恢复数据到数据库

mysqlbinlog --start-datetime="2018-04-27 20:58:18" --stop-datetime="2018-04-27 20:58:35" --database=hello /var/lib/mysql/mysql-bin.000009 | /usr/bin/mysql -uroot -p8856769abcd -v hello

3.3.4 内容结构

3.3.4.1 binlog的基本块

# at 417750
#181007 1:50:38 server id 1630000 end_log_pos 417844 CRC32 0x9fc3e3cd Query thread_id=440109962 exec_time=0 error_code=0
SET TIMESTAMP=1538877038/*!*/;
BEGIN

# at 417750

指明的当前位置相对文件开始的偏移位置,这个在mysqlbinlog命令中可以作为–start-position的参数

#181007 1:50:38 server id 1630000 end_log_pos 417844 CRC32 0x9fc3e3cd Query thread_id=440109962 exec_time=0 error_code=0

  • 181007 1:50:38 指明时间为18年10月7号1:50:38;
  • serverid 也就是你在配置文件中的配置的;
  • end_log_pos 417844 这个块在417844结束;
  • thread_id 执行的线程id;
  • exec_time 执行时间;
  • error_code 错误码。

SET TIMESTAMP=1538877038/!/;
BEGIN

具体的执行语句

3.3.4.2 完整内容

一行记录产生的日志如下所示:

# at 417750
#181010  9:50:38 server id 1630000  end_log_pos 417844 CRC32 0x9fc3e3cd     Query   thread_id=440109962 exec_time=0 error_code=0
SET TIMESTAMP=1539136238/*!*/;
BEGIN
/*!*/;
# at 417844
#181010  9:50:38 server id 1630000  end_log_pos 417930 CRC32 0xce36551b     Table_map: `goods`.`good_info` mapped to number 129411
# at 417930
#181010  9:50:38 server id 1630000  end_log_pos 418030 CRC32 0x5827674a     Update_rows: table id 129411 flags: STMT_END_F
### UPDATE `goods`.`good_info`
### WHERE
###   @1='2018:10:07' /* DATE meta=0 nullable=0 is_null=0 */
###   @2=9033404 /* INT meta=0 nullable=0 is_null=0 */
###   @3=1 /* INT meta=0 nullable=0 is_null=0 */
###   @4=8691108 /* INT meta=0 nullable=0 is_null=0 */
###   @5=9033404 /* INT meta=0 nullable=0 is_null=0 */
###   @6=20 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @7=1538877024 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
### SET
###   @1='2018:10:07' /* DATE meta=0 nullable=0 is_null=0 */
###   @2=9033404 /* INT meta=0 nullable=0 is_null=0 */
###   @3=1 /* INT meta=0 nullable=0 is_null=0 */
###   @4=8691108 /* INT meta=0 nullable=0 is_null=0 */
###   @5=9033404 /* INT meta=0 nullable=0 is_null=0 */
###   @6=21 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @7=1538877024 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
# at 418030
#181010  9:50:38 server id 1630000  end_log_pos 418061 CRC32 0x468fb30e     Xid = 212760460521
COMMIT/*!*/;
# at 418061

以SET TIMESTAMP=1539136238/!/;开始,以COMMIT/!/;结尾。我们可以根据两个at指明的位置来限定范围。

注意一条记录开始的SET TIMESTAMP之前的# at 417750和结尾的COMMIT之后的# at 418061。

恢复到数据库

4 Binlog相关变量

mysql> show variables like "%binlog%";

+------------------------------------------------+----------------------+
| Variable_name                                  | Value                |
+------------------------------------------------+----------------------+
| binlog_cache_size                              | 32768                |
| binlog_checksum                                | CRC32                |
| binlog_direct_non_transactional_updates        | OFF                  |
| binlog_encryption                              | OFF                  |
| binlog_error_action                            | ABORT_SERVER         |
| binlog_expire_logs_seconds                     | 2592000              |
| binlog_format                                  | ROW                  |
| binlog_group_commit_sync_delay                 | 0                    |
| binlog_group_commit_sync_no_delay_count        | 0                    |
| binlog_gtid_simple_recovery                    | ON                   |
| binlog_max_flush_queue_time                    | 0                    |
| binlog_order_commits                           | ON                   |
| binlog_rotate_encryption_master_key_at_startup | OFF                  |
| binlog_row_event_max_size                      | 8192                 |
| binlog_row_image                               | FULL                 |
| binlog_row_metadata                            | MINIMAL              |
| binlog_row_value_options                       |                      |
| binlog_rows_query_log_events                   | OFF                  |
| binlog_stmt_cache_size                         | 32768                |
| binlog_transaction_dependency_history_size     | 25000                |
| binlog_transaction_dependency_tracking         | COMMIT_ORDER         |
| innodb_api_enable_binlog                       | OFF                  |
| log_statements_unsafe_for_binlog               | ON                   |
| max_binlog_cache_size                          | 18446744073709547520 |
| max_binlog_size                                | 1073741824           |
| max_binlog_stmt_cache_size                     | 18446744073709547520 |
| sync_binlog                                    | 1                    |
+------------------------------------------------+----------------------+

5 数据恢复流程实例

0 数据库中创建一张表,插入一条数据,再将表删除。此时我们来恢复被删除的这条数据。

CREATE TABLE USER (
	id INT,
	NAME VARCHAR(32)
);
INSERT INTO USER VALUES (1, "张三");

DROP TABLE USER;

1 查看binlog日志

show master status;
+---------------+----------+--------------+------------------+-------------------+
| File          | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+-------------------+
| binlog.000012 |      865 |              |                  |                   |
+---------------+----------+--------------+------------------+-------------------+

2 使用flush logs;创建新的日志文件,方便处理当前文件。

3 查看binlog.000012中的事件。

mysql> show binlog events in "binlog.000012";
+---------------+-----+----------------+-----------+-------------+------------------------------------------------------+
| Log_name      | Pos | Event_type     | Server_id | End_log_pos | Info													|        +---------------+-----+----------------+-----------+-------------+------------------------------------------------------+
| binlog.000012 |   4 | Format_desc    |         1 |         124 | Server ver: 8.0.17, Binlog ver: 4					|       
| binlog.000012 | 124 | Previous_gtids |         1 |         155 |														|
| binlog.000012 | 155 | Anonymous_Gtid |         1 |         232 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'					|
| binlog.000012 | 232 | Query          |         1 |         371 | use `test`; create table user (
                                                                                        id int,
                                                                                        name varchar(32)
                                                                                ) /* xid=458 */ 						|
| binlog.000012 | 371 | Anonymous_Gtid |         1 |         450 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'					|
| binlog.000012 | 450 | Query          |         1 |         525 | BEGIN												|
| binlog.000012 | 525 | Table_map      |         1 |         581 | table_id: 342 (test.user)							|
| binlog.000012 | 581 | Write_rows     |         1 |         628 | table_id: 342 flags: STMT_END_F						|
| binlog.000012 | 628 | Xid            |         1 |         659 | COMMIT /* xid=460 */									|
| binlog.000012 | 659 | Anonymous_Gtid |         1 |         736 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'					|
| binlog.000012 | 736 | Query          |         1 |         865 | use `test`; DROP TABLE `user` /* generated by server
																	*/ /* xid=466 */									|
| binlog.000012 | 865 | Rotate         |         1 |         909 | binlog.000013;pos=4									|
+---------------+-----+----------------+-----------+-------------+------------------------------------------------------+

可以看到,从659的commit到865,是删除表操作。所以我们恢复数据应是从155到659。

4 恢复数据

mysqlbinlog --start-position=155 --stop-position=659 --database=test /var/lib/mysql/binlog.000012 | /usr/bin/mysql -uroot -p8856769abcd -v test

-v 控制台输出信息

5 查看数据

select * from user;
+------+--------+
| id   | name   |
+------+--------+
|    1 | 张三    |
+------+--------+

在实际生产环境中,通常是将备份(mysqldump)与binlog结合,在备份数据的基础上使用binlog恢复剩余的数据。

0

评论区