mariadb 記憶體佔用優化

qcloud發表於2019-01-23

本文由雲+社群發表

作者:工程師小熊

摘要:我們在使用mariadb的時候發現有時候不能啟動起來,在使用過程中mariadb佔用的記憶體很大,在這裡學習下mariadb與記憶體相關的配置項,對mariadb進行調優。

查詢最高記憶體佔用

使用以下命令可以知道mysql的配置使用多少 RAM

SELECT ( @@key_buffer_size
+ @@query_cache_size
+ @@innodb_buffer_pool_size
+ @@innodb_additional_mem_pool_size
+ @@innodb_log_buffer_size
+ @@max_connections * ( @@read_buffer_size
+ @@read_rnd_buffer_size
+ @@sort_buffer_size
+ @@join_buffer_size
+ @@binlog_cache_size
+ @@thread_stack
+ @@tmp_table_size
)
) / (1024 * 1024 * 1024) AS MAX_MEMORY_GB;

可以使用mysql計算器來計算記憶體使用

下面是理論,可以直接到推薦配置

如何調整配置

key_buffer_size(MyISAM索引用)

指定索引緩衝區的大小,它決定索引處理的速度,尤其是索引讀的速度。為了最小化磁碟的 I/O , MyISAM 儲存引擎的表使用鍵快取記憶體來快取索引,這個鍵快取記憶體的大小則通過 key-buffer-size 引數來設定。如果應用系統中使用的表以 MyISAM 儲存引擎為主,則應該適當增加該引數的值,以便儘可能的快取索引,提高訪問的速度。

怎麼設

show global status like 'key_read%';

+------------------------+-------------+
| Variable_name | Value |
+------------------------+-------------+
| Key_read_requests | 27813678764 |
| Key_reads | 6798830 |
--------------------- 
  • key_buffer_size通過檢查狀態值Key_read_requests和Key_reads,可以知道key_buffer_size設定是否合理。
  • 比例key_reads / key_read_requests應該儘可能的低,至少是1:100,1:1000更好。
show global status like '%created_tmp_disk_tables%';
  • key_buffer_size只對MyISAM表起作用。即使你不使用MyISAM表,但是內部的臨時磁碟表是MyISAM表,也要使用該值。可以使用檢查狀態值created_tmp_disk_tables得知詳情。
  • 對於1G記憶體的機器,如果不使用MyISAM表,推薦值是16M(8-64M)

另一個參考如下

show global status like 'key_blocks_u%';
+------------------------+-------------+
| Variable_name | Value |
+------------------------+-------------+
| Key_blocks_unused | 0 |
| Key_blocks_used | 413543 |
+------------------------+-------------+

Key_blocks_unused表示未使用的快取簇(blocks)數,Key_blocks_used表示曾經用到的最大的blocks數,比如這臺伺服器,所有的快取都用到了,要麼增加key_buffer_size,要麼就是過渡索引了,把快取佔滿了。比較理想的設定:

  • 可以根據此工式來動態的調整Key_blocks_used / (Key_blocks_unused + Key_blocks_used) * 100% ≈ 80%
show engines;
  • 查詢儲存引擎

innodb_buffer_pool_size (innodb索引用)

這個引數和MyISAM的key_buffer_size有相似之處,但也是有差別的。這個引數主要快取innodb表的索引,資料,插入資料時的緩衝。為Innodb加速優化首要引數。  

該引數分配記憶體的原則:這個引數預設分配只有8M,可以說是非常小的一個值。

  • 如果是專用的DB伺服器,且以InnoDB引擎為主的場景,通常可設定實體記憶體的50%,這個引數不能動態更改,所以分配需多考慮。分配過大,會使Swap佔用過多,致使Mysql的查詢特慢。
  • 如果是非專用DB伺服器,可以先嚐試設定成記憶體的1/4,如果有問題再調整

query_cache_size(查詢快取)

快取機制簡單的說就是快取sql文字及查詢結果,如果執行相同的sql,伺服器直接從快取中取到結果,而不需要再去解析和執行sql。如果表更改了,那麼使用這個表的所有緩衝查詢將不再有效,查詢快取值的相關條目被清空。更改指的是表中任何資料或是結構的改變,包括INSERT、UPDATE、DELETE、TRUNCATE、ALTER TABLE、DROP TABLE或DROP DATABASE等,也包括那些對映到改變了的表的使用MERGE表的查詢。顯然,這對於頻繁更新的表,查詢快取是不適合的,而對於一些不常改變資料且有大量相同sql查詢的表,查詢快取會節約很大的效能。

  • 注意:如果你查詢的表更新比較頻繁,而且很少有相同的查詢,最好不要使用查詢快取。因為這樣會消耗很大的系統效能還沒有任何的效果

要不要開啟?

先設定成這樣跑一段時間

query_cache_size=128M 
query_cache_type=1 

看看命中結果來進行進一步的判斷

mysql> show status like '%Qcache%';
+-------------------------+-----------+
| Variable_name           | Value     |
+-------------------------+-----------+
| Qcache_free_blocks      | 669       |
| Qcache_free_memory      | 132519160 |
| Qcache_hits             | 1158      |
| Qcache_inserts          | 284824    |
| Qcache_lowmem_prunes    | 2741      |
| Qcache_not_cached       | 1755767   |
| Qcache_queries_in_cache | 579       |
| Qcache_total_blocks     | 1853      |
+-------------------------+-----------+
8 rows in set (0.00 sec)

Qcache_free_blocks:表示查詢快取中目前還有多少剩餘的blocks,如果該值顯示較大,則說明查詢快取中的記憶體碎片過多了,可能在一定的時間進行整理。

Qcache_free_memory:查詢快取的記憶體大小,通過這個引數可以很清晰的知道當前系統的查詢記憶體是否夠用,是多了,還是不夠用,DBA可以根據實際情況做出調整。

Qcache_hits:表示有多少次命中快取。我們主要可以通過該值來驗證我們的查詢快取的效果。數字越大,快取效果越理想。

Qcache_inserts: 表示多少次未命中然後插入,意思是新來的SQL請求在快取中未找到,不得不執行查詢處理,執行查詢處理後把結果insert到查詢快取中。這樣的情況的次數,次數越多,表示查詢快取應用到的比較少,效果也就不理想。當然系統剛啟動後,查詢快取是空的,這很正常。

Qcache_lowmem_prunes:該引數記錄有多少條查詢因為記憶體不足而被移除出查詢快取。通過這個值,使用者可以適當的調整快取大小。

Qcache_not_cached: 表示因為query_cache_type的設定而沒有被快取的查詢數量。

Qcache_queries_in_cache:當前快取中快取的查詢數量。

Qcache_total_blocks:當前快取的block數量。

  • 我們可以看到現網命中1158,未快取的有1755767次,說明我們這個系統命中的太少了,表變動比較多,不什麼開啟這個功能涉及引數
  • query_cache_limit:允許 Cache 的單條 Query 結果集的最大容量,預設是1MB,超過此引數設定的 Query 結果集將不會被 Cache
  • query_cache_min_res_unit:設定 Query Cache 中每次分配記憶體的最小空間大小,也就是每個 Query 的 Cache 最小佔用的記憶體空間大小
  • query_cache_size:設定 Query Cache 所使用的記憶體大小,預設值為0,大小必須是1024的整數倍,如果不是整數倍,MySQL 會自動調整降低最小量以達到1024的倍數
  • query_cache_type:控制 Query Cache 功能的開關,可以設定為0(OFF),1(ON)和2(DEMAND)三種,意義分別如下: 0(OFF):關閉 Query Cache 功能,任何情況下都不會使用 Query Cache 1(ON):開啟 Query Cache 功能,但是當 SELECT 語句中使用的 SQL_NO_CACHE 提示後,將不使用Query Cache 2(DEMAND):開啟 Query Cache 功能,但是隻有當 SELECT 語句中使用了 SQL_CACHE 提示後,才使用 Query Cache
  • query_cache_wlock_invalidate:控制當有寫鎖定發生在表上的時刻是否先失效該表相關的 Query Cache,如果設定為 1(TRUE),則在寫鎖定的同時將失效該表相關的所有 Query Cache,如果設定為0(FALSE)則在鎖定時刻仍然允許讀取該表相關的 Query Cache。

innodb_additional_mem_pool_size(InnoDB內部目錄大小)

InnoDB 字典資訊快取主要用來存放 InnoDB 儲存引擎的字典資訊以及一些 internal 的共享資料結構資訊,也就是存放Innodb的內部目錄,所以其大小也與系統中所使用的 InnoDB 儲存引擎表的數量有較大關係。

這個值不用分配太大,通常設定16M夠用了,預設8M,如果設定的記憶體大小不夠,InnoDB 會自動申請更多的記憶體,並在 MySQL 的 Error Log 中記錄警告資訊。

innodb_log_buffer_size (日誌緩衝)

表示InnoDB寫入到磁碟上的日誌檔案時使用的緩衝區的位元組數,預設值為16M。一個大的日誌緩衝區允許大量的事務在提交之前不用寫日誌到磁碟,所以如果有更新,插入或刪除許多行的事務,則使日誌緩衝區更大一些可以節省磁碟IO

通常最大設為64M足夠

max_connections (最大併發連線)

MySQL的max_connections引數用來設定最大連線(使用者)數。每個連線MySQL的使用者均算作一個連線,max_connections的預設值為100。

  • 這個引數實際起作用的最大值(實際最大可連線數)為16384,即該引數最大值不能超過16384,即使超過也以16384為準;
  • 增加max_connections引數的值,不會佔用太多系統資源。系統資源(CPU、記憶體)的佔用主要取決於查詢的密度、效率等;
  • 該引數設定過小的最明顯特徵是出現”Too many connections”錯誤
mysql> show variables like '%max_connect%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| extra_max_connections | 1     |
| max_connect_errors    | 100   |
| max_connections       | 2048  |
+-----------------------+-------+
3 rows in set (0.00 sec)

mysql> show status like 'Threads%';
+-------------------+---------+
| Variable_name     | Value   |
+-------------------+---------+
| Threads_cached    | 0       |
| Threads_connected | 1       |
| Threads_created   | 9626717 |
| Threads_running   | 1       |
+-------------------+---------+
4 rows in set (0.00 sec)

可以看到此時的併發數也就是Threads_connected=1,還遠遠達不到2048

mysql> show variables like 'open_files_limit';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| open_files_limit | 65535 |
+------------------+-------+
1 row in set (0.00 sec)

max_connections 還取決於作業系統對單程式允許開啟最大檔案數的限制

也就是說如果作業系統限制單個程式最大可以開啟100個檔案

那麼 max_connections 設定為200也沒什麼用

MySQL 的 open_files_limit 引數值是在MySQL啟動時記錄的作業系統對單程式開啟最大檔案數限制的值

可以使用 show variables like 'open_files_limit'; 檢視 open_files_limit 值

ulimit -n
65535

或者直接在 Linux 下通過ulimit -n命令檢視作業系統對單程式開啟最大檔案數限制 ( 預設為1024 )

connection級記憶體引數(執行緒獨享)

connection級引數,是在每個connection第一次需要使用這個buffer的時候,一次性分配設定的記憶體。

排序效能

mysql對於排序,使用了兩個變數來控制sort_buffer_size和 max_length_for_sort_data, 不象oracle使用SGA控制. 這種方式的缺點是要單獨控制,容易出現排序效能問題.

mysql> SHOW GLOBAL STATUS like '%sort%';
+---------------------------+--------+
| Variable_name             | Value  |
+---------------------------+--------+
| Sort_merge_passes         | 0      |
| Sort_priority_queue_sorts | 1409   |
| Sort_range                | 0      |
| Sort_rows                 | 843479 |
| Sort_scan                 | 13053  |
+---------------------------+--------+
5 rows in set (0.00 sec)
  • 如果發現Sort_merge_passes的值比較大,你可以考慮增加sort_buffer_size 來加速ORDER BY 或者GROUP BY 操作,不能通過查詢或者索引優化的。我們這為0,那就沒必要設定那麼大。

讀取快取

read_buffer_size = 128K(預設128K)為需要全表掃描的MYISAM資料表執行緒指定快取

read_rnd_buffer_size = 4M:(預設256K)首先,該變數可以被任何儲存引擎使用,當從一個已經排序的鍵值表中讀取行時,會先從該緩衝區中獲取而不再從磁碟上獲取。

大事務binlog

mysql> show global status like 'binlog_cache%';
+-----------------------+----------+
| Variable_name         | Value    |
+-----------------------+----------+
| Binlog_cache_disk_use | 220840   |
| Binlog_cache_use      | 67604667 |
+-----------------------+----------+
2 rows in set (0.00 sec)
  • Binlog_cache_disk_use表示因為我們binlog_cache_size設計的記憶體不足導致快取二進位制日誌用到了臨時檔案的次數
  • Binlog_cache_use 表示 用binlog_cache_size快取的次數
  • 當對應的Binlog_cache_disk_use 值比較大的時候 我們可以考慮適當的調高 binlog_cache_size 對應的值
  • 如上圖,現網是32K,我們加到64K

join語句記憶體影響

如果應用中,很少出現join語句,則可以不用太在乎join_buffer_size引數的設定大小。

如果join語句不是很少的話,個人建議可以適當增大join_buffer_size到1MB左右,如果記憶體充足可以設定為2MB。

執行緒記憶體影響

Thread_stack:每個連線執行緒被建立時,MySQL給它分配的記憶體大小。當MySQL建立一個新的連線執行緒時,需要給它分配一定大小的記憶體堆疊空間,以便存放客戶端的請求的Query及自身的各種狀態和處理資訊。

mysql> show status like '%threads%';
+-------------------------+---------+
| Variable_name           | Value   |
+-------------------------+---------+
| Delayed_insert_threads  | 0       |
| Slow_launch_threads     | 0       |
| Threadpool_idle_threads | 0       |
| Threadpool_threads      | 0       |
| Threads_cached          | 0       |
| Threads_connected       | 1       |
| Threads_created         | 9649301 |
| Threads_running         | 1       |
+-------------------------+---------+
8 rows in set (0.00 sec)

mysql> show status like 'connections';
+---------------+---------+
| Variable_name | Value   |
+---------------+---------+
| Connections   | 9649311 |
+---------------+---------+
1 row in set (0.00 sec)

如上:系統啟動到現在共接受到客戶端的連線9649311次,共建立了9649301個連線執行緒,當前有1個連線執行緒處於和客戶端連線的狀態。而在Thread Cache池中共快取了0個連線執行緒(Threads_cached)。

Thread Cache 命中率:

Thread_Cache_Hit = (Connections - Threads_created) / Connections * 100%;

一般在系統穩定執行一段時間後,Thread Cache命中率應該保持在90%左右才算正常。

記憶體臨時表

tmp_table_size 控制記憶體臨時表的最大值,超過限值後就往硬碟寫,寫的位置由變數 tmpdir 決定

max_heap_table_size 使用者可以建立的記憶體表(memory table)的大小.這個值用來計算記憶體表的最大行數值。

Order By 或者Group By操作多的話,加大這兩個值,預設16M

mysql> show status like 'Created_tmp_%';
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| Created_tmp_disk_tables | 0     |
| Created_tmp_files       | 626   |
| Created_tmp_tables      | 3     |
+-------------------------+-------+
3 rows in set (0.00 sec)
  • 如上圖,寫入硬碟的為0,3次中間表,說明我們的預設值足夠用了

mariadb 推薦配置

  • 注意這裡只推薦innodb引擎
  • 記憶體配置只關注有註釋的行
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
default-storage-engine=INNODB

character-set-server=utf8
collation-server=utf8_general_ci

user=mysql
symbolic-links=0

# global settings
table_cache=65535
table_definition_cache=65535

max_allowed_packet=4M
net_buffer_length=1M
bulk_insert_buffer_size=16M

query_cache_type=0              #是否使用查詢緩衝,0關閉
query_cache_size=0              #0關閉,因為改表操作多,命中低,開啟消耗cpu

# shared
key_buffer_size=8M              #保持8M MyISAM索引用
innodb_buffer_pool_size=4G              #DB專用mem*50%,非DB專用mem*15%到25%
myisam_sort_buffer_size=32M
max_heap_table_size=16M             #最大中間表大小
tmp_table_size=16M              #中間表大小

# per-thread
sort_buffer_size=256K               #加速排序快取大小
read_buffer_size=128k               #為需要全表掃描的MYISAM資料表執行緒指定快取
read_rnd_buffer_size=4M             #已排序的表讀取時快取,如果比較大記憶體就到6M
join_buffer_size=1M             #join語句多時加大,1-2M
thread_stack=256k               #執行緒空間,256K or 512K
binlog_cache_size=64K               #大事務binlog

# big-tables
innodb_file_per_table = 1
skip-external-locking
max_connections=2048                #最大連線數
skip-name-resolve

# slow_query_log
slow_query_log_file = /var/log/mysql-slow.log
long_query_time = 30
group_concat_max_len=65536

# according to tuning-primer.sh
thread_cache_size = 8
thread_concurrency = 16

# set variables
concurrent_insert=2

執行時修改

使用以下命令來修改變數

set global {要改的key} = {值}; (立即生效重啟後失效)
set @@{要改的key} = {值}; (立即生效重啟後失效)
set @@global.{要改的key} = {值}; (立即生效重啟後失效)

試驗

mysql> set @@global.innodb_buffer_pool_size=4294967296;
ERROR 1238 (HY000): Variable 'innodb_buffer_pool_size' is a read only variable
mysql> set @@global.thread_stack=262144;
ERROR 1238 (HY000): Variable 'thread_stack' is a read only variable
mysql> set @@global.binlog_cache_size=65536;
Query OK, 0 rows affected (0.00 sec)
mysql> set @@join_buffer_size=1048576;
Query OK, 0 rows affected (0.00 sec)
mysql> set @@read_rnd_buffer_size=4194304;
Query OK, 0 rows affected (0.00 sec)
mysql> set @@sort_buffer_size=262144;
Query OK, 0 rows affected (0.00 sec)
mysql> set @@read_buffer_size=131072;
Query OK, 0 rows affected (0.00 sec)
mysql> set global key_buffer_size=8388608;
Query OK, 0 rows affected (0.39 sec)
  • 我們可以看到innodb_buffer_pool_sizethread_stack報錯了,他們只能改配置檔案,在執行時是隻讀的。 以下直接複製使用
set @@global.binlog_cache_size=65536;
set @@join_buffer_size=1048576;
set @@read_rnd_buffer_size=4194304;
set @@sort_buffer_size=262144;
set @@read_buffer_size=131072;
set global key_buffer_size=8388608;

引用

記一次Mysql佔用記憶體過高的優化過程

mysql 優化技巧心得一(key_buffer_size設定)

mysql記憶體計算

mysql計算器

mariadb官網

此文已由騰訊雲+社群在各渠道釋出

獲取更多新鮮技術乾貨,可以關注我們騰訊雲技術社群-雲加社群官方號及知乎機構號

相關文章