MySQL 8 复制性能的增强
2024-11-15 14:22 abce 阅读(31) 评论(0) 编辑 收藏 举报
新的复制时间戳
MySQL主从复制环境,最常见的任务是确保复制确实在进行,而且主从之间没有发生错误。常用的命令是 show slave status,该命令提供了从库线程的状态信息。因此,通常需要每个从库上执行 show slave status并检查输出结果。
输出内容中,有个参数指标 "Seconds_Behind_Master"。虽然该指标完全适用于简单的主从设置,但对于更复杂的复制场景来说,该指标是不够的。Seconds_Behind_Master 指标主要有四个缺点:
1.它只报告从库与最上层主库之间的延迟
例如,在链式复制设置中,Seconds_Behind_Master 报告的是相对于原始主库的延迟,而不提供任何有关从库与其最近(即直接)主库之间延迟的信息。
2.它是相对于最上层主库的时区而言的
因此,服务器跨时区复制会导致测得的延迟被两台服务器之间的时区差抵消。
3.延迟是根据语句的执行开始时间按事件测量的
更具洞察力的测量方法是以每笔事务为单位,从事务在主库上实际提交的时间算起。
4.用于测量复制延迟的时间戳只能精确到秒
MySQL 8引入了两个新的时间戳,它们是对 “Seconds_Behind_Master ”的补充,可以避免上述问题。这些时间戳与写入二进制日志的每个事务(而不是每个事件)的全局事务标识符(GTID)相关联。GTID 是一个唯一标识符,与在主库上提交的每个事务相关联。由于与事务相关联,所有事务和所有 GTID 之间都有 1 对 1 的映射关系。
两个新的时间戳是:
· original commit timestamp (OCT):即原始提交时间戳 (OCT),当事务被写入原始主库(original master)的二进制日志时,自纪元(即 POSIX 时间/UNIX 时间/1970 年 1 月 1 日/1970-01-01T00:00:00Z)起的微秒数
· immediate commit timestamp (ICT):即时提交时间戳 (ICT),事务写入直接主库(immediate master)的二进制日志时,自纪元起的微秒数。
mysqlbinlog 的输出以两种格式显示新的时间戳:
1.微秒
2.以用户时区显示的 TIMESTAMP 格式(更易读)
# at 708 #241113 19:24:24 server id 30 end_log_pos 787 CRC32 0x0950fa02 GTID last_committed=2 sequence_number=3 rbr_only=yes original_committed_timestamp=1731497064388667 immediate_commit_timestamp=1731497064388667 transaction_length=326 /*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/; # original_commit_timestamp=1731497064388667 (2024-11-13 19:24:24.388667 CST) # immediate_commit_timestamp=1731497064388667 (2024-11-13 19:24:24.388667 CST) /*!80001 SET @@session.original_commit_timestamp=1731497064388667*//*!*/; /*!80014 SET @@session.original_server_version=80036*//*!*/; /*!80014 SET @@session.immediate_server_version=80036*//*!*/; SET @@SESSION.GTID_NEXT= 'd59173d4-a168-11ef-bb5c-005056b04cdd:7'/*!*/; # at 787 #241113 19:24:24 server id 30 end_log_pos 861 CRC32 0x2ce7b347 Query thread_id=23 exec_time=0 error_code=0 SET TIMESTAMP=1731497064/*!*/; BEGIN /*!*/; # at 861 #241113 19:24:24 server id 30 end_log_pos 912 CRC32 0xc13bf03f Rows_query # insert into a values(4),(3) # at 912 #241113 19:24:24 server id 30 end_log_pos 958 CRC32 0xdf0e13db Table_map: `abc`.`a` mapped to number 116 # has_generated_invisible_primary_key=0 # at 958 #241113 19:24:24 server id 30 end_log_pos 1003 CRC32 0x8e24a4c5 Write_rows: table id 116 flags: STMT_END_F BINLOG ' aIw0Zx0eAAAAMwAAAJADAACAABtpbnNlcnQgaW50byBhIHZhbHVlcyg0KSwoMyk/8DvB aIw0ZxMeAAAALgAAAL4DAAAAAHQAAAAAAAEAA2FiYwABYQABAwABAQEA2xMO3w== aIw0Zx4eAAAALQAAAOsDAAAAAHQAAAAAAAEAAgAB/wAEAAAAAAMAAADFpCSO '/*!*/; ### INSERT INTO `abc`.`a` ### SET ### @1=4 /* INT meta=0 nullable=1 is_null=0 */ ### INSERT INTO `abc`.`a` ### SET ### @1=3 /* INT meta=0 nullable=1 is_null=0 */ # at 1003 #241113 19:24:24 server id 30 end_log_pos 1034 CRC32 0x09af8ed0 Xid = 37 COMMIT/*!*/; SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/; DELIMITER ; # End of log file /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
Performance Schema 新增的表
MySQL 8.0 对Performance Schema添加了一些更改,从而提高了性能并增加了更多指标:
1.可以检测 server 错误
2.现在支持索引
3.为现有的Performance Schema复制状态表添加了新字段
检测 server 错误
MySQL 8 引入了五个新的汇总表,以帮助检测服务器错误。它们包括
1.events_errors_summary_by_account_by_error
2.events_errors_summary_by_host_by_error
3.events_errors_summary_by_thread_by_error
4.events_errors_summary_by_user_by_error
5.events_errors_summary_global_by_error
在上述所有表中,错误统计数据都是按错误汇总的。此外,除 events_errors_summary_global_by_error 外,每个表都存储与特定用户、主机、账户或线程有关的错误;events_errors_summary_global_by_error 包含整个服务器的错误。
表结构
每个表都包含以下字段:
+-------------------+---------------------+------+-----+---------------------+ | Field | Type | Null | Key | Default | +-------------------+---------------------+------+-----+---------------------+ | error_number | int(11) | yes | | null | | error_name | varchar(64) | yes | | null | | sql_state | varchar(5) | yes | | null | | sum_error_raised | bigint(20) unsigned | no | | null | | sum_error_handled | bigint(20) unsigned | no | | null | | first_seen | timestamp | yes | | 0000-00-00 00:00:00 | | last_seen | timestamp | yes | | 0000-00-00 00:00:00 | +-------------------+---------------------+------+-----+---------------------+
其中:
· first_seen/last_seen 列:表示出现特定错误的第一次和最后一次。
· sum_error_raised 列:抛出特定错误的发生次数。
· sum_error_handled 列:列出特定错误被处理的次数。
在 sum_error_handled 下统计/汇总了所有在存储程序中处理过的错误。同时,sum_error_raised 是所有其他已抛出但未处理的错误的次数。因此,要查看服务器上遇到特定错误的次数,我们可以执行以下操作:
查看不存在的表: >select * from abc.abce; ERROR 1146 (42S02): Table 'abc.abce' doesn't exist 查看错误表中信息: >select * from performance_schema.events_errors_summary_global_by_error where error_name = 'er_no_such_table'; +--------------+------------------+-----------+------------------+-------------------+---------------------+---------------------+ | ERROR_NUMBER | ERROR_NAME | SQL_STATE | SUM_ERROR_RAISED | SUM_ERROR_HANDLED | FIRST_SEEN | LAST_SEEN | +--------------+------------------+-----------+------------------+-------------------+---------------------+---------------------+ | 1146 | ER_NO_SUCH_TABLE | 42S02 | 1 | 0 | 2024-11-13 19:44:06 | 2024-11-13 19:44:06 | +--------------+------------------+-----------+------------------+-------------------+---------------------+---------------------+ 1 row in set (0.01 sec)
本示例查询的是全局表,但也可以从用户/主机/账户/线程各自的表中按用户/主机/账户/线程汇总检索这些错误的统计数据,以获得更精细的统计数据。
索引支持
自从在 MySQL 5.5 中加入 Performance Schema 后,该模式已增加到 93 个表,其中一些表存储了大量数据。新增的索引支持功能大大提高了 Performance Schema 的效率,从而显著提升了许多监控查询的速度。
在许多 sys Schema 查询中,都能很容易地看到索引带来的性能提升。例如,在有 1000 个空闲线程的情况下,查询 "SELECT * FROM sys.session" 从 34.70 秒下降到 1.01 秒,提高了 30 倍!
Performance Schema 中总共添加了 115 个索引。与 Information Schema 不同,Performance Schema 将数据作为存储引擎而不是临时表公开。
临时表无法公开优化器可能会使用的索引,而存储引擎却可以。对 Performance Schema 的数据访问也使用与常规表相同的(SQL)接口,因此它能受益于未来对查询优化器的改进。
现有 Performance Schema 复制状态表新增的字段
除了新的错误表,现有的 Performance Schema 表也增加了一些字段,以帮助检测和诊断多个点的延迟情况。复制流中的每个潜在延迟点都映射到自己的表中:
延迟点 |
Performance Schema 复制状态表 |
连接线程检索主库来的事务,并以丢列的方式将其加入relay log |
replication_connection_status:与主库连接的当前状态 |
协调线程读取来自relay log的事务,并调度到worker线程(如果开启了多线程复制) |
replication_applier_status_by_coordinator:协调器线程的当前状态,仅在启用 MTS 时显示信息 |
worker线程应用日志 |
replication_applier_status_by_worker: 应用从主服务器接收的事务的线程的当前状态 |
查看示例:
root@localhost (none)>select * from performance_schema.replication_connection_status\g *************************** 1. row *************************** channel_name: group_name: source_uuid: 3dc957a8-4b53-13ee-81be-055056a0cda9 thread_id: 290 service_state: on count_received_heartbeats: 12104 last_heartbeat_timestamp: 2024-11-13 20:03:49.797661 received_transaction_set: 3dc957a8-4b53-13ee-81be-055056a0cda9:90536365-92544861 last_error_number: 0 last_error_message: last_error_timestamp: 0000-00-00 00:00:00.000000 last_queued_transaction: 3dc957a8-4b53-13ee-81be-055056a0cda9:92544861 last_queued_transaction_original_commit_timestamp: 2024-11-13 20:00:49.794755 last_queued_transaction_immediate_commit_timestamp: 2024-11-13 20:00:49.794755 last_queued_transaction_start_queue_timestamp: 2024-11-13 20:00:49.795718 last_queued_transaction_end_queue_timestamp: 2024-11-13 20:00:49.804412 queueing_transaction: queueing_transaction_original_commit_timestamp: 0000-00-00 00:00:00.000000 queueing_transaction_immediate_commit_timestamp: 0000-00-00 00:00:00.000000 queueing_transaction_start_queue_timestamp: 0000-00-00 00:00:00.000000 1 row in set (0.00 sec) root@localhost (none)>select * from performance_schema.replication_applier_status_by_coordinator\g *************************** 1. row *************************** channel_name: thread_id: 291 service_state: on last_error_number: 0 last_error_message: last_error_timestamp: 0000-00-00 00:00:00.000000 last_processed_transaction: 3dc957a8-4b53-13ee-81be-055056a0cda9:92544861 last_processed_transaction_original_commit_timestamp: 2024-11-13 20:00:49.794755 last_processed_transaction_immediate_commit_timestamp: 2024-11-13 20:00:49.794755 last_processed_transaction_start_buffer_timestamp: 2024-11-13 20:00:49.795788 last_processed_transaction_end_buffer_timestamp: 2024-11-13 20:00:49.830551 processing_transaction: processing_transaction_original_commit_timestamp: 0000-00-00 00:00:00.000000 processing_transaction_immediate_commit_timestamp: 0000-00-00 00:00:00.000000 processing_transaction_start_buffer_timestamp: 0000-00-00 00:00:00.000000 1 row in set (0.00 sec) root@localhost (none)>select * from performance_schema.replication_applier_status_by_worker\g *************************** 1. row *************************** channel_name: worker_id: 1 thread_id: 292 service_state: on last_error_number: 0 last_error_message: last_error_timestamp: 0000-00-00 00:00:00.000000 last_applied_transaction: 3dc957a8-4b53-13ee-81be-055056a0cda9:92544861 last_applied_transaction_original_commit_timestamp: 2024-11-13 20:00:49.794755 last_applied_transaction_immediate_commit_timestamp: 2024-11-13 20:00:49.794755 last_applied_transaction_start_apply_timestamp: 2024-11-13 20:00:49.796949 last_applied_transaction_end_apply_timestamp: 2024-11-13 20:00:49.852644 applying_transaction: applying_transaction_original_commit_timestamp: 0000-00-00 00:00:00.000000 applying_transaction_immediate_commit_timestamp: 0000-00-00 00:00:00.000000 applying_transaction_start_apply_timestamp: 0000-00-00 00:00:00.000000 last_applied_transaction_retries_count: 0 last_applied_transaction_last_transient_error_number: 0 last_applied_transaction_last_transient_error_message: last_applied_transaction_last_transient_error_timestamp: 0000-00-00 00:00:00.000000 applying_transaction_retries_count: 0 applying_transaction_last_transient_error_number: 0 applying_transaction_last_transient_error_message: applying_transaction_last_transient_error_timestamp: 0000-00-00 00:00:00.000000 *************************** 2. row *************************** channel_name: worker_id: 2 thread_id: 295 service_state: on last_error_number: 0 last_error_message: last_error_timestamp: 0000-00-00 00:00:00.000000 last_applied_transaction: 3dc957a8-4b53-13ee-81be-055056a0cda9:92543553 last_applied_transaction_original_commit_timestamp: 2024-11-13 19:55:11.074457 last_applied_transaction_immediate_commit_timestamp: 2024-11-13 19:55:11.074457 last_applied_transaction_start_apply_timestamp: 2024-11-13 19:55:12.013437 last_applied_transaction_end_apply_timestamp: 2024-11-13 19:55:12.015771 applying_transaction: applying_transaction_original_commit_timestamp: 0000-00-00 00:00:00.000000 applying_transaction_immediate_commit_timestamp: 0000-00-00 00:00:00.000000 applying_transaction_start_apply_timestamp: 0000-00-00 00:00:00.000000 last_applied_transaction_retries_count: 0 last_applied_transaction_last_transient_error_number: 0 last_applied_transaction_last_transient_error_message: last_applied_transaction_last_transient_error_timestamp: 0000-00-00 00:00:00.000000 applying_transaction_retries_count: 0 applying_transaction_last_transient_error_number: 0 applying_transaction_last_transient_error_message: applying_transaction_last_transient_error_timestamp: 0000-00-00 00:00:00.000000 *************************** 3. row *************************** channel_name: worker_id: 3 thread_id: 296 service_state: on last_error_number: 0 last_error_message: last_error_timestamp: 0000-00-00 00:00:00.000000 last_applied_transaction: 3dc957a8-4b53-13ee-81be-055056a0cda9:92543080 last_applied_transaction_original_commit_timestamp: 2024-11-13 19:54:48.822867 last_applied_transaction_immediate_commit_timestamp: 2024-11-13 19:54:48.822867 last_applied_transaction_start_apply_timestamp: 2024-11-13 19:54:51.491876 last_applied_transaction_end_apply_timestamp: 2024-11-13 19:54:54.896176 applying_transaction: applying_transaction_original_commit_timestamp: 0000-00-00 00:00:00.000000 applying_transaction_immediate_commit_timestamp: 0000-00-00 00:00:00.000000 applying_transaction_start_apply_timestamp: 0000-00-00 00:00:00.000000 last_applied_transaction_retries_count: 0 last_applied_transaction_last_transient_error_number: 0 last_applied_transaction_last_transient_error_message: last_applied_transaction_last_transient_error_timestamp: 0000-00-00 00:00:00.000000 applying_transaction_retries_count: 0 applying_transaction_last_transient_error_number: 0 applying_transaction_last_transient_error_message: applying_transaction_last_transient_error_timestamp: 0000-00-00 00:00:00.000000 *************************** 4. row *************************** channel_name: worker_id: 4 thread_id: 297 service_state: on last_error_number: 0 last_error_message: last_error_timestamp: 0000-00-00 00:00:00.000000 last_applied_transaction: 3dc957a8-4b53-13ee-81be-055056a0cda9:92540369 last_applied_transaction_original_commit_timestamp: 2024-11-13 19:43:11.017099 last_applied_transaction_immediate_commit_timestamp: 2024-11-13 19:43:11.017099 last_applied_transaction_start_apply_timestamp: 2024-11-13 19:43:11.088638 last_applied_transaction_end_apply_timestamp: 2024-11-13 19:43:11.091951 applying_transaction: applying_transaction_original_commit_timestamp: 0000-00-00 00:00:00.000000 applying_transaction_immediate_commit_timestamp: 0000-00-00 00:00:00.000000 applying_transaction_start_apply_timestamp: 0000-00-00 00:00:00.000000 last_applied_transaction_retries_count: 0 last_applied_transaction_last_transient_error_number: 0 last_applied_transaction_last_transient_error_message: last_applied_transaction_last_transient_error_timestamp: 0000-00-00 00:00:00.000000 applying_transaction_retries_count: 0 applying_transaction_last_transient_error_number: 0 applying_transaction_last_transient_error_message: applying_transaction_last_transient_error_timestamp: 0000-00-00 00:00:00.000000 4 rows in set (0.00 sec) root@localhost (none)>
每个表中增加了九个字段,用于存储上一个事务、相应处理的线程以及该线程当前正在处理的事务的信息。这些信息包括:
· 事务的 GTID
· OCT 和 ICT(从库的中继日志中获取)
· 线程开始处理的时间
· 如果是最后处理的事务,线程完成处理的时间
复制线程之间的关系更高效
从 MySQL 8.0.1 开始,由于复制线程之间关系的改进,从库的改进将使其比以前的 MySQL 版本更高效。
MySQL 从库侧的复制核心由两个线程(有时更多)组成:
- connection :处理与主库的连接,检索事件并按队列写入 relay log。
- applier:从 relay log 中读取排队的事件,并将其应用到副本中。
旧的仲裁线程模型
由于"仲裁"的原因,当 connection 和 applier 处理同一个 relay log 时,connection 和 applier 之间的关系就会出现问题。relay log 一次只能由一个线程访问,导致复制线程相互排斥。因此,当 connection 写入 relay log 时,applier 无法读取要应用的内容,只能等待。同样,当 applier 从 relay log 中读取内容时,connection 也无法向其中写入新内容,从而进入空闲状态。
仲裁是为了防止 applier 程序将只部分写入 relay log 的事件发送给 worker 线程。虽然这种仲裁有时对资源有限的从库有益,但也限制了多线程 (MTS)复制的可扩展性。
新线程模型
从 MySQL 8.0.1 开始,applier 几乎不再阻塞 connection ,但中继日志超过其大小限制时例外。
同样,对于已经完全写入队列的事务,connection 也不会阻塞 applier。
为使这一解决方案奏效,connection 线程会不断更新上次完全假如队列的事件在 relay log 中的位置信息。applier 现在从日志中读取直到该位置,并等待 connection 线程的通知。