压缩MySQL二进制日志(译文)

简介: 在一个繁忙的MySQL服务器上,二进制日志最终可能会成为使用磁盘空间的最大占用者之一。这意味着更高的I/O,更大的备份集(您正在备份二进制日志,对吗?)

在一个繁忙的MySQL服务器上,二进制日志最终可能会成为使用磁盘空间的最大占用者之一。这意味着更高的I/O,更大的备份集(您正在备份二进制日志,对吗?),当向从库传输二进制日志时,网络流量会增加,等等。所以长期以来一直希望有一个二进制日志压缩功能,允许对MySQL正在使用的二进制日志进行压缩。从MySQL 8.0.20开始,现在可以了。这篇文章将探讨这个新功能。

01—

配置


二进制日志压缩功能由两个变量控制,一个用于启用该功能,另一个用于指定压缩级别。

变量名称 默认值 允许值
binlog_transaction_compression OFF OFF/ON
binlog_transaction_compression_level_zstd 3 1-22


这两个变量的作用可以从它们的名称推断出来:

  • binlog_transaction_compression指定是否启用压缩,
  • binlog_transaction_compression_level_zstd指定压缩级别。原则上,高级别的压缩消耗更多的CPU。

这两个选项都可以在全局范围内和会话范围内动态设置。但是,不允许在事务中间更改。如果您这样做,您会收到这样的错误:



mysql> SET SESSION binlog_transaction_compression = ON;ERROR: 1766 (HY000): The system variable binlog_transaction_compression cannot be set when there is an ongoing transaction.

虽然配置二进制日志压缩很容易,但也需要注意一些限制。


02—

限制


关于二进制日志压缩的限制简短地说就是只压缩事务行事件。基于语句的事件、GTID信息、旋转事件、非事务表的行事件等没有压缩。此外,如果您对事务添加非事务性更改,那么两者都不会被压缩。这也意味着每笔交易都是单独压缩的。有关这意味着什么的更多信息,请参阅本文中接下来的例子。

如果您对二进制日志使用所有默认值,并使用InnoDB存储引擎(默认值),则压缩可以起作用。有关限制的完整列表,请参阅官方文档中的二进制日志事务压缩(https://dev.mysql.com/doc/refman/8.0/en/binary-log-transaction-compression.html)。正如我通常所宣扬的,监控是了解您的系统的关键。下面说明如何监控二进制日志压缩功能。

03—

监视


有两种方法可以监控二进制日志压缩功能的性能,一种是性能视图中的压缩统计,另一种是性能视图中的新增的两个阶段事件。性能视图中的binary_log_transaction_compression_stats表包括自上次重新启动MySQL(或上次截断表)以来用于压缩的统计信息。该表有与两个二进制日志相关的行,一行用于压缩事件,一行用于未压缩的事件。从库中同样将有两行用于中继日志。一个查询这个视图和二进制日志的例子是:



mysql> SELECT * FROM binary_log_transaction_compression_stats\G*************************** 1. row ***************************                            LOG_TYPE: BINARY                    COMPRESSION_TYPE: ZSTD                 TRANSACTION_COUNTER: 15321            COMPRESSED_BYTES_COUNTER: 102796461          UNCOMPRESSED_BYTES_COUNTER: 252705572              COMPRESSION_PERCENTAGE: 59                FIRST_TRANSACTION_ID: 74470a0c-8ea4-11ea-966e-080027effed8:30730  FIRST_TRANSACTION_COMPRESSED_BYTES: 313FIRST_TRANSACTION_UNCOMPRESSED_BYTES: 363         FIRST_TRANSACTION_TIMESTAMP: 2020-05-07 19:26:37.744437                 LAST_TRANSACTION_ID: 74470a0c-8ea4-11ea-966e-080027effed8:46058   LAST_TRANSACTION_COMPRESSED_BYTES: 712 LAST_TRANSACTION_UNCOMPRESSED_BYTES: 1627          LAST_TRANSACTION_TIMESTAMP: 2020-05-07 19:38:14.149782*************************** 2. row ***************************                            LOG_TYPE: BINARY                    COMPRESSION_TYPE: NONE                 TRANSACTION_COUNTER: 20            COMPRESSED_BYTES_COUNTER: 5351          UNCOMPRESSED_BYTES_COUNTER: 5351              COMPRESSION_PERCENTAGE: 0                FIRST_TRANSACTION_ID: 74470a0c-8ea4-11ea-966e-080027effed8:30718  FIRST_TRANSACTION_COMPRESSED_BYTES: 116FIRST_TRANSACTION_UNCOMPRESSED_BYTES: 116         FIRST_TRANSACTION_TIMESTAMP: 2020-05-07 19:26:37.508155                 LAST_TRANSACTION_ID: 74470a0c-8ea4-11ea-966e-080027effed8:31058   LAST_TRANSACTION_COMPRESSED_BYTES: 116 LAST_TRANSACTION_UNCOMPRESSED_BYTES: 116          LAST_TRANSACTION_TIMESTAMP: 2020-05-07 19:30:30.8407672 rows in set (0.0026 sec) mysql> SHOW BINARY LOGS;+---------------+-----------+-----------+| Log_name      | File_size | Encrypted |+---------------+-----------+-----------+| binlog.000142 |       240 | No        || binlog.000143 |      4933 | No        || binlog.000144 |  28238118 | No        || binlog.000145 |  24667167 | No        || binlog.000146 |  39221771 | No        || binlog.000147 |  11944631 | No        || binlog.000148 |       196 | No        |+---------------+-----------+-----------+7 rows in set (0.0005 sec)

该示例是在启用GTID的情况下生成的,除了binlog.000142,所有二进制日志都是在上次重新启动后创建的。这表明有15341个事务(74470a0c-8ea4-11ea-966e-080027effed8:30718-46058),其中15321个事务被压缩,平均压缩率是59%(将252,705,572字节压缩为102,796,461字节)。还有第一个和最近一次被压缩的事务的统计数据,也有20个事务无法压缩。另外一件事是要知道是在进行压缩和解压方面付出的代价。这可以使用性能模式中的两个阶段事件进行监控:

  • stage/sql/Compressing transaction changes.
  • stage/sql/Decompressing transaction changes. (是的,英文句号是名称的一部分。)


默认情况下,两者都不启用,要收集这些性能计量,您还需要启用events_stages_current消费者。例如,要在配置文件中启用这些配置参数:



[mysqld]performance-schema-instrument = "stage/sql/%Compressing transaction changes.=ON"performance-schema-consumer-events-stages-current = ON

需要注意,启用这些阶段计量会产生一些开销。如果您考虑在生产系统上启用这些影响,请确保首先测试影响。您可以将这两个阶段计量信息与wait/io/file/sql/binlog事件(默认启用)进行比较,后者是花在做I/O上的时间。例如:




mysql> SELECT EVENT_NAME, COUNT_STAR,              FORMAT_PICO_TIME(SUM_TIMER_WAIT) AS total_latency,              FORMAT_PICO_TIME(MIN_TIMER_WAIT) AS min_latency,              FORMAT_PICO_TIME(AVG_TIMER_WAIT) AS avg_latency,              FORMAT_PICO_TIME(MAX_TIMER_WAIT) AS max_latency         FROM performance_schema.events_stages_summary_global_by_event_name        WHERE EVENT_NAME LIKE 'stage/sql/%transaction changes.'\G*************************** 1. row ***************************   EVENT_NAME: stage/sql/Compressing transaction changes.   COUNT_STAR: 15321total_latency: 6.10 s  min_latency: 22.00 ns  avg_latency: 397.96 us  max_latency: 982.12 ms*************************** 2. row ***************************   EVENT_NAME: stage/sql/Decompressing transaction changes.   COUNT_STAR: 0total_latency:   0 ps  min_latency:   0 ps  avg_latency:   0 ps  max_latency:   0 ps2 rows in set (0.0008 sec) mysql> SELECT *         FROM sys.io_global_by_wait_by_latency        WHERE event_name = 'sql/binlog'\G*************************** 1. row ***************************   event_name: sql/binlog        total: 27537total_latency: 4.83 min  avg_latency: 10.51 ms  max_latency: 723.92 ms read_latency: 138.25 uswrite_latency: 290.69 ms misc_latency: 4.82 min   count_read: 37   total_read: 1002 bytes     avg_read:   27 bytes  count_write: 16489total_written: 99.26 MiB  avg_written: 6.16 KiB1 row in set (0.0015 sec)

这里sys视图输出的数据已经自动转换为人类可读的格式,而性能视图中的时间使用FORMAT_PICO_TIME()函数进行转换。在本例中,MySQL总计花了6.21秒进行二进制日志的压缩,每笔事务平均略低于400微秒。相比之下,MySQL总计花了4.8分钟在二进制日志文件上做I/O,这说明压缩在写日志的时间中占比很低。在启用压缩之前,您应该检查写入和读取二进制日志文件所花费的时间,以便确定性能的变化。您还应该检查CPU使用情况的变化。在上面的输出中,它显示压缩率为59%,但对于不同类型的工作负载来说,压缩率如何?

04—

示例 – 工作负载为了测量压缩的效果,我运行了一系列任务,并比较了压缩或不压缩的二进制日志的大小。为了比较,我还尝试手动压缩这些测试中未压缩的二进制日志,以查看最佳压缩效果(而不是MySQL使用的每笔事务压缩)。除了必要的设置外,测试采用默认的配置。已经测试了以下工作负载:

  • 批量加载:加载employees示例数据库。
  • 批量更新:更新employees.salaries中所有行salary列:UPDATE employees.salaries SET salary = salary + 1
  • 批量加载:使用sysbench填充四个10万行的表,为oltp_read_write基准测试做准备。
  • OLTP 工作负载:使用前面创建的4个表,用 sysbench运行oltp_read_write基准测试,选项 --events=15000。
  • 单行删除:从sysbench测试中删除其中一个表中的所有10万行。这些行逐一删除,这是压缩的最坏情况,因为事务非常小,并且每个已删除行的二进制日志中只有前镜像。

使用MySQL Shell可以轻松执行单行删除,例如在Python语言模式下:



from datetime import datetime for i in range(100000):    if i % 5000 == 0:        print('{0}: i = {1}'.format(datetime.now(), i))    session.run_sql('DELETE FROM sbtest.sbtest1 WHERE id = {0}'.format(i+1))print('{0}: i = 1000000'.format(datetime.now()))

每个任务的大小生成25 MiB至82 MiB范围内的未压缩二进制日志。测试使用以下设置进行:

  • 没有压缩
  • 启用压缩
  • 加密但未压缩
  • 启用加密和压缩
  • MySQL中没有压缩,手动使用zstd进行压缩

选择zstd的压缩,因为MySQL使用Zstandard压缩算法。如果您想自己尝试,您可以从Facebook的GitHub存储库下载Zstandard源代码,其中还包括编译说明。下表列出了每个组合生成的二进制日志字节大小。

测试 标准 压缩 加密 加密+压缩 zstd
加载employees表 66378639 28237933 66379151 28238634 26892387
批量更新 85698320 24667051 85698832 24667677 24779953
sysbench准备 76367740 39221052 39221052 39221806 39775067
sysbench运行 26190200 11933713 26190712 11936561 8468625
单行删除 47300156 39492400 47300668 39637684 16525219

分析加密和压缩的数据,可以推断出加密是压缩后完成,因为加密后数据压缩效果不佳。由于启用加密对压缩的效果影响不大,因此将只讨论正常(未压缩)、压缩和zstd结果。二进制日志大小也可以在下图中看到:测试的结果并不让人吃惊,批量加载和批量更新的二进制压缩效果分别是51%和29%,sysbench OLTP压缩是46%,单行删除压缩是83%,比使用zstd压缩效果差很多。当将MySQL压缩的二进制日志与手动使用zstd压缩的二进制日志进行比较时,发现批量负载的文件大小大致相同,这说明对于大型事务,对每笔事务压缩和对整个文件压缩效果一样。随着事务大小变小,每笔事务压缩的相对效率降低,这对单行删除尤为明显。需要考虑的另一个因素是压缩级别。05—

示例 – 压缩级别


关于压缩级别有一些奇怪之处,为读者省事的说法是没有必要修改默认设置。第一个奇怪的是,允许的值是1-22,但zstd只支持1-19级。MySQL文档中没有任何内容可以解释差异。第二个奇怪的是,通过更改binlog_transaction_compression_level_zstd的值,压缩二进制日志的大小实际上不会发生变化,这可以从表中看到:

测试压缩级别 MySQL加载 MySQL OLTP zstd 加载 zstd OLTP
1 28238142 11935450 34483207 8531545
3 28237933 11933713 26892387 8468625
11 28238128 11902669 24737194 6639524
19 28238246 11937664 18867187 5724300
22 28238125 11910022

  • 加载是加载employees数据库。
  • OLTP是使用sysbench进行oltp_read_write基准测试。

为了比较,1、3、11和19级的压缩包括使用zstd手动压缩二进制日志。数据也可以在下图中看到:从图中可以看到,无论MySQL中使用的哪种压缩级别,文件大小基本上都没有差异;而对于zstd,文件大小会随着压缩级别的增加而正常减少。对于加载测试的1级,MySQL的压缩甚至明显优于zstd,看起来就像在MySQL中从未设置压缩级别一样。一个可能的解释是,Zstandard对给定类型的数据进行算法训练(创建字典),这尤其有助于改善小数据的压缩(应为改善大数据的压缩—译者注)。我不知道MySQL是否使用字典,如果是的话,是否使所有压缩级别的效果大致相等。

06—

结论


新的二进制日志事务压缩效果很好,可以成为减少I/O、磁盘使用量和网络使用量的好方法,建议您考虑启用它。除非您的CPU资源非常紧张,否则您很可能会从启用二进制日志压缩中受益。从这些测试中,二进制日志占用的磁盘空间可能大致减少一半。但实际情况还要看您的工作负载,您应该使用工作负载进行测试。建议:您还可以启用二进制日志传输压缩,但没有理由同时启用二进制日志事务压缩和传输压缩。另外,目前没有理由改变压缩级别。

相关文章
|
Ubuntu 关系型数据库 MySQL
MySQL二进制包安装
本文详细介绍了在多种Linux系统上通过二进制包安装MySQL 8.0和8.4版本的完整过程,涵盖用户创建、glibc版本匹配、程序解压、环境变量配置、初始化数据库及服务启动等步骤,并提供支持多发行版的一键安装脚本,助力高效部署MySQL环境。
2142 4
MySQL二进制包安装
|
SQL 运维 关系型数据库
深入探讨MySQL的二进制日志(binlog)选项
总结而言,对MySQL binlogs深度理解并妥善配置对数据库运维管理至关重要;它不仅关系到系统性能优化也是实现高可靠性架构设计必须考虑因素之一。通过精心规划与周密部署可以使得该机能充分发挥作用而避免潜在风险带来影响。
436 6
|
SQL 监控 关系型数据库
MySQL日志分析:binlog、redolog、undolog三大日志的深度探讨。
数据库管理其实和写小说一样,需要规划,需要修订,也需要有能力回滚。理解这些日志的作用与优化,就像把握写作工具的使用与运用,为我们的数据库保驾护航。
1138 23
|
SQL 运维 关系型数据库
MySQL Binlog 日志查看方法及查看内容解析
本文介绍了 MySQL 的 Binlog(二进制日志)功能及其使用方法。Binlog 记录了数据库的所有数据变更操作,如 INSERT、UPDATE 和 DELETE,对数据恢复、主从复制和审计至关重要。文章详细说明了如何开启 Binlog 功能、查看当前日志文件及内容,并解析了常见的事件类型,包括 Format_desc、Query、Table_map、Write_rows、Update_rows 和 Delete_rows 等,帮助用户掌握数据库变化历史,提升维护和排障能力。
|
Oracle 关系型数据库 MySQL
Oracle linux 8 二进制安装 MySQL 8.4企业版
Oracle linux 8 二进制安装 MySQL 8.4企业版
738 1
|
存储 SQL 关系型数据库
mysql的undo log、redo log、bin log、buffer pool
MySQL的undo log、redo log、bin log和buffer pool是确保数据库高效、安全和可靠运行的关键组件。理解这些组件的工作原理和作用,对于优化数据库性能和保障数据安全具有重要意义。通过适当的配置和优化,可以显著提升MySQL的运行效率和数据可靠性。
522 16
|
存储 SQL 关系型数据库
mysql的undo log、redo log、bin log、buffer pool
MySQL的undo log、redo log、bin log和buffer pool是确保数据库高效、安全和可靠运行的关键组件。理解这些组件的工作原理和作用,对于优化数据库性能和保障数据安全具有重要意义。通过适当的配置和优化,可以显著提升MySQL的运行效率和数据可靠性。
351 4
|
SQL 存储 关系型数据库
简单聊聊MySQL的三大日志(Redo Log、Binlog和Undo Log)各有什么区别
在MySQL数据库管理中,理解Redo Log(重做日志)、Binlog(二进制日志)和Undo Log(回滚日志)至关重要。Redo Log确保数据持久性和崩溃恢复;Binlog用于主从复制和数据恢复,记录逻辑操作;Undo Log支持事务的原子性和隔离性,实现回滚与MVCC。三者协同工作,保障事务ACID特性。文章还详细解析了日志写入流程及可能的异常情况,帮助深入理解数据库日志机制。
2226 0
|
缓存 关系型数据库 BI
使用MYSQL Report分析数据库性能(下)
使用MYSQL Report分析数据库性能
743 158
|
关系型数据库 MySQL 数据库
自建数据库如何迁移至RDS MySQL实例
数据库迁移是一项复杂且耗时的工程,需考虑数据安全、完整性及业务中断影响。使用阿里云数据传输服务DTS,可快速、平滑完成迁移任务,将应用停机时间降至分钟级。您还可通过全量备份自建数据库并恢复至RDS MySQL实例,实现间接迁移上云。

推荐镜像

更多