`Performance Schema`的`底层`架构:`事件`、`线程`和`仪表`的`监控`体系`。

MySQL Performance Schema 底层架构深度解析:事件、线程与仪表盘的监控体系

大家好,今天我们来深入探讨 MySQL Performance Schema 的底层架构,重点关注其事件、线程和仪表盘的监控体系。Performance Schema 是 MySQL 提供的一个强大的性能监控工具,它能够帮助我们深入了解 MySQL 服务器内部的运行状态,从而更好地进行性能优化和故障排查。理解它的底层架构是有效利用它的关键。

1. Performance Schema 的核心概念

Performance Schema 的核心在于监控 MySQL 服务器内部发生的各种事件。为了更好地理解这些事件,我们需要了解几个关键概念:

  • 事件(Event): Performance Schema 监控的最小单位,代表 MySQL 服务器内部发生的某个操作或活动,例如函数调用、等待锁、SQL语句执行等。
  • 线程(Thread): MySQL 服务器中的工作单元,负责处理客户端请求。Performance Schema 可以追踪每个线程发生的事件。
  • 仪表(Instrument): Performance Schema 用来衡量特定事件类型的性能指标。每个仪表都关联着一组事件,并提供关于这些事件的统计信息。
  • 消费者(Consumer): Performance Schema 将收集到的事件数据写入不同的存储位置,这些存储位置被称为消费者。常见的消费者包括内存表和文件。

2. 事件的产生与收集

Performance Schema 的核心任务是收集 MySQL 服务器内部发生的各种事件。这些事件可以分为多种类型,例如:

  • 函数事件: 记录 MySQL 函数的调用情况,包括函数名称、调用时间、执行时间等。
  • 等待事件: 记录线程等待资源的情况,例如等待锁、等待 I/O 完成等。
  • SQL 事件: 记录 SQL 语句的执行情况,包括 SQL 语句内容、执行时间、影响的行数等。
  • 阶段事件: 记录SQL语句的执行阶段,例如preparing、executing等等。

为了收集这些事件,Performance Schema 在 MySQL 服务器的代码中插入了大量的监控点。当某个事件发生时,相应的监控点会被触发,并将事件信息记录下来。

事件收集流程:

  1. 事件发生: MySQL 服务器内部执行某个操作,例如调用函数、等待锁等。
  2. 监控点触发: 与该操作相关的监控点被触发。
  3. 事件记录: 监控点将事件信息记录到内存中的缓冲区。
  4. 事件写入: Performance Schema 将缓冲区中的事件数据写入到相应的消费者(例如内存表)。

代码示例(简化):

// 假设这是一个 MySQL 函数的实现
int my_function(int arg) {
  // 触发 Performance Schema 的函数开始事件
  PERF_SCHEMA_INSTRUMENT_ENTER(my_function);

  // 函数的具体实现
  int result = arg * 2;

  // 触发 Performance Schema 的函数结束事件
  PERF_SCHEMA_INSTRUMENT_EXIT(my_function);

  return result;
}

// PERF_SCHEMA_INSTRUMENT_ENTER 和 PERF_SCHEMA_INSTRUMENT_EXIT
// 是一些宏或函数,用于记录事件的开始和结束时间

上面的代码示例展示了 Performance Schema 如何在 MySQL 函数的实现中插入监控点。 PERF_SCHEMA_INSTRUMENT_ENTERPERF_SCHEMA_INSTRUMENT_EXIT 宏或函数负责记录函数调用事件的开始和结束时间。

3. 线程与事件关联

Performance Schema 的一个重要功能是将事件与线程关联起来。通过跟踪每个线程发生的事件,我们可以了解每个线程的性能瓶颈,并找出导致性能问题的根源。

线程与事件的关联方式:

Performance Schema 使用线程 ID(thread ID)将事件与线程关联起来。每个线程都有一个唯一的线程 ID,Performance Schema 在记录事件时会将线程 ID 记录下来。

代码示例:

// 假设这是 Performance Schema 记录事件的函数
void record_event(event_type type, thread_id id, timestamp start_time, timestamp end_time) {
  // 将事件信息写入到内存缓冲区
  event_buffer.push_back({type, id, start_time, end_time});
}

上面的代码示例展示了 Performance Schema 如何记录事件信息,其中包括事件类型、线程 ID、开始时间和结束时间。

4. 仪表的统计与展示

仪表是 Performance Schema 用来衡量特定事件类型的性能指标。每个仪表都关联着一组事件,并提供关于这些事件的统计信息,例如事件数量、总执行时间、平均执行时间等。

仪表的工作原理:

  1. 事件分组: Performance Schema 将事件按照事件类型和仪表进行分组。
  2. 统计计算: Performance Schema 对每个仪表关联的事件进行统计计算,例如计算事件数量、总执行时间、平均执行时间等。
  3. 数据存储: Performance Schema 将统计结果存储到相应的消费者(例如内存表)。

常见的仪表类型:

  • 函数仪表: 统计函数调用的性能指标。
  • 等待仪表: 统计线程等待资源的性能指标。
  • SQL 仪表: 统计 SQL 语句执行的性能指标。

代码示例:

// 假设这是 Performance Schema 计算函数仪表统计信息的函数
void calculate_function_instrument_stats(instrument_id id) {
  // 获取与该仪表关联的事件列表
  std::vector<event> events = get_events_by_instrument(id);

  // 计算事件数量
  int event_count = events.size();

  // 计算总执行时间
  long long total_execution_time = 0;
  for (const auto& event : events) {
    total_execution_time += event.end_time - event.start_time;
  }

  // 计算平均执行时间
  double average_execution_time = (double)total_execution_time / event_count;

  // 将统计结果存储到内存表
  store_instrument_stats(id, event_count, total_execution_time, average_execution_time);
}

上面的代码示例展示了 Performance Schema 如何计算函数仪表的统计信息,包括事件数量、总执行时间和平均执行时间。

5. 消费者的选择与配置

Performance Schema 将收集到的事件数据写入不同的存储位置,这些存储位置被称为消费者。常见的消费者包括内存表和文件。

内存表消费者:

  • 优点: 访问速度快,适合实时监控。
  • 缺点: 占用内存,数据易丢失。

文件消费者:

  • 优点: 数据持久化,适合历史分析。
  • 缺点: 访问速度慢,不适合实时监控。

消费者的配置:

可以通过 MySQL 的配置文件或 SQL 命令来配置 Performance Schema 的消费者。例如,可以使用以下 SQL 命令来启用或禁用某个消费者:

-- 启用 events_waits_history_long 消费者
UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'events_waits_history_long';

-- 禁用 events_waits_history_long 消费者
UPDATE performance_schema.setup_consumers SET ENABLED = 'NO' WHERE NAME = 'events_waits_history_long';

选择消费者的原则:

  • 对于需要实时监控的数据,应选择内存表消费者。
  • 对于需要长期保存的数据,应选择文件消费者。
  • 可以根据实际需求选择多个消费者,并将数据写入不同的存储位置。

6. Performance Schema 的使用示例

了解了 Performance Schema 的底层架构后,我们来看几个使用示例,展示如何利用 Performance Schema 进行性能分析和故障排查。

示例 1:查找慢查询

SELECT
    DIGEST_TEXT,
    COUNT(*),
    AVG(TIMER_WAIT) AS avg_latency,
    SUM(TIMER_WAIT) AS total_latency,
    SUM(LOCK_TIME) AS total_lock_time,
    SUM(ROWS_SENT) AS total_rows_sent,
    SUM(ROWS_EXAMINED) AS total_rows_examined,
    MAX(LAST_SEEN) AS last_seen
FROM performance_schema.events_statements_summary_by_digest
ORDER BY avg_latency DESC
LIMIT 10;

这个查询语句从 events_statements_summary_by_digest 表中获取 SQL 语句的摘要信息,并按照平均执行时间进行排序,找出执行时间最长的 SQL 语句。

表结构说明:

列名 数据类型 描述
DIGEST_TEXT VARCHAR(256) SQL 语句的规范化形式,用于聚合相似的查询。
COUNT(*) BIGINT 具有相同 DIGEST_TEXT 的 SQL 语句的执行次数。
avg_latency BIGINT 具有相同 DIGEST_TEXT 的 SQL 语句的平均执行时间(TIMER_WAIT 的平均值)。单位通常是皮秒。
total_latency BIGINT 具有相同 DIGEST_TEXT 的 SQL 语句的总执行时间(TIMER_WAIT 的总和)。单位通常是皮秒。
total_lock_time BIGINT 具有相同 DIGEST_TEXT 的 SQL 语句的总锁等待时间。单位通常是皮秒。
total_rows_sent BIGINT 具有相同 DIGEST_TEXT 的 SQL 语句发送的总行数。
total_rows_examined BIGINT 具有相同 DIGEST_TEXT 的 SQL 语句检查的总行数。
last_seen TIMESTAMP 具有相同 DIGEST_TEXT 的 SQL 语句最后一次执行的时间。

示例 2:查找锁等待

SELECT
    event_name,
    COUNT(*),
    SUM(timer_wait) AS total_latency,
    AVG(timer_wait) AS avg_latency
FROM performance_schema.events_waits_summary_global_by_event_name
WHERE event_name LIKE 'wait/lock/%'
ORDER BY total_latency DESC
LIMIT 10;

这个查询语句从 events_waits_summary_global_by_event_name 表中获取全局锁等待事件的统计信息,并按照总等待时间进行排序,找出等待时间最长的锁。

表结构说明:

列名 数据类型 描述
event_name VARCHAR(128) 等待事件的名称,例如 ‘wait/lock/table/sql/handler’。
COUNT(*) BIGINT 该等待事件发生的总次数。
total_latency BIGINT 该等待事件的总等待时间。单位通常是皮秒。
avg_latency BIGINT 该等待事件的平均等待时间。单位通常是皮秒。

示例 3:分析 IO 等待

SELECT
    FILE_NAME,
    EVENT_NAME,
    COUNT_STAR,
    SUM_TIMER_WAIT,
    AVG_TIMER_WAIT
FROM performance_schema.file_summary_by_event_name
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 10;

这个查询语句从 file_summary_by_event_name 表中获取文件 I/O 事件的统计信息,并按照总等待时间进行排序,找出 I/O 等待时间最长的文件。

表结构说明:

列名 数据类型 描述
FILE_NAME VARCHAR(64) 受影响的文件的名称或标识符。
EVENT_NAME VARCHAR(128) 与文件操作相关的事件的名称,例如 ‘wait/io/file/sql/data’ (数据文件 I/O 等待) 或 ‘wait/io/file/sql/log’ (日志文件 I/O 等待)。
COUNT_STAR BIGINT 该事件(与特定文件相关)发生的总次数。
SUM_TIMER_WAIT BIGINT 该事件(与特定文件相关)的总等待时间。单位通常是皮秒。
AVG_TIMER_WAIT BIGINT 该事件(与特定文件相关)的平均等待时间。单位通常是皮秒。

通过以上示例,我们可以看到 Performance Schema 提供了丰富的性能监控数据,可以帮助我们深入了解 MySQL 服务器的运行状态,并找出性能瓶颈。

7. Performance Schema 的配置与优化

虽然 Performance Schema 提供了强大的性能监控功能,但它也会带来一定的性能开销。因此,我们需要合理配置和优化 Performance Schema,以降低其对 MySQL 服务器性能的影响。

配置原则:

  • 只启用需要的仪表: Performance Schema 默认情况下会启用所有的仪表,这会带来很大的性能开销。我们应该只启用我们需要监控的仪表,禁用不需要的仪表。
  • 合理选择消费者: 根据实际需求选择合适的消费者,避免不必要的数据写入。
  • 调整缓冲区大小: Performance Schema 使用内存缓冲区来存储事件数据。我们可以调整缓冲区的大小,以平衡内存占用和性能。

优化技巧:

  • 使用过滤条件: 在查询 Performance Schema 的数据时,可以使用过滤条件来减少数据量,提高查询效率。
  • 定期清理数据: Performance Schema 的数据会占用大量的存储空间。我们可以定期清理过期的数据,以释放存储空间。
  • 监控 Performance Schema 自身的性能: Performance Schema 也会消耗 CPU 和内存资源。我们可以监控 Performance Schema 自身的性能,以确保其不会成为性能瓶颈。

配置示例:

-- 禁用所有仪表
UPDATE performance_schema.setup_instruments SET ENABLED = 'NO', TIMED = 'NO';

-- 启用函数仪表
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME LIKE 'instrument/function/%';

-- 调整事件缓冲区大小
SET GLOBAL performance_schema_events_stages_history_size = 100;

8. 深入理解 Performance Schema 的内部表结构

Performance Schema 提供了大量的表,用于存储各种性能监控数据。理解这些表的结构对于有效地使用 Performance Schema 至关重要。以下是一些常见的 Performance Schema 表及其用途:

  • setup_instruments: 配置哪些 instrument(例如函数,锁,SQL语句)需要被监控。
  • setup_consumers: 配置哪些 consumer(例如内存表,文件)用于存储监控数据。
  • events_statements_current: 包含当前正在执行的SQL语句的信息。
  • events_statements_history: 包含最近完成的SQL语句的信息(短历史)。
  • events_statements_history_long: 包含最近完成的SQL语句的更长历史记录。
  • events_statements_summary_by_digest: 按照 SQL 语句的摘要(DIGEST)聚合的统计信息。
  • events_waits_current: 包含当前正在发生的等待事件的信息。
  • events_waits_history: 包含最近发生的等待事件的信息(短历史)。
  • events_waits_history_long: 包含最近发生的等待事件的更长历史记录。
  • events_waits_summary_global_by_event_name: 按照事件名称聚合的全局等待事件统计信息。
  • file_summary_by_event_name: 按照事件名称聚合的文件 I/O 统计信息。
  • threads: 包含关于每个线程的信息,包括线程 ID、名称、类型等。

理解这些表的结构和用途,可以帮助我们更有效地查询和分析 Performance Schema 的数据,从而更好地进行性能优化和故障排查。

总结

Performance Schema 是 MySQL 提供的一个强大的性能监控工具,它通过收集和分析 MySQL 服务器内部发生的各种事件,帮助我们深入了解 MySQL 服务器的运行状态。理解 Performance Schema 的底层架构,包括事件的产生与收集、线程与事件的关联、仪表的统计与展示、消费者的选择与配置,以及 Performance Schema 的配置与优化,对于有效地利用 Performance Schema 至关重要。通过合理配置和使用 Performance Schema,我们可以更好地进行性能优化和故障排查,从而提高 MySQL 服务器的性能和稳定性。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注