mysql memory=off_MySQL内存调优
原文鏈接: MySQL Memory Allocation -- by Rick James
原文日期: Created 2010; Refreshed Oct, 2012, Jan, 2014
翻譯人員: 鐵錨
翻譯日期: 2014年5月28日
MySQL 內存分配—— 高速設置方案
假設僅使用MyISAM存儲引擎,設置 key_buffer_size為可用內存的20%,(再加上設置 innodb_buffer_pool_size = 0 )
假設僅使用InnoDB存儲引擎,設置 innodb_buffer_pool_size為可用內存的 70%, (設置 key_buffer_size = 10M,非常小但不是0.)
調優mysql的實踐經驗:
首先拷貝 my.cnf / my.ini 文件副本.
依據使用的存儲引擎及可用內存,設置 key_buffer_size 和innodb_buffer_pool_size.
慢查詢(Slow queries)的修正通常是通過加入索引(indexes),改變表結構(schema),改變 SELECT 語句 來實現,而不是通過數據庫調優.
不要隨便設置查詢緩存(Query cache),除非你真正掌握它的優缺點以及適用場景.
不要改變其它的參數,除非你遇到了相應的問題(如最大連接數問題, max connections).
確保改動的是 [mysqld] 這一節下的內容,而不是其它部分.以下向您展示一些實際的細節. (本文不涉及 NDB Cluster)
什么是索引緩存(key_buffer)?
MyISAM引擎的緩存分為兩部分.
索引塊(Index blocks,每一個1 KB,BTree結構、存放于 .MYI 文件) 緩存到 “key buffer” 中.
數據塊緩存(Data block caching, 存放于 .MYD 文件里)交給操作系統負責, 所以確保留下了適量的空暇內存(給操作系統).警告: 某些類型的操作系統總是報告說內存使用超過90%,盡管實際上還有非常多的空暇內存.
SHOW GLOBAL STATUS LIKE 'Key%'; 運行后計算 Key_read_requests / Key_reads 的值, 假設比值較大(比方大于10), 那么 key_buffer 就足夠了.
什么是緩存池(buffer_pool)?
InnoDB將全部緩存都放在 “buffer pool” 中, 緩存池的大小通過 innodb_buffer_pool_size控制. 包括被打開表(open tables)中的 16KB一塊的數據/索引塊,此外還有一些附加開銷.
MySQL 5.5(以及帶插件的 5.1版本號)同意您指定 塊大小(block size)為 8 KB或4 KB. MySQL 5.5能夠有多個緩沖池,由于每一個緩存池有一個相互排斥鎖, 所以設置多個池能夠緩解一些相互排斥鎖瓶頸.
SHOW TABLE STATUS;?顯示各個數據庫中全部表的狀態.計算全部MyISAM表的 Index_length 值的總和. 讓 key_buffer_size 小于等于這個和值.
計算全部 InnoDB表 Data_length + Index_length 值的總和. 設置 innodb_buffer_pool_size 為不超過總和值的110%.假設有內存交換(swapping發生),須要將兩個參數適量地按減小一些.
運行以下的SQL語句查看適合的參數值. (假設有非常多表,可能耗時幾分鐘.)
SELECT ENGINE,
ROUND(SUM(data_length) /1024/1024, 1) AS "Data MB",
ROUND(SUM(index_length)/1024/1024, 1) AS "Index MB",
ROUND(SUM(data_length + index_length)/1024/1024, 1) AS "Total MB",
COUNT(*) "Num Tables"
FROM INFORMATION_SCHEMA.TABLES
WHERE table_schema not in ("information_schema", "performance_schema")
GROUP BY ENGINE;相互排斥鎖瓶頸
MySQL 是單核CPU時代設計的,且能夠非常easy移植到不同的硬件體系架構中. 不幸的是,這導致了對連結鎖(interlock)操作的凌亂. 在幾個重要的流程中存在少量(非常少)的“相互排斥(mutexes)”. 包括:
MyISAM的 key_buffer
查詢緩存(Query Cache)
InnoDB的buffer_pool隨著多核CPU的盛行,相互排斥問題引起了MySQL的性能問題. 一般來說,CPU超過 4~8 核越多,則MySQL變得越慢,而不會更快. MySQL 5.5 中 InnoDB 的增強版 Percona XtraDB 對多核CPU的支持要好非常多; 實際的限制大致是32核, CPU核心超過這個數后性能會達到瓶頸 ,但不再下降. MySQL 5.6版聲稱最多能夠支持48核.
超線程和多核CPU
簡單的處理方式:
禁用超線程(HyperThreading)
停用超過8個核心以上的部分
超線程這里主要是指曾經的超線程技術,因此此部分可能不一定正確.超線程適合拿來做營銷宣傳,但對(專用應用的)性能極不友好. 有兩個處理單元在共享同一個物理緩存. 假設這兩個線程在做相同的事情,緩存會相當高效. 假設這倆線程在干不同的事,他們會相互妨礙到還有一個(超)線程的緩存項.
總的來說MySQL在多核處理上并不占優勢. 所以,假設禁用超線程(HT),剩下的核心將會運行得更快一點.
32位操作系統和MySQL
(譯者注: 肯定64位的MySQL在 32位OS上跑不起來...)
首先,操作系統(以及硬件?) 會限制進程不能使用4GB RAM中的全部,假設有 4G內存的話. 假設物理 RAM 超過 4 GB, 超過的部分在32位操作系統中不可訪問,也是不可用的.
其次,操作系統可能會限制單個進程最大使用多少內存.
比如:FreeBSD的 maxdsiz ,默覺得512 MB.
演示樣例:
$ ulimit -a
...
max memory size (kbytes, -m) 524288因此,確定了 mysqld有多少可用內存, 就能夠設置為 20% ~ 70%,但須要適當的減少一些.
假設系統報錯,比如[ERROR] /usr/libexec/mysqld: Out of memory (Needed xxx bytes) , 可能是MySQL申請了超過操作系統同意的內存范圍. 須要減小緩存設置.
64位OS與32位MySQL
64位操作系統不受4 GB內存的限制,但32位MySQL依舊受這個限制.
假設你有 4 GB以上的內存,那么能夠設置:
key_buffer_size = 20%(全部RAM的),但不要超過3 GB.
buffer_pool = 3G當然最好的辦法是將MySQL換成64位版本號.
64位OS與64位MySQL
僅僅使用MyISAM引擎: (5.0.52 ~ 5.1.23之前的)key_buffer_size有 4GB的硬性限制. 詳情請參考MySQL 5.1 限制(restrictions)在更高版本號中,設置 key_buffer_size 為 20%的RAM. 在(my.cnf / my.ini)中加上 innodb_buffer_pool_size = 0.
僅僅使用InnoDB引擎: 設置 innodb_buffer_pool_size = 70%的RAM. 假設內存非常大,并使用 5.5(及以上)版本號,能夠考慮使用 多個緩存池. 推薦設置 1 - 16 個 ?innodb_buffer_pool_instances, 每一個都不小于1 GB. (非常抱歉,沒有最優設置為多少個的具體參考指標;但應該不能設置太多).與此同一時候,設置 key_buffer_size = 20M(非常小,但不是零)
假設你在數據庫中混合使用多個引擎,將兩個值都減少一些.
最大連接數,線程棧
(max_connections,thread_stack)
每一個“線程”都要占用一定的內存. 通常為 200 KB左右; 因此 100個線程大概就是 20 MB. 假設設置 max_connections= 1000,那大概就須要 200 MB,或者很多其它. 同一時候連接數太大可能會引起其它某些問題,這點須要注意.
在5.6(或 MariaDB5.5)中,能夠選擇線程池與 max_connections 交互. 這是一個高級話題.
線程棧溢出非常少出現. 假設確實發生了,能夠設置: thread_stack = 256K
很多其它關于ulimit的討論請點擊這里
(這一段是有爭議的.) 還有一方面,表緩存(過去?)的實現方式非常低效 —— 查找通過線性掃描來完畢. 因此,設置 table_cache 為幾千確實會使得 mysql變慢. (基準測試也證明了這一點.)
你能夠通過 SHOW GLOBAL STATUS; 查看系統的性能信息, 并計算 每秒打開數(opens/second): Opened_files /Uptime , 假設這個值較大,比如大于 5, 那么應該加大 table_cache; 假設非常小,比方是 1,通過減小 table_cache 值,可能會對性能有所改善.
查詢緩存(Query Cache)
簡短的回答: 設置 query_cache_type = OFF 及 query_cache_size = 0
QC(Query Cache)實際上是將 SELECT語句與結果集(resultsets)進行散列映射.
具體的回答…… 關于“查詢緩存”有很多種觀點; 當中很多是負面的.
新手警告! QC與key_buffer和buffer_pool全然無關.
當命中時, QC速度快如閃電. 要創建一個運行快1000倍的基準測試并不難.
在QC中僅僅有一個相互排斥鎖(譯者注: 鎖越少,就是鎖鑰匙越少,高并發時就會激烈競爭/等待).
除非將QC設置為OFF與0,否則每次查詢都會去對照一遍.
真相,相互排斥鎖會發生碰撞,即使 query_cache_type = DEMAND (2).
真相,相互排斥鎖會發生碰撞,即便設置了 SQL_NO_CACHE.
查詢語句僅僅要變了一點點(即使多了個空格)都可能導致在QC中生成多個不同的緩存項.“改動”是代價高昂與頻繁的:
在一個表中發生不論什么 write 事件, QC中相應到這個表的全部條目都會被清除.
即便在僅僅讀從server(readonly Slave)上也是這樣.
清除使用的是線性算法來運行,所以QC較大(比方200MB)則會導致速度明顯地變慢.要查看QC的運行效率怎樣,運行 SHOW GLOBAL STATUS LIKE 'Qc%'; 然后計算read的命中率: Qcache_hits / Qcache_inserts, 假設大于5,則 QC的效率還不錯.
假設QC適合你的應用,那么我推薦:
query_cache_size = 不超過50M
query_cache_type = DEMAND
在全部 SELECT 語句中指明 SQL_CACHE 或 SQL_NO_CACHE, 依據哪些查詢可能會從QC緩存中命中.深入了解Query Cache
thread_cache_size
這是一個非常小的調優項. 設置為 0 會減少線程(連接)創建的速度. 設置為較小的值(比方 10) 是比較好的. 該選項對RAM沒有多少影響.
它是server額外保持的線程數量,不會影響實際線程數; 起限制作用的是 max_connections.
二進制日志
假設為 復制(replication) 或 時間點恢復(point-in-time recovery) 啟用二進制日志(通過 og_bin開啟), 則server將一直記錄二進制日志(binary logs). 也就是說,可能慢慢地占用磁盤. 建議設置expire_logs_days = 14 ,僅僅保留14天的日志記錄.
swappiness
RHEL,非常英明地,同意用戶自己控制 OS 怎樣進行預先內存交換分配. 總的來說這是非常好的策略,但對MySQL來說則是一個災難.
(感覺翻譯的有點不流暢,本段原文為: RHEL, in its infinite wisdom, decided to let you control how aggressively the OS will preemptively swap RAM. This is good in general, but lousy for MySQL)MySQL期望相當穩定的內存分配 —— 緩存(大部分)是預先分配的; 線程(大都)是限制數量的. 不論什么內存交換都可能極大地損害MySQL的性能.
設置非常高的swappiness值,會丟失一些內存,由于操作系統試圖為以后的分配保留大量的自由空間(MySQL通常是不須要的).
設置swappiness = 0,不交換,在內存不足時操作系統可能會崩潰,. 我寧愿MySQL一卡一卡的,也不希望他崩了.
對于MySQL-only(專用)server, 中間數(比方5 ?)可能是一個非常好的值.
NUMA
OK,是時候了解一些CPU管理內存的架構了. 我們先看 NUMA(Non-Uniform Memory Access, 非統一內存尋址). 每一個CPU(或多路server中的每一個socket(CPU插座)) 都掛載有一部分內存. 這使得訪問本地(local) RAM 非常快, 而訪問掛載在其它 CPU下的RAM要慢上數十個周期.
接著看操作系統. 在(RHEL ?
)非常多情形下,有兩個行為:OS分配的內存固定到 “first(第一個)” CPU名下.
接著分配的其它內存也默認分配到第一個CPU名下,直到它滿了.如今問題來了.
OS與MySQL分配完了第一個 CPU的全部RAM.
MySQL分配了第二個 CPU的部分內存.
操作系統OS還須要分配一些其它內存.Ouch —— 一個CPU須要分配內存,但自己名下控制的RAM已經耗盡了,所以它將MySQL的部分內存置換出去. 渣渣!
可能的解決方式:配置BIOS內存分配為 “interleave”(交錯). 這將防止過早交換(premature swapping),代價是有一半左右的 RAM 訪問要跨CPU(off-CPU). 嗯,不論怎樣訪問的代價都較大, 假設真的要使用全部內存的話.
總體性能損失/收益:幾個百分點.
大內存分頁(huge pages)
這里有還有一個硬件性能陷阱.
CPU訪問RAM,特別是將64位地址映射到某個地方, 比方 128 GB 或“真實”的RAM,會使用TLB. (TLB =Translation Lookaside Buffer,旁路轉換緩沖.) TLB是硬件實現的內存關聯查找表; 將64位的虛擬地址轉換到實際的物理地址.
由于TLB是一個小的,虛擬尋址的緩存,有時會發生 “misses”(未命中),那就會進入物理RAM來查找. 這是兩次查找是非常費時的操作,所以應該避免.
通常,內存被 “分頁” 為 4 KB一頁,TLB實際上將高位的(64 - 12)位映射到一個特定頁面. 而低12位通過虛地址轉換得到完整的地址.
比如,128 GB的RAM按 4 KB分頁須要 32M(3200萬個) page-table條目. 這太大了, 遠遠超過TLB的容量. 所以陷入了“Huge page”的騙局.
隨著硬件與操作系統的支持,使部分RAM成為巨型頁面成為可能 ,比方說4 MB(而不是4 KB). 這使得TLB條目劇減,對這部分RAM來說分頁單元是4 MB. 因此,巨大的頁面相當于是不分頁的(non-pagable).
如今內存被分為 pagable 和 non pagable 兩部分; 哪些部分 non pagable 是合理的?
在MySQL中, innodb_buffer_pool 就是一個完美的使用者. 通過正確地配置這些,InnoDB能跑得更快一點:啟用 Huge pages
通知操作系統分配適當的數量(和 buffer_pool 個數一致)
通知MySQL使用huge pagesMEMORY引擎(ENGINE=MEMORY)
這是一個不經常使用的存儲引擎,算是MyISAM和InnoDB的替代品. 其數據不是持久的,所以其應用范圍相當有限. 內存表的大小受限于 max_heap_table_size ,默認值是16 MB. 我提起它,以防你將此值改動得太大;這會偷偷地占用可用的RAM.
怎樣設置變量(VARIABLEs)
在文本文件my.cnf中(Windows上是my.ini),加入一行,比如
innodb_buffer_pool_size = 5G
即: 變量名,等號“=”,變量的值. 有些值同意縮寫,如M代表 million(1048576),G代表billion.
要讓server看到這些設置,必須將其放到配置文件的 “[mysqld]”節下.
對 my.cnf 或 my.ini的設置不會馬上生效,須要你重新啟動server.
大多數的設置能夠通過 root 賬號登陸后在線改動 ?(其它 SUPER權限賬號也能夠),比如:
SET @@global.key_buffer_size = 77000000;
注意:此處不同意設置 M 或 G 等單位.
查看全局變量的設置信息:
mysql> SHOW GLOBAL VARIABLES LIKE "key_buffer_size";
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| key_buffer_size | 76996608 |
+-----------------+----------+注意,這部分設置MySQL會向下取整,對齊到一定的數字.
你可能須要改動兩個地方(運行SET 并改動my.cnf),以使改動馬上生效,而且下次重新啟動后依舊是相同的值(無論是手動,還是其它原因又一次啟動)
Webserver
像Apache這種webserver使用多線程來處理. 假設每一個線程打開一個 MySQL連接,可能會超過同意的最大連接數. 確保將webserver的 MaxClients (或相似參數) 設置為一個合理的值(如50以下).
工具
MySQLTuner
TUNING-PRIMER上面是幾個對內存設置建議的工具. 當中有一個誤導性條目:
Maximum possible memory usage: 31.3G(266% of installed RAM)
可能使用的內存最大值為: 31.3G (可能是物理內存的 266%)
不要讓它嚇到你,這些工具使用的公式過于保守了. 他們假設全部 max_connections 都在使用而且處于活躍狀態,并正在運行一些內存密集型的工作.
Total fragmented tables: 23
有碎片的tables: 23 個
這意味著 OPTIMIZE TABLE 可能會有作用. 我建議對表設置高百分比的 “free space”(見SHOW TABLE STATUS) 或者你知道對什么表做了大量的刪除/更新操作. 只是,不必費心頻繁地對table進行OPTIMIZE 優化整理. 一個月一次可能就夠了.
文章改動記錄
2010創建;2012年10月更新,2014年1月更新;
更深入的文章:
MySQL?5.6的調優
InnoDB性能優化的基本知識(終極版)
MySQL安裝后的10項優化設置
通過 MySQL論壇::性能 聯系作者 ——里克·詹姆斯
里克·詹姆斯的MySQL相關文檔
提示,調試、howto、優化相關等等……
總結
以上是生活随笔為你收集整理的mysql memory=off_MySQL内存调优的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql mycat one_Myca
- 下一篇: mysql慢查询开启语句分析_linux