一个常见问题是实例占用大量内存或内存不足 (OOM) 问题。运行内存利用率高的数据库实例通常会导致性能问题、停滞,甚至数据库停机。
某些 MySQL 内存块在全球范围内使用。这意味着所有查询工作负载共享内存位置,始终被占用,并且仅在 MySQL 进程停止时释放。某些内存块基于会话,这意味着一旦会话关闭,该会话使用的内存就会释放回系统。
每当 Cloud SQL for MySQL 实例的内存用量较高时,Cloud SQL 会建议您找出使用大量内存的查询或进程并释放内存。MySQL 内存消耗分为三个主要部分:
- 线程和进程内存消耗
- 缓冲区内存消耗
- 缓存消耗
线程和进程内存消耗
每个用户会话都会消耗内存,具体取决于正在运行的查询、缓冲区或该会话使用的缓存,并且由 MySQL 的会话参数控制。主要参数包括:
thread_stack
net_buffer_length
read_buffer_size
read_rnd_buffer_size
sort_buffer_size
join_buffer_size
max_heap_table_size
tmp_table_size
如果在特定时间运行 N 个查询,则每个查询会在会话期间按照这些参数消耗内存。
缓冲区内存消耗
这部分内存在所有查询中都是通用的,由 Innodb_buffer_pool_size
、Innodb_log_buffer_size
和 key_buffer_size
等参数控制。
缓存消耗
缓存包括查询缓存,用于保存查询及其结果,以便更快地检索相同后续查询的数据。它还包含 binlog
缓存,用于在事务运行时保存对二进制日志所做的更改,并由 binlog_cache_size
控制。
其他内存消耗
联接和排序操作也会使用内存。如果您的查询使用联接或排序操作,则这些查询将基于 join_buffer_size
和 sort_buffer_size
使用内存。
除此之外,如果启用了性能架构,它也会占用内存。如需按性能架构检查内存用量,请使用以下查询:
SELECT *
FROM
performance_schema.memory_summary_global_by_event_name
WHERE EVENT_NAME LIKE 'memory/performance_schema/%';
MySQL 中有许多工具供您设置,以用于监控性能架构的内存用量。如需了解详情,请参阅 MySQL 文档。
用于批量插入数据的 MyISAM 相关参数为 bulk_insert_buffer_size
。
如需了解 MySQL 如何使用内存,请参阅 MySQL 文档。
建议
使用 Metrics Explorer 确定内存用量
您可以使用 Metrics Explorer 中的 database/memory/components.usage
指标查看实例的内存用量。
如果 database/memory/components.cache
和 database/memory/components.free
的内存总计不足 5%,则发生 OOM 事件的风险较高。如需监控内存用量并防止 OOM 事件,我们建议您设置提醒政策,并在 database/memory/components.usage
中将指标阈值条件设置为 95% 或更高。
下表显示了实例内存与建议的提醒阈值之间的关系:
实例内存 | 建议的提醒阈值 |
---|---|
100 GB 及以下 | 95% |
100 GB 到 200 GB | 96% |
200 GB 到 300 GB | 97% |
超过 300 GB | 98% |
计算内存消耗
计算 MySQL 数据库的内存使用量上限,以便为 MySQL 数据库选择适当的实例类型。使用以下公式:
MySQL 内存使用量上限 = innodb_buffer_pool_size
+ innodb_additional_mem_pool_size
+ innodb_log_buffer_size
+ tmp_table_size
+ key_buffer_size
+ ((read_buffer_size
+ read_rnd_buffer_size
+ sort_buffer_size
+ join_buffer_size
) x max_connections
)
以下是公式中使用的参数:
innodb_buffer_pool_size
:缓冲池的大小(以字节为单位),即 InnoDB 缓存表和索引数据的内存区域。innodb_additional_mem_pool_size
:InnoDB 用于存储数据字典信息和其他内部数据结构的内存池的大小(以字节为单位)。innodb_log_buffer_size
:InnoDB 用于写入磁盘上的日志文件的缓冲区大小(以字节为单位)。tmp_table_size
:MEMORY 存储引擎和 TempTable 存储引擎(从 MySQL 8.0.28 开始)创建的内部内存临时表的大小上限。Key_buffer_size
:用于索引块的缓冲区大小。MyISAM 表的索引块已缓冲,并由所有线程共享。Read_buffer_size
:对 MyISAM 表执行依序扫描的每个线程都会为其扫描的每个表分配一个此大小(以字节为单位)的缓冲区。Read_rnd_buffer_size
:此变量用于 MyISAM 表读取、任何存储引擎以及多范围读取优化。Sort_buffer_size
:必须执行排序的每个会话分配一个该大小的缓冲区。sort_buffer_size 不特定于任何存储引擎,并且以一般方式应用于优化。Join_buffer_size
:用于普通索引扫描、范围索引扫描,以及不使用索引并因此执行全表扫描的联接的缓冲区的最小大小。Max_connections
:允许的最大并行客户端连接数。
排查高内存消耗问题
运行
SHOW PROCESSLIST
可查看当前正在消耗内存的查询。它会显示所有连接的线程及其当前运行的 SQL 语句,并尝试对其进行优化。注意状态列和时长列。mysql> SHOW [FULL] PROCESSLIST;
检查
BUFFER POOL AND MEMORY
部分中的SHOW ENGINE INNODB STATUS
以查看当前缓冲区池和内存用量,这有助于您设置缓冲区池大小。mysql> SHOW ENGINE INNODB STATUS \G ---------------------- BUFFER POOL AND MEMORY ---------------------- Total memory allocated 398063986; in additional pool allocated 0 Dictionary memory allocated 12056 Buffer pool size 89129 Free buffers 45671 Database pages 1367 Old database pages 0 Modified db pages 0
使用 MySQL 的
SHOW variables
命令检查计数器值,这会提供临时表数量、线程数、表缓存数、脏页数、打开表的数量和缓冲池用量等信息。mysql> SHOW variables like 'VARIABLE_NAME'
应用更改
分析不同组件的内存用量后,在 MySQL 数据库中设置适当的标志。如需更改 Cloud SQL for MySQL 实例中的标志,您可以使用 Google Cloud 控制台或 gcloud CLI。如需使用 Google Cloud 控制台更改标志值,请修改标志部分,选择标志,然后输入新值。
最后,如果内存使用率仍然很高,并且您认为正在运行的查询和标志值已经过优化,请考虑增加实例大小以避免 OOM。