當前位置:
首頁 > 知識 > mariadb 內存佔用優化

mariadb 內存佔用優化

本文由雲+社區發表

作者:工程師小熊

摘要:我們在使用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_size和thread_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官網

mariadb 內存佔用優化

打開今日頭條,查看更多圖片

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

程序員趣圖—Bug 是一門藝術
非常震撼的純CSS3人物行走動畫

TAG:程序員小新人學習 |