
# RDS for MySQL内存过载定位及处理建议
#### 场景介绍
内存过载主要体现以下两个场景：
- 场景一：内存持续缓慢上涨导致OOM。
- 场景二：短时间内存飙升导致OOM。
 
#### 可能原因
**场景一（内存持续缓慢上涨导致OOM）主要包含以下原因：**
- 内存参数设置较大，导致全局或每个连接占用的session级别内存较高，且随着执行的SQL变化。 执行如下命令，即可查询全局内存分配情况：
  ```
  ```plaintext
  show variables where variable_name in (
  'innodb_buffer_pool_size','query_cache_size'
  );
  ```
  ```
  执行如下命令，查询示例的Session私有内存分配情况：
  ```
  ```plaintext
  show variables where variable_name in (
  'read_buffer_size','read_rnd_buffer_size','sort_buffer_size','join_buffer_size','binlog_cache_size','tmp_table_size'
  );
  ```
  ```
  可以适当调整参数使内存稳定在合理范围（75%\~90%且稳定无较大波动）。
  

- 客户端连接空闲超时参数设置过大，导致出现长连接无法释放。 首先检查客户端连接空闲超时断开的参数，例如Druid连接池的"minEvictableIdleTimeMillis"和"maxEvictableIdleTimeMillis"参数。假设客户端空闲超时时间设置为60s，但客户端连接每秒都会请求SQL，不存在空闲时间，则此连接将作为长连接持续存在而不会被释放。
  长连接在使用过程中，由于无法保证自身访问的数据量会不会出现变化、自身接收到的SQL文本长度会不会发生变化，有极大可能造成连接的私有内存块net buffer被撑大，且此内存的分配策略为复用不主动回收且随连接释放而释放，最终导致每个长连接占用大块的net buffer内存（最大1GB）导致OOM。
  

- 实例中存在较多的大文本存储过程，导致连接执行存储过程后内存缓慢上升不释放。 存储过程在首次被创建时会进行语法分析和编译，生成执行计划并存储在数据库中，如果连接执行了较大文本的存储过程，被编译好的存储过程会存储在连接的sp_head:mem_root内存块中，且由于其预编译属性，此内存块会在连接释放时才进行释放，如果持续调用不同的存储过程且不释放，数据库内存会呈现上升趋势。
  
**场景二（短时间内存飙升导致OOM）主要包含以下原因：**
- SQL文本过大导致net buffer内存占用过大以及词法分析阶段占用内存过大。 RDS for MySQL在处理SQL文本的词法解析以及语法解析时，会将整个SQL的关键字，以及数据信息存储到对应的内存数据结构中，当SQL文本过大时，会占用大量内存导致内存极速上升引发OOM。
  常见大SQL主要分为以下几类：
  - 类型一： In方式的查询条件中包含大量的查询值导致SQL文本过大。 SQL举例：
    ```
    select column from table where column2 in (a1,a2,a3,a4,a5,a6…aN);
    ```
    
  
  - 类型二：单条insert插入行数过多导致SQL文本过大。 SQL举例：
    ```
    insert into large_data_table values(1,’张三’),(2,’李四’),...(500000,’xxx’)
    ```
    
  
  - 类型三：单条insert涉及文本较长字段，例如：longtext、text、blob、json类型字段。 SQL举例：
    ```
    insert into large_text_table values(1,’xxxx...’),(2,’xxx...’);
    ```
    
   
- SQL结果集存在超大单行记录导致瞬时消耗大量内存。 RDS for MySQL在返回结果时，会按照net_buffer_size缓存大小来分批读取结果并发送结果，但缓存的最小单元为单行，如果存在单行结果很大，比如单行记录存在longtext、text、blob、json字段，会导致内存极速上升引发OOM。
  SQL举例：
  ```
  select * from large_text_table limit 1;
  ```
  被查询表结构中存在大字段longtext，并且存储了1GB数据，单条SQL占用内存大小。
  
 
#### 对业务的影响
OOM会导致数据库宕机，通常会导致1分钟以内的连接中断。
#### 处理建议
- **出现过载异常前的建议：**
  - 排查客户端驱动以及连接池的空闲超时断开参数是否合理。
  
  - 排查业务中的长文本SQL，长文本SQL通常为代码生成，建议设置SQL文本长度的最大值来做拦截。
  
  - 尽量使用业务逻辑代理存储过程。
   

- **过载异常中的建议：**
  针对内存缓慢上升的场景，建议杀掉长连接会话，释放部分内存。详见[管理实时会话](https://support.huaweicloud.com/usermanual-rds-mysql/rds_08_0026.html)。
  
 
