查看内存使用情况
RDS MySQL的控制台提供了多种查看内存使用率的方法:
RDS控制台
监控与报警
在RDS控制台的“监控与报警”页中的“标准监控”->“资源监控”和“引擎监控”下,可以查看实例的内存使用率和缓存池命中率监控:
数据库自治服务
在RDS控制台的“自治服务”->“性能趋势”->“MySQL CPU/内存利用率”页中可以查看内存利用率和缓冲池命中率监控:
RDS MySQL 内存高常见原因
通常InnoDB buffer pool的内存占用是最大的,buffer pool的内存占用上限受到buffer pool配置参数的限制,但是还有很多内存是在query运行中动态分配和调整的,比如内存临时表消耗的内存、prefetch cache、table cache、哈希索引、行锁对象等,详细的内存占用和相关参数限制参考MySQL官方文档https://dev.mysql.com/doc/refman/5.7/en/memory-use.html。
如何查看内存占用
您还可以通过打开performance_schema,然后设置相关的内存instrumentation,查询内存占用统计table来查看各个维护的内存占用,参考MySQL官方文档 https://dev.mysql.com/doc/refman/5.7/en/memory-summary-tables.html#memory-instrumentation-behavior:
performance_schema = on # 修改此参数,需要重启实例 update performance_schema.setup_instruments set enabled = 'yes' where name like 'memory%'; # 内存占用统计相关的表,从各个维度统计了内存消耗 memory_summary_by_account_by_event_name memory_summary_by_host_by_event_name memory_summary_by_thread_by_event_name memory_summary_by_user_by_event_name memory_summary_global_by_event_name
multiple statements 导致的OOM
MySQL支持将多个SQL语句用分号分隔相连,然后一起发给MySQL,MySQL Server会逐条处理SQL,但是某些内存需要等到所有的SQL执行结束才释放,这种multiple statements的发送方式,如果一次性发送的SQL非常多,比如达到数百M,SQL实际执行过程中各种对象分配累积的消耗内存非常大,很有可能触发MySQL进程OOM。一般场景下,如果存在大批量的multiple statements,网络流量会有突增,可以从网络流量监控和SQL洞察,判断是否有这种现象。建议业务实现中尽量避免multiple statements这种SQL发送方式。
buffer pool缓冲池相关问题
所有表的数据页存都放在buffer pool中,查询执行的时候如果需要的数据页直接命中buffer pool,则就没有物理IO的产生,SQL执行的效率较高,buffer pool采用LRU算法管理缓存的数据页,所有的脏页放到Flush list链表。
RDS MySQL InnoDB buffer pool的大小设置为规格内存的75%,这部分内存通常是实例内存中占比最大的。
buffer pool相关的常见问题:
- 数据页没有足够的预热,导致查询的延迟较高。通常发生在实例发生过重启、冷数据读取或内存不足,缓冲池命中率较低的场景,建议升级实例规格或大促前预热数据来避免这种问题。
- 脏页累计太多。当当前未刷脏的最老lsn和当前Lsn的距离超过76%时,会触发用户线程同步刷脏,引发实例严重的性能下降。优化方式是业务均衡写负载,避免写入吞吐过高、调整刷脏参数、升级实例规格等。
- 大规格内存实例innodb_buffer_pool_instances设置较小,高QPS负载情况下,缓冲池的锁竞争会比较激烈。建议高规格内存的实例innodb_buffer_pool_instances设置为8或16,甚至更高。
临时表
内存临时表大小受到tmp_table_size 和max_heap_table_size限制,超过限制后将转化为磁盘临时表,如果瞬间有大量的连接创建大量的临时表,有可能会造成内存突增。MySQL 8.0 实现了新的temptable engine,所有线程分配的内存临时表大小之和必须小于temptable_max_ram参数,temptable_max_ram默认1G,超出后转换为磁盘临时表。
其他原因
如果表特别多或QPS很高,table cache可能也会消耗内存,建议实例避免创建太多表和设置非常大的table_open_cache参数。还有自适应哈希索引占用的内存默认是bufffer pool size的1/64。如果查询或写入长度非常大的blob大字段,会对大字段动态分配内存,也会造成内存增加。还有非常多的原因会造成内存上涨,如果碰见内存使用率异常增加或实例OOM,您可以参考官方文档 https://dev.mysql.com/doc/refman/5.7/en/memory-use.html 排查上涨原因,或提售工单,售后值班会帮您排查。