MySQL Binlog 的关键作用与优化策略
前言
MySQL 的日志系统包含了多种类型,其中最重要的包括错误日志、查询日志、慢查询日志、事务日志、二进制日志(binlog)、以及回滚日志(undo log)。在这些日志中,二进制日志(binlog)和事务日志(redo log)尤为关键。
binlog 是用来做什么的?
简而言之,binlog 在 MySQL 数据库中扮演着至关重要的角色,它是实现数据备份、主从复制、故障恢复等功能的基础。通过 binlog,MySQL 能够确保数据一致性和可靠性。
今天,我们将重点讨论 binlog(二进制日志)及其作用。
什么是 Binlog 日志
Binlog(Binary Log)是 MySQL 数据库生成的一种日志类型,用于记录所有对数据库的操作,主要包括 DML(数据操作语言)和 DDL(数据定义语言)操作。每次执行增、删、改等操作时,都会在 binlog 中留下记录。此外,对数据库结构的变更(如创建、修改表结构)也会被记录。
binlog 的重要性:
- 数据恢复:当数据库发生故障时,binlog 是恢复丢失数据的重要工具。它记录了每一条变更操作,确保能够在恢复时重新执行这些操作。
- 主从复制:在 MySQL 的主从架构中,binlog 用于同步主库的变更到从库,从而保证数据一致性。
- 审计功能:binlog 为数据库操作提供了详尽的审计日志,便于追溯和排查问题。
为什么需要 Binlog 日志
数据备份与恢复: Binlog 日志的关键作用之一是用于数据库的增量备份。每次对数据进行修改时,Binlog 记录了这次变更操作。在数据库受损或数据丢失的情况下,我们可以依靠这些 Binlog 日志来还原数据,确保不会丢失关键的更新。
主从复制: Binlog 日志在实现 MySQL 主从复制中扮演着关键角色。主数据库生成的 Binlog 日志会被同步到从数据库,从而使从数据库能够按照相同的顺序执行这些日志,保持与主数据库的数据一致性。这种复制机制不仅用于提高读取性能,还在分布式系统中发挥着重要作用。
审计: Binlog 日志提供了对数据库操作历史的详尽记录,可用于审计和排查问题。通过查看 Binlog,我们可以追溯到每一次对数据库的操作,了解何时发生了什么变更。这为问题排查和系统审计提供了有力的支持。
Binlog 日志因此成为数据库管理中不可或缺的工具,它保障了数据的完整性,支持数据库备份和恢复,同时提供了强大的审计功能。
Binlog 日志的实现原理
Binlog 日志的实现原理是 MySQL 数据库系统中的关键机制,确保了数据库操作的一致性和持久性。以下是Binlog 日志实现的主要步骤:
1. 数据操作的记录:
- 当执行对数据库产生影响的 SQL 语句(例如增、删、改)时,这些操作会首先被记录到 Binlog 日志中。这确保了每次数据变更都被详细地记录下来。
2. 二阶段提交:
- 为了保证 Binlog 日志与实际数据库操作的原子性,MySQL 使用了二阶段提交策略。首先,将数据操作记录到 Binlog 日志中,然后才执行实际的数据修改。这种方式防止了在数据写入日志前出现意外导致的数据不一致性。
3. 日志的读取与重放:
- 当需要读取 Binlog 日志时,比如进行主从复制或者数据恢复,MySQL 会按照操作的顺序读取 Binlog 日志中的内容,并重放这些操作以还原数据的状态。这确保了数据库在恢复时能够准确地按照历史操作还原数据。
4. 输出格式:
- Binlog 日志可以以不同的输出格式存在,包括纯文本格式和二进制格式。纯文本格式便于人类阅读,而二进制格式则更为紧凑和高效,适合用于主从复制等场景。
总体来说,Binlog 日志的实现原理基于将数据变更记录到日志中,使用二阶段提交确保操作的原子性,以及在需要时读取和重放日志以还原数据状态。这个机制对于数据库的数据备份、恢复和主从复制等场景起到了至关重要的作用。
Binlog 日志的使用示例
首先确保MySQL开启了Binlog日志功能
mysql> show variables like '%log_bin%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| log_bin | OFF |
| 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.00 sec)
字段解释
log_bin:
- 含义: 表示是否启用二进制日志。
- 值: OFF 表示未启用,ON 表示已启用。
log_bin_basename:
- 含义: 指定二进制日志文件的基本名称。
- 值: 通常是一个文件名,用于构造二进制日志文件的完整路径。
log_bin_index:
- 含义: 指定二进制日志索引文件的名称。
- 值: 通常是一个文件名,用于存储二进制日志文件的索引信息。
log_bin_trust_function_creators:
- 含义: 表示是否信任具有非确定性函数创建者的二进制日志事务。
- 值: OFF 表示不信任,ON 表示信任。
log_bin_use_v1_row_events:
- 含义: 表示是否使用 v1 行事件格式。
- 值: OFF 表示不使用 v1 格式,ON 表示使用。
sql_log_bin:
- 含义: 表示是否记录 SQL 语句到二进制日志。
- 值: OFF 表示不记录 SQL 语句,ON 表示记录。
在配置中,log_bin
是 OFF,这表示你的 MySQL 实例当前未启用二进制日志。如果你想启用二进制日志,你需要将 log_bin 设置为 ON,并提供相应的 log_bin_basename 和 log_bin_index。
开启Binlog
注意,注意,注意,这个路径是我的docker容器内挂载MySQL服务的路径!!! 如果你不是docker部署,或者挂载路径不一致,请按照自己的修改,不要直接CV,然后发现不好用!!!
vim /mydata/mysql/conf/my.cnf
添加
[mysqld]
log-bin=mysql-bin
server_id=1
# 配置定时清理
expire_logs_days = 5
# binlog每个日志文件大小
max_binlog_size = 200m
# binlog日志格式,MySQL默认采用的是STATEMENT,建议使用MIXED
binlog_format = MIXED
重启MySQL服务
docker restart mysql
Binlog日志格式
STATEMENT模式(SBR):
优点:
- 不需要记录每一条SQL语句和每一行的数据变化,减少了binlog日志量,有助于提高性能。
缺点:
- 某些情况可能导致主从之间的数据不一致,例如在SQL语句中使用
sleep()
或6204970
等操作。
ROW模式(RBR):
优点:
- 任何情况下都可以复制,并且不会受到存储过程、函数等调用或触发器无法正确复制的问题的影响。
缺点:
- binlog日志文件可能会变得非常大。
- 在主节点执行
update
语句时,所有的变化都会写入binlog中,相较于STATEMENT模式,可能导致更频繁的binlog并发写问题。
MIXED模式:
特点:
- 是STATEMENT和ROW两种模式的混合使用。
- 一般的复制使用STATEMENT模式保存binlog,对于STATEMENT模式无法复制的操作使用ROW模式保存binlog。
- MySQL会根据执行的SQL语句的特性自动选择日志保存方式。
这种混合模式充分利用了两者的优势,同时避免了各自的缺点。
确认Binlog开启
mysql> show variables like '%log_bin%';
+---------------------------------+--------------------------------+
| Variable_name | Value |
+---------------------------------+--------------------------------+
| log_bin | ON |
| log_bin_basename | /var/lib/mysql/mysql-bin |
| log_bin_index | /var/lib/mysql/mysql-bin.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)
查看当前的Binlog日志文件列表
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 724 |
| mysql-bin.000002 | 154 |
+------------------+-----------+
2 rows in set (0.00 sec)
构建数据
CREATE TABLE `t` (
`id` INT (11) NOT NULL,
`a` INT (11) DEFAULT NULL,
`t_modified` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `a` (`a`),
KEY `t_modified` (`t_modified`)
) ENGINE = INNODB;
insert into t values(1,1,'2018-11-13');
insert into t values(2,2,'2018-11-12');
insert into t values(3,3,'2018-11-11');
insert into t values(4,4,'2018-11-10');
insert into t values(5,5,'2018-11-09');
查看当前的Binlog日志文件列表
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 724 |
| mysql-bin.000002 | 2044 |
+------------------+-----------+
2 rows in set (0.00 sec)
注意:不能通过cat 直接打开binlog 文件,否则会出现乱码
cd /var/lib/mysql/mysql-bin
cat mysql-bin.000002
$ mysqlbinlog /var/lib/mysql/mysql-bin.000002
mysqlbinlog: [ERROR] unknown variable 'default-character-set=utf8'
原因是mysqlbinlog这个工具无法识别binlog中的配置中的default-character-set=utf8这个指令。
两个方法解决这个问题
在MySQL的配置**
/my.cnf
中将default-character-set=utf8
** 修改为 **character-set-server = utf8
**但是这需要重启MySQL服务,如果MySQL服务正在忙,那这样的代价会比较大。 用命令打开
mysqlbinlog --no-defaults /var/lib/mysql/mysql-bin.000002
下载文件到本地
mysqlbinlog --no-defaults /var/lib/mysql/mysql-bin.000002 > 20231114.sql
docker cp mysql:/20231114.sql ./
Binlog写入机制
MySQL 的二进制日志(binlog)不仅用于记录数据库的操作(例如增、删、改),它在事务处理、数据恢复、主从复制等方面都起着至关重要的作用。在事务执行过程中,binlog 的写入机制是保证数据一致性和持久性的重要环节。
下面详细解释了 binlog 的写入机制以及一些关键参数的作用:
1. 写入时机
当数据库执行修改数据的操作时(如 INSERT
、UPDATE
、DELETE
等),这些操作首先会被记录到 binlog 缓存(binlog cache) 中。这个缓存是每个线程独立的内存空间,用于暂存即将提交的事务日志。
- 事务提交时:当事务被提交时,binlog 缓存的内容会被一次性写入到实际的 binlog 文件中。这个过程保证了事务的日志记录是原子性的,只有在事务提交后,数据变更才会真正写入 binlog 文件中,避免了在事务失败时产生不一致的日志。
2. Binlog Cache 大小控制
MySQL 提供了 binlog_cache_size
参数来控制每个线程的 binlog 缓存大小。这个缓存存储的是待写入的事务日志。
- binlog_cache_size:如果这个缓存大小不够存储当前事务的所有日志内容,超出的部分会被暂存到磁盘的交换空间(Swap)。这样可以防止内存溢出,但会牺牲一些性能。
注意:如果
binlog_cache_size
设置得过小,可能会导致频繁的磁盘交换,影响性能;设置得过大,又可能浪费内存资源。
3. Binlog 文件刷盘流程
在 binlog 被写入时,MySQL 会先将日志数据写入内存中的 page cache,然后在适当的时机将其持久化到磁盘。这一过程有两个关键操作:
- write 操作:MySQL 将日志内容写入内存中的缓存区域(page cache)。这一操作速度较快,因为是内存操作。
- fsync 操作:将内存中的数据(page cache)刷到磁盘,这才是将数据持久化的关键步骤,保证数据在硬盘中不丢失。
具体的刷盘时机由 sync_binlog 参数来控制。
sync_binlog 参数的调整
sync_binlog
是 MySQL 用来控制 binlog 刷盘时机的重要参数。通过调整该参数,可以在 性能 和 数据安全性 之间找到平衡。
1. sync_binlog = 0
- 含义:每次提交事务时,MySQL 只进行
write
操作,至于什么时候执行fsync
操作则由操作系统自行判断。 - 优点:这种配置能提高写入性能,因为每次事务提交时不强制进行磁盘刷盘。
- 缺点:如果系统崩溃,最近的 binlog 数据可能会丢失。因为操作系统并不保证
write
操作后的数据一定会立刻刷到磁盘。
这种配置通常用于对性能要求更高、数据一致性要求相对宽松的环境,但不适用于要求严格一致性的场景。
2. sync_binlog = 1
- 含义:每次事务提交时,MySQL 都会执行一次
fsync
操作,确保日志数据立即被刷到磁盘。 - 优点:数据安全性得到极大保证,因为每个事务的日志都被强制写入磁盘,确保不会丢失。
- 缺点:会增加磁盘 I/O 开销,因此性能上可能会有所下降。适用于对数据一致性和安全性有极高要求的场景。
例如,在金融、支付等领域,数据一致性是至关重要的,因此选择 sync_binlog = 1
配置。
3. sync_binlog = N(N > 1)
- 含义:每次提交事务时,MySQL 进行
write
操作,并在累积了 N 次事务后再执行一次fsync
操作。 - 优点:在性能和数据安全性之间找到一个平衡点。适用于在 I/O 瓶颈比较明显的环境中,既要保证一定的数据安全性,又希望减少频繁的磁盘刷盘操作。
- 缺点:如果机器突然宕机,可能会丢失最近 N 次事务的 binlog 日志。
这种配置适用于大部分需要平衡性能和数据安全性的中等负载应用。
IO 瓶颈优化
在高并发的系统中,频繁的 fsync
操作可能会导致磁盘 I/O 瓶颈。此时,可以通过将 sync_binlog
设置为较大的值来减轻 I/O 压力。这样,MySQL 会在提交多次事务后才执行一次 fsync
,减少了磁盘刷盘的频率,从而提高性能。
但需要注意的是,如果机器突然宕机,设置较大值的 sync_binlog
会导致丢失最近 N 次事务的 binlog 日志。因此,在设置该参数时,需要根据实际的负载情况、系统的可靠性要求以及性能需求来做综合考虑。
Binlog 的优缺点
优点
- 数据恢复:在出现数据库故障或数据丢失时,binlog 提供了强有力的数据恢复机制。通过回放 binlog 中的操作,可以将数据库恢复到故障发生之前的状态。
- 主从复制:binlog 是 MySQL 主从复制的基础。主数据库上的 binlog 会被从数据库读取和执行,确保主从数据库的数据一致性。这是分布式系统和高可用架构的重要支撑。
- 数据审计:binlog 记录了所有数据修改操作,是数据库审计和追溯的重要工具。通过分析 binlog,可以追踪某个操作发生的具体时间和修改内容,帮助排查问题。
缺点
- 占用存储:binlog 文件会随着数据库操作的增多而不断增长,特别是在高并发的场景中,binlog 文件可能占用大量硬盘空间。为了防止磁盘空间被耗尽,需要定期清理旧的 binlog 文件。
- 性能影响:记录 binlog 会带来一定的性能开销,尤其是在高并发的数据库操作中,会对性能产生一定的影响。在极端高负载的环境下,binlog 写入可能成为性能瓶颈。
使用注意事项
- 定期清理 Binlog 文件:可以通过
expire_logs_days
参数配置 MySQL 自动清理过期的 binlog 文件,避免占用过多的磁盘空间。 - 按顺序恢复数据:在进行数据库恢复时,需要按 binlog 文件的顺序逐个应用,确保数据的一致性。如果跳过某个 binlog 文件,可能会导致数据丢失或不一致。
- 选择合适的 Binlog 格式:
STATEMENT
格式会记录 SQL 语句,适合大部分场景,但某些情况下可能导致主从数据不一致。ROW
格式会记录每一行的数据变更,适合复杂的数据库操作。MIXED
格式则结合了两者的优点,适合大多数情况。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?