MariaDB 中 binlog 格式选择的策略
MariaDB 中 binlog 格式简介
在 MariaDB 数据库中,二进制日志(binlog)起着至关重要的作用。它记录了数据库的更改操作,用于数据备份、恢复以及主从复制等场景。而 binlog 有多种格式,每种格式都有其特点和适用场景。
目前 MariaDB 支持的 binlog 格式主要有以下几种:
- Statement 格式:在这种格式下,binlog 记录的是实际执行的 SQL 语句。例如,如果执行
UPDATE users SET age = age + 1 WHERE city = 'Beijing';
,binlog 就会记录这条 SQL 语句。 - Row 格式:Row 格式下,binlog 记录的是数据行的变化。假设上述
UPDATE
语句,它会记录每一行users
表中符合条件的行在更新前后的具体数据。 - Mixed 格式:这是一种混合了 Statement 和 Row 格式的方式。MariaDB 会根据具体的 SQL 语句来自动选择使用 Statement 还是 Row 格式记录到 binlog 中。
Statement 格式的特点
- 优点
- 日志量小:因为只记录 SQL 语句,相比于记录每一行数据变化的 Row 格式,日志量会显著减少。这对于存储空间有限或者网络带宽受限的场景非常友好。例如,一个批量插入 1000 条数据的
INSERT
语句,在 Statement 格式下,binlog 只需要记录这一条INSERT
语句,而在 Row 格式下,需要记录 1000 条数据行的插入信息。 - 兼容性好:对于一些不涉及数据行具体修改逻辑,只涉及数据库结构变更等操作,如
CREATE TABLE
、ALTER TABLE
等语句,Statement 格式能够很好地记录和重现。而且,这种格式对于不同版本的 MariaDB 兼容性较高,不会因为版本差异导致日志记录和回放出现问题。
- 日志量小:因为只记录 SQL 语句,相比于记录每一行数据变化的 Row 格式,日志量会显著减少。这对于存储空间有限或者网络带宽受限的场景非常友好。例如,一个批量插入 1000 条数据的
- 缺点
- 数据一致性风险:由于记录的是 SQL 语句,在主从复制场景下,如果主库和从库的环境稍有差异,比如函数版本、系统变量设置不同等,可能会导致从库执行相同的 SQL 语句得到与主库不同的结果。例如,主库和从库的时区设置不同,而 SQL 语句中又涉及到日期时间函数,就可能出现数据不一致的情况。
- 不确定性函数问题:一些具有不确定性的函数,如
NOW()
、RAND()
等,在主从复制时可能会出现问题。假设主库执行INSERT INTO logs (time) VALUES (NOW());
,记录到 binlog 中的是这条语句。当从库回放时,NOW()
函数返回的是从库当前的时间,而不是主库执行时的时间,这就导致数据不一致。
Statement 格式示例
下面通过实际的代码示例来展示 Statement 格式下 binlog 的记录情况。
首先,确保 MariaDB 配置为使用 Statement 格式。在 my.cnf
文件中添加或修改以下配置:
[mysqld]
binlog_format = STATEMENT
重启 MariaDB 服务使配置生效。
创建一个测试表并插入数据:
CREATE TABLE test_statement (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50)
);
INSERT INTO test_statement (name) VALUES ('Alice'), ('Bob');
查看 binlog 文件内容(可以使用 mysqlbinlog
工具):
mysqlbinlog /var/lib/mysql/mysql-bin.000001
在 binlog 文件中,会看到类似如下记录:
# at 4
#190920 15:22:06 server id 1 end_log_pos 123 CRC32 0x7f08567c Start: binlog v 4, server v 10.4.8-MariaDB-log created 190920 15:22:06
ROLLBACK/*!*/;
# at 123
#190920 15:22:06 server id 1 end_log_pos 219 CRC32 0x89f79c52 Query thread_id=1 exec_time=0 error_code=0
SET TIMESTAMP=1568964126/*!*/;
CREATE TABLE test_statement (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50)
)/*!*/;
# at 219
#190920 15:22:06 server id 1 end_log_pos 309 CRC32 0x2c376686 Query thread_id=1 exec_time=0 error_code=0
SET TIMESTAMP=1568964126/*!*/;
INSERT INTO test_statement (name) VALUES ('Alice'), ('Bob')/*!*/;
可以清晰地看到,binlog 记录的是实际执行的 SQL 语句。
Row 格式的特点
- 优点
- 数据一致性高:由于记录的是数据行的具体变化,在主从复制时,从库直接应用这些数据行的变化,避免了因为环境差异导致的执行结果不一致问题。无论主从库的函数版本、系统变量等如何设置,只要数据行变化记录准确,从库就能重现主库的修改。
- 适合复杂数据操作:对于一些复杂的 SQL 操作,如涉及到触发器、存储过程等对数据行进行复杂处理的场景,Row 格式能够准确记录数据的变化,确保主从复制的准确性。
- 缺点
- 日志量大:每一行数据的变化都要记录,导致 binlog 文件会迅速增大。特别是在高并发写入的场景下,大量的数据行变化记录会占用大量的存储空间,同时也会增加网络传输负担,影响主从复制的性能。
- 恢复性能影响:在进行数据恢复时,由于需要应用每一行数据的变化记录,恢复过程可能会比 Statement 格式慢。而且如果 binlog 文件过大,恢复所需的时间和资源也会相应增加。
Row 格式示例
同样,先配置 MariaDB 使用 Row 格式。在 my.cnf
文件中修改配置:
[mysqld]
binlog_format = ROW
重启 MariaDB 服务。
执行与 Statement 格式示例相同的创建表和插入数据操作:
CREATE TABLE test_row (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50)
);
INSERT INTO test_row (name) VALUES ('Charlie'), ('David');
查看 binlog 文件:
mysqlbinlog /var/lib/mysql/mysql-bin.000002
在 binlog 文件中会看到如下类似记录(这里简化展示,实际会包含更多详细的行数据变化信息):
# at 4
#190920 15:30:00 server id 1 end_log_pos 123 CRC32 0x7f08567c Start: binlog v 4, server v 10.4.8-MariaDB-log created 190920 15:30:00
ROLLBACK/*!*/;
# at 123
#190920 15:30:00 server id 1 end_log_pos 234 CRC32 0x89f79c52 Table_map: `test`.`test_row` mapped to number 123
# at 234
#190920 15:30:00 server id 1 end_log_pos 345 CRC32 0x2c376686 Write_rows: table id 123 flags: STMT_END_F
### INSERT INTO `test`.`test_row`
### SET
### @1=1 /* INT meta=0 nullable=0 is_null=0 */
### @2='Charlie' /* STRING(50) meta=50 nullable=1 is_null=0 */
# at 345
#190920 15:30:00 server id 1 end_log_pos 456 CRC32 0x3c476686 Write_rows: table id 123 flags: STMT_END_F
### INSERT INTO `test`.`test_row`
### SET
### @1=2 /* INT meta=0 nullable=0 is_null=0 */
### @2='David' /* STRING(50) meta=50 nullable=1 is_null=0 */
可以看到,binlog 详细记录了每一行数据的插入变化。
Mixed 格式的特点
- 优点
- 灵活性高:它结合了 Statement 和 Row 格式的优点,对于大部分不涉及不确定性函数和环境敏感操作的 SQL 语句,使用 Statement 格式记录,以减少日志量;而对于可能导致主从数据不一致的操作,如包含不确定性函数的语句、涉及触发器等复杂操作,自动切换到 Row 格式记录。这样既保证了一定的日志精简性,又确保了数据一致性。
- 适应性强:能够根据不同的 SQL 操作类型,动态选择最合适的记录格式,对于各种复杂的数据库应用场景都有较好的适应性。在既有简单的结构变更操作,又有复杂的数据处理操作的混合场景下,Mixed 格式能够较好地平衡日志量和数据一致性。
- 缺点
- 选择逻辑复杂:虽然 MariaDB 会自动选择记录格式,但这种选择逻辑相对复杂。对于开发和运维人员来说,在排查问题时,理解和分析 binlog 记录可能会有一定难度,因为需要同时考虑两种格式的记录特点和切换规则。
- 潜在的兼容性问题:在不同版本的 MariaDB 中,混合格式的自动选择逻辑可能会有所变化。这可能导致在版本升级或降级过程中,出现 binlog 记录和回放的兼容性问题,需要特别关注和测试。
Mixed 格式示例
配置 MariaDB 使用 Mixed 格式,在 my.cnf
文件中设置:
[mysqld]
binlog_format = MIXED
重启服务后,执行如下操作:
CREATE TABLE test_mixed (
id INT AUTO_INCREMENT PRIMARY KEY,
value INT
);
INSERT INTO test_mixed (value) VALUES (FLOOR(RAND() * 10));
查看 binlog 文件:
mysqlbinlog /var/lib/mysql/mysql-bin.000003
在 binlog 文件中,对于 CREATE TABLE
语句,可能以 Statement 格式记录:
# at 4
#190920 15:35:00 server id 1 end_log_pos 123 CRC32 0x7f08567c Start: binlog v 4, server v 10.4.8-MariaDB-log created 190920 15:35:00
ROLLBACK/*!*/;
# at 123
#190920 15:35:00 server id 1 end_log_pos 219 CRC32 0x89f79c52 Query thread_id=1 exec_time=0 error_code=0
SET TIMESTAMP=1568964900/*!*/;
CREATE TABLE test_mixed (
id INT AUTO_INCREMENT PRIMARY KEY,
value INT
)/*!*/;
而对于包含 RAND()
不确定性函数的 INSERT
语句,可能以 Row 格式记录(简化展示):
# at 219
#190920 15:35:00 server id 1 end_log_pos 324 CRC32 0x2c376686 Table_map: `test`.`test_mixed` mapped to number 124
# at 324
#190920 15:35:00 server id 1 end_log_pos 435 CRC32 0x3c476686 Write_rows: table id 124 flags: STMT_END_F
### INSERT INTO `test`.`test_mixed`
### SET
### @1=1 /* INT meta=0 nullable=0 is_null=0 */
### @2=5 /* INT meta=0 nullable=0 is_null=0 */
binlog 格式选择策略
-
考虑应用场景
- 简单业务场景:如果应用主要进行简单的增删改查操作,且对主从复制的一致性要求不是特别高,如一些小型的网站后台数据库,Statement 格式可能是一个不错的选择。它能够有效减少日志量,降低存储和网络传输压力,提高数据库的整体性能。
- 复杂业务场景:对于涉及复杂业务逻辑,如大量使用触发器、存储过程,以及对数据一致性要求极高的金融、电商等应用场景,Row 格式更为合适。虽然日志量较大,但能确保主从复制的数据准确性,避免因数据不一致导致的业务问题。
- 混合业务场景:当应用既有简单的结构变更操作,又有复杂的数据处理操作时,Mixed 格式可以很好地适应。它根据 SQL 语句的特点自动选择合适的记录格式,在保证数据一致性的同时,尽量减少日志量。
-
结合性能需求
- 性能优先:如果数据库服务器的存储空间充足,网络带宽较高,且对数据库写入性能要求极高,Row 格式可能会因为日志记录开销较大而影响性能。此时,Statement 格式或 Mixed 格式可能更有利于提高写入性能,因为它们的日志记录开销相对较小。
- 数据一致性优先:如果数据的准确性和一致性是首要考虑因素,即使在性能略有牺牲的情况下,也应选择 Row 格式或 Mixed 格式(对于可能导致不一致的操作会切换到 Row 格式)。在一些对数据质量要求严格的行业,如医疗、财务等,数据一致性的重要性远远高于性能的微小提升。
-
关注版本兼容性 在进行 binlog 格式选择时,还需要考虑 MariaDB 的版本兼容性。不同版本的 MariaDB 在 binlog 格式的实现和特性上可能会有差异。特别是在进行版本升级或降级操作时,要确保选择的 binlog 格式在目标版本中能够正常工作。例如,某些旧版本的 MariaDB 对 Mixed 格式的支持可能存在一些限制或 bug,在升级到新版本后,可能需要重新评估 binlog 格式的选择。同时,对于一些新特性相关的 binlog 格式改进,如在新版本中对 Row 格式日志压缩的优化,也可以根据实际需求进行考虑和选择。
-
监控与调整 无论选择哪种 binlog 格式,都需要对数据库进行持续的监控。通过监控 binlog 文件的大小增长速度、主从复制的延迟情况、数据库的性能指标等,来判断当前选择的 binlog 格式是否合适。如果发现 binlog 文件增长过快,导致存储空间不足,而应用对数据一致性要求并非绝对严格,可以考虑切换到 Statement 格式或调整 Mixed 格式的相关参数,减少 Row 格式记录的比例。反之,如果发现主从复制出现数据不一致问题,可能需要将 binlog 格式切换为 Row 格式或检查 Mixed 格式下自动选择逻辑是否正确。
总结 binlog 格式选择要点
在 MariaDB 中选择合适的 binlog 格式是一个综合考虑多方面因素的过程。要充分了解应用场景的特点、性能需求、版本兼容性等,通过合理的选择和持续的监控调整,确保数据库既能高效运行,又能保证数据的一致性和可靠性。同时,随着业务的发展和数据库环境的变化,可能需要适时重新评估和调整 binlog 格式,以适应新的需求。
希望通过以上对 MariaDB 中 binlog 格式的详细介绍和选择策略的分析,能帮助开发和运维人员在实际工作中做出更明智的决策,优化数据库的性能和数据管理。在实际应用中,还需要结合具体的业务场景和数据库环境进行深入的测试和验证,以确保选择的 binlog 格式能够满足长期稳定运行的需求。