MySQL 實際內存分配

背景

MySQL 版本: MySQL 5.7.20
硬件配置: 8C + 32GB + 1000GB

MySQL實際內存分配

  MySQL 的內存是一個重要的性能參數,常常出現由於異常的SQL請求以及待優化的數據庫導致內存利用率升高的情況,嚴重時還會出現由於OOM導致數據庫宕機,在沒有做HA的情況下導致整個業務線的癱瘓。

MySQL的內存大體可以分爲共享內存session私有內存兩部分。

共享內存

執行如下命令,即可查詢示例的共享內存參數分配情況:

show variables where variable_name in (
'innodb_buffer_pool_size',
'innodb_log_buffer_size',
'innodb_additional_mem_pool_size',
'key_buffer_size','query_cache_size'
);

輸出示例:

+---------------------------------+-----------------+
| Variable_name                   | Value           |
+---------------------------------+-----------------+
| innodb_additional_mem_pool_size | 8388608         |
| innodb_buffer_pool_size         | 25769803776     |
| innodb_log_buffer_size          | 8388608         |
| key_buffer_size                 | 16777216        |
| query_cache_size                | 3145728         |
+---------------------------------+-----------------+
共返回 5 行記錄,花費 342.74 ms.

參數說明
◎ innodb_buffer_pool_size
  該部分緩存是Innodb引擎最重要的緩存區域,是通過內存來彌補物理數據文件的重要手段,數據庫實例上會採用實例規格配置的75%作爲該部分大小。其中主要包括數據頁、索引頁、undo頁、insert buffer、自適應哈希索引、鎖信息以及數據字典等信息。在進行SQL讀和寫的操作時,首先並不是對物理數據文件操作,而是先對buffer_pool進行操作,然後再通過checkpoint等機制寫回數據文件。該空間的優點是可以提升數據庫性能、加快SQL運行速度,缺點是故障恢復速度較慢。
◎ innodb_log_buffer_size
  該部分主要存放redo log的信息,在RDS上會設置1M的大小。InnoDB會首先將redo log寫在這裏,然後按照一定頻率將其刷新回重做日誌文件中。該空間不需要太大,因爲一般情況下該部分緩存會以較快刷新頻率刷新至redo log(Master Thread會每秒刷新、事務提交時會刷新、其空間少於1/2時同樣會刷新)。
◎ innodb_additional_mem_pool_size
  該部分主要存放InnoDB內的一些數據結構,在RDS中統一設置爲2M。通常是在buffer_pool中申請內存的時候還需要在額外內存中申請空間存儲該對象的結構信息。該大小主要與表數量有關,表數量越大需要的空間越大。
◎ key_buffer
  該部分是MyISAM表的重要緩存區域,所有實例統一爲16M。該部分主要存放MyISAM表的鍵。MyISAM表不同於InnoDB表,其緩存的索引緩存是放在key_buffer中的,而數據緩存則存儲於操作系統的內存中。RDS的系統是MyISAM引擎的,因此在RDS中是給予該部分一定量的空間的。
◎ query_cache
  該部分是對查詢結果做緩存以減少解析SQL和執行SQL的花銷,在RDS上關閉了該部分的緩存。主要適合於讀多寫少的應用場景,因爲他是按照SQL語句的hash值進行緩存的,當表數據發生變化後即失效。

Session私有內存

  共享內存中介紹的內存空間是實例創建時即分配的內存空間,並且是所有連接共享的。而出現OOM異常的實例都是由於下面各個連接私有的內存造成的。
執行如下命令,查詢示例的session私有內存分配情況:

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'
);

輸出示例:

+-------------------------+-----------------+
| Variable_name           | Value           |
+-------------------------+-----------------+
| binlog_cache_size       | 262144          |
| join_buffer_size        | 262144          |
| read_buffer_size        | 262144          |
| read_rnd_buffer_size    | 262144          |
| sort_buffer_size        | 262144          |
| tmp_table_size          | 262144          |
+-------------------------+-----------------+
共返回 6 行記錄,花費 356.54 ms.

參數說明
◎ read_buffer_size & read_rnd_buffer_size
  分別存放了對順序和隨機掃描(例如按照排序的順序訪問)的緩存,RDS給每個session設置256K的大小。當thread進行順序或隨機掃描數據是會首先掃描該buffer空間避免更多的物理讀。
◎ sort_buffer_size
  需要執行order by和group by的SQL都會分配sort buffer,用於存儲排序的中間結果,在RDS上設置256K。在排序過程中,若存儲量大於sort_buffer_size,則會在磁盤生成臨時表以完成操作。在Linux系統中,當分配空間大於2M是會使用mmap()而不是malloc()來進行內存分配,導致效率降低。
◎ join_buffer_size
  MySQL僅支持nest loop的join算法,RDS設置256K的大小。處理邏輯是驅動表的一行和非驅動表聯合查找,這時就可以 將非驅動表放入join_buffer,不需要訪問擁有併發保護機制的buffer_pool。
◎ binlog_cache_size
  該區域用來緩存該thread的binlog日誌,RDS設置256K的大小。在一個事務還沒有commit之前會將其日誌存儲於binlog_cache中,等到事務commit後會將binlog刷回磁盤上的binlog文件以持久化。
◎ tmp_table_size
  不同於上面各個session層次的buffer,這個參數可以在控制檯上修改。該參數是指用戶內存臨時表的大小,如果該thread創建的臨時表超過它設置的大小會把臨時錶轉換爲磁盤上的一張MyISAM臨時表。如果用戶在執行事務時遇到類似如下這樣的錯誤,可以考慮增大tmp_table的值.

[Err] 1114 - The table '/home/mysql/data3081/tmp/#sql_6197_2' is full
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章