1,Binlog简介
MySQL 的 Binlog 日志是一种二进制格式的日志,Binlog 记录所有的 DDL 和 DML 语句(除了数据查询语句SELECT、SHOW等),以 Event 的形式记录,同时记录语句执行时间。
Binlog 的主要作用有两个:
- 数据恢复
因为 Binlog 详细记录了所有修改数据的 SQL,当某一时刻的数据误操作而导致出问题,或者数据库宕机数据丢失,那么可以根据 Binlog 来回放历史数据。
- 主从复制
想要做多机备份的业务,可以去监听当前写库的 Binlog 日志,同步写库的所有更改。
Binlog 包括两类文件:
- 二进制日志索引文件(.index):记录所有的二进制文件。
- 二进制日志文件(.00000*):记录所有 DDL 和 DML 语句事件。
Binlog 日志功能默认是开启的,线上情况下 Binlog 日志的增长速度是很快的,在 MySQL 的配置文件 my.cnf 中提供一些参数来对 Binlog 进行设置。
设置此参数表示启用binlog功能,并制定二进制日志的存储目录
log-bin=/home/mysql/binlog/
#mysql-bin.*日志文件最大字节(单位:字节)
#设置最大100MB
max_binlog_size=104857600
#设置了只保留7天BINLOG(单位:天)
expire_logs_days = 7
#binlog日志只记录指定库的更新
#binlog-do-db=db_name
#binlog日志不记录指定库的更新
#binlog-ignore-db=db_name
#写缓冲多少次,刷一次磁盘,默认0
sync_binlog=0
需要注意的是:
max_binlog_size :Binlog 最大和默认值是 1G,该设置并不能严格控制 Binlog 的大小,尤其是 Binlog 比较靠近最大值而又遇到一个比较大事务时,为了保证事务的完整性不可能做切换日志的动作,只能将该事务的所有 SQL 都记录进当前日志直到事务结束。所以真实文件有时候会大于 max_binlog_size 设定值。
expire_logs_days :Binlog 过期删除不是服务定时执行,是需要借助事件触发才执行,事件包括:
- 服务器重启
- 服务器被更新
- 日志达到了最大日志长度
max_binlog_size
- 日志被刷新
二进制日志由配置文件的 log-bin 选项负责启用,MySQL 服务器将在数据根目录创建两个新文件mysql-bin.000001 和 mysql-bin.index,若配置选项没有给出文件名,MySQL 将使用主机名称命名这两个文件,其中 .index 文件包含一份全体日志文件的清单。
sync_binlog:这个参数决定了 Binlog 日志的更新频率。默认 0 ,表示该操作由操作系统根据自身负载自行决定多久写一次磁盘。
sync_binlog = 1 表示每一条事务提交都会立刻写盘。sync_binlog=n 表示 n 个事务提交才会写盘。
根据 MySQL 文档,写 Binlog 的时机是:SQL transaction 执行完,但任何相关的 Locks 还未释放或事务还未最终 commit 前。这样保证了 Binlog 记录的操作时序与数据库实际的数据变更顺序一致。
检查 Binlog 文件是否已开启:
mysql> show variables like '%log_bin%';
+---------------------------------+------------------------------------+
| Variable_name | Value |
+---------------------------------+------------------------------------+
| log_bin | ON |
| log_bin_basename | /usr/local/mysql/data/binlog |
| log_bin_index | /usr/local/mysql/data/binlog.index |
| log_bin_trust_function_creators | OFF |
| log_bin_use_v1_row_events | OFF |
| sql_log_bin | ON |
+---------------------------------+------------------------------------+
6 rows in set (0.00 sec)
MySQL 会把用户对所有数据库的内容和结构的修改情况记入 mysql-bin.n 文件,而不会记录 SELECT 和没有实际更新的 UPDATE 语句。
如果你不知道现在有哪些 Binlog 文件,可以使用如下命令:
show binary logs; #查看binlog列表
show master status; #查看最新的binlog
mysql> show binary logs;
+------------------+-----------+-----------+
| Log_name | File_size | Encrypted |
+------------------+-----------+-----------+
| mysql-bin.000001 | 179 | No |
| mysql-bin.000002 | 156 | No |
+------------------+-----------+-----------+
2 rows in set (0.00 sec)
Binlog 文件是二进制文件,强行打开看到的必然是乱码,MySQL 提供了命令行的方式来展示 Binlog 日志
mysqlbinlog mysql-bin.000002 | more
2,Binlog日志格式
针对不同的使用场景,Binlog 也提供了可定制化的服务,提供了三种模式来提供不同详细程度的日志内容。
- Statement 模式:基于 SQL 语句的复制(statement-based replication-SBR)
- Row 模式:基于行的复制(row-based replication-RBR)
- Mixed 模式:混合模式复制(mixed-based replication-MBR)
Statement 模式
保存每一条修改数据的SQL。
该模式只保存一条普通的SQL语句,不涉及到执行的上下文信息。
因为每台 MySQL 数据库的本地环境可能不一样,那么对于依赖到本地环境的函数或者上下文处理的逻辑 SQL 去处理的时候可能同样的语句在不同的机器上执行出来的效果不一致。
比如像 sleep()函数,last_insert_id()函数,等等,这些都跟特定时间的本地环境有关。
Row 模式
MySQL V5.1.5 版本开始支持Row模式的 Binlog,它与 Statement 模式的区别在于它不保存具体的 SQL 语句,而是记录具体被修改的信息。
比如一条 update 语句更新10条数据,如果是 Statement 模式那就保存一条 SQL 就够,但是 Row 模式会保存每一行分别更新了什么,有10条数据。
Row 模式的优缺点就很明显了。保存每一个更改的详细信息必然会带来存储空间的快速膨胀,换来的是事件操作的详细记录。所以要求越高代价越高。
Mixed 模式
Mixed 模式即以上两种模式的综合体。既然上面两种模式分别走了极简和一丝不苟的极端,那是否可以区分使用场景的情况下将这两种模式综合起来呢?
在 Mixed 模式中,一般的更新语句使用 Statement 模式来保存 Binlog,但是遇到一些函数操作,可能会影响数据准确性的操作则使用 Row 模式来保存。这种方式需要根据每一条具体的 SQL 语句来区分选择哪种模式。
MySQL 从 V5.1.8 开始提供 Mixed 模式,V5.7.7 之前的版本默认是Statement 模式,之后默认使用Row模式, 但是在 8.0 以上版本已经默认使用 Mixed 模式了。
查询当前 Binlog 日志使用格式:
mysql> show global variables like '%binlog_format%';
+---------------------------------+---------+
| Variable_name | Value |
+---------------------------------+---------+
| binlog_format | MIXED |
| default_week_format | 0 |
| information_schema_stats_expiry | 86400 |
| innodb_default_row_format | dynamic |
| require_row_format | OFF |
+---------------------------------+---------+
5 rows in set (0.01 sec)