禁用内存清理_MySql那些事儿(二):InnoDB架构介绍之内存篇
作者:阿茂
InnoDB介紹
書接上回,我們基本說(shuō)完了mysql的邏輯架構(gòu)與物理架構(gòu)。今天我們來(lái)說(shuō)說(shuō)當(dāng)下比較火的存儲(chǔ)引擎InnoDb。MySQL 5.5以前InnoDB引擎是需要手動(dòng)通過(guò)Plugin方式引入,內(nèi)置的是MyISAM。MySQL 5.5以后隨著數(shù)據(jù)庫(kù)默認(rèn)引擎的更換,InnobaseOy的InnoDB就開(kāi)始大放異彩(以下我們將用MySQL5.7舉例)。我們先說(shuō)說(shuō)它有什么樣的特性讓諸位英雄都說(shuō)香:
- 免費(fèi):這個(gè)在當(dāng)時(shí)Oracle,DB2,Sybase MSSQL壟斷的時(shí)代,有一款免費(fèi)還相對(duì)穩(wěn)定的的數(shù)據(jù)庫(kù),再加上后期社區(qū)非?;钴S,能不香嗎?
- 完善的崩潰恢復(fù)機(jī)制:不管是服務(wù)器硬件故障還是挖掘機(jī)挖斷電線導(dǎo)致的關(guān)機(jī),重啟數(shù)據(jù)庫(kù)后都無(wú)需執(zhí)行任何操作(根據(jù)設(shè)置參數(shù)有關(guān)) 崩潰恢復(fù)會(huì)自動(dòng)完成崩潰之前已提交的所有更改,并撤消正在處理但尚未提交的所有更改。只需重新啟動(dòng),然后從上次中斷的地方繼續(xù)即可。
- 高效的緩存查詢機(jī)制:通過(guò)一些算法和設(shè)計(jì)(后面會(huì)說(shuō)到)讓常用的數(shù)據(jù)最大可能的基于內(nèi)存Buffer處理減少IO,通常這塊Buffer將高達(dá)數(shù)據(jù)庫(kù)服務(wù)器內(nèi)存的80%分配給它。
- 完整性外鍵機(jī)制:將數(shù)據(jù)拆分到不同數(shù)據(jù)表中使用外鍵機(jī)制會(huì)自動(dòng)更新或刪除關(guān)聯(lián)表中的數(shù)據(jù)(現(xiàn)在基本沒(méi)有人這么玩了,一旦設(shè)計(jì)不全面, 數(shù)據(jù)的修改將不受程序的控制,數(shù)據(jù)耦合度太強(qiáng),適用于一些強(qiáng)制保證數(shù)據(jù)完整規(guī)范的系統(tǒng),例如工作流這類的)
- 數(shù)據(jù)完整性校驗(yàn)機(jī)制:數(shù)據(jù)在磁盤或內(nèi)存中損壞,則校驗(yàn)機(jī)制會(huì)在使用前提醒您注意虛假數(shù)據(jù)
- 自動(dòng)引入主鍵列:有適當(dāng)數(shù)據(jù)庫(kù)主鍵列時(shí)會(huì)自動(dòng)在Where子句,Order By子句,Group By字句后自動(dòng)引入主鍵。
- 基于數(shù)據(jù)庫(kù)緩存Buffer寫數(shù)據(jù):不僅允許對(duì)同一表的并發(fā)讀寫訪問(wèn),而且還緩存更改的數(shù)據(jù)以減少磁盤IO。
- 自適應(yīng)哈希索引 :當(dāng)頻繁的從巨表中查詢相同行的數(shù)據(jù)時(shí)候就會(huì)使用此方式,讓它們像從Hash表中查出來(lái)的一樣。
- 表和索引壓縮:這個(gè)不用大多說(shuō)了,它借助于zlib庫(kù),采用L777壓縮算法。就是讓你在原來(lái)兩個(gè)數(shù)據(jù)頁(yè)中的數(shù)據(jù)現(xiàn)在一頁(yè)就能顯示下,但是過(guò)度壓縮會(huì)帶來(lái)重組頁(yè)的影響, 而且不是對(duì)所有類型數(shù)據(jù)列都有良好的壓縮比。
- 動(dòng)態(tài)創(chuàng)建或刪除索引,保證數(shù)據(jù)的可用性(這個(gè)后面單獨(dú)說(shuō))
- 截?cái)啾砜臻g非???#xff0c;并且可以釋放空間給系統(tǒng)重用。
- 支持存儲(chǔ)引擎混用,最常見(jiàn)的就是我們關(guān)聯(lián)表查詢的時(shí)候產(chǎn)生的中間臨時(shí)表,默認(rèn)就是使用MEMORY引擎來(lái)實(shí)現(xiàn)的。
###InnoDB內(nèi)存結(jié)構(gòu) 接下來(lái)我們來(lái)看一張InnoDB的邏輯架構(gòu)圖:
Buffer Pool
InnoDB使用malloc()操作在啟動(dòng)時(shí)為整個(gè)緩沖池分配緩存,緩沖池存儲(chǔ)著常訪問(wèn)的表數(shù)據(jù)和索引,以頁(yè)面為單位(一個(gè)頁(yè)面可能包含多個(gè)行 )組成一個(gè)鏈接列表,使用LRU的變體算法將緩沖池作為列表管理。當(dāng)需要空間將新頁(yè)面加入到緩沖池時(shí),將淘汰掉最近最少使用的頁(yè)面,將其加入到列表的中間,通過(guò)此插入點(diǎn)將列表分為兩段:最前面的一段為最新訪問(wèn)過(guò)的頁(yè)面,末尾是最近訪問(wèn)的舊頁(yè)面,如下圖:該算法大致如下:
默認(rèn)情況下,3/8的緩沖池專用于舊的數(shù)據(jù)頁(yè)列表(Old SubList),當(dāng)然也可以(通過(guò)innodb_old_blocks_pct參數(shù)默認(rèn)是37,5-95范圍值)調(diào)整其比例大小。列表的中點(diǎn)(Midpoint)是新數(shù)據(jù)頁(yè)(New SubList)列表的尾部與舊數(shù)據(jù)頁(yè)(Old Sublist)列表的頭相交的邊界。當(dāng)一個(gè)頁(yè)面讀入緩沖池時(shí),它首先會(huì)插入舊列表(Old Sublist)的頭部如果再次讀取到舊列表(Old Sublist)的數(shù)據(jù)頁(yè)時(shí)(在一定時(shí)間內(nèi),由參數(shù)innodb_old_blocks_time來(lái)決定,默認(rèn)1000ms)將其移動(dòng)到新列表的的頭部。如果是用戶啟動(dòng)的操作需要讀取頁(yè)面,立即將其“年輕化”如果是預(yù)讀操作讀取該頁(yè)面第一次,不發(fā)生任何變化。隨著數(shù)據(jù)庫(kù)的逐漸運(yùn)行,中點(diǎn)數(shù)據(jù)的不斷插入,新老頁(yè)面都會(huì)隨著其他頁(yè)面的更新而老化,而最終未被使用到的頁(yè)面將到達(dá)舊列表的尾部被淘汰掉。默認(rèn)情況下,查詢讀取的頁(yè)面會(huì)立即移入新的列表,它們?cè)诰彌_池中停留時(shí)間更長(zhǎng)。例如,針對(duì)mysqldump操作或不帶WHERE的SELECT子句執(zhí)行的表掃描可以將大量數(shù)據(jù)載入緩沖池,并老化同等數(shù)量的舊數(shù)據(jù),即使不再使用新數(shù)據(jù)也是如此。預(yù)讀后臺(tái)線程加載且僅訪問(wèn)一次的頁(yè)面將移到新列表的開(kāi)頭。這些情況可能會(huì)將熱數(shù)據(jù)擠壓到舊的列表或者淘汰。我們可以通過(guò)以下幾種方法來(lái)優(yōu)化:
- 調(diào)整innodb_old_blocks_pct參數(shù):為較小的值可以使僅讀取一次的數(shù)據(jù)不會(huì)占用緩沖池的很大一部分。掃描小型表時(shí),在緩沖池中移動(dòng)頁(yè)面的開(kāi)銷較小,可以設(shè)置為較大值。
- 防止緩沖池被預(yù)讀攪動(dòng):可以避免由于表或索引掃描而引起的類似問(wèn)題,它們的特征是:通常快速連續(xù)地訪問(wèn)數(shù)據(jù)頁(yè)面幾次,而再也不會(huì)被訪問(wèn)。調(diào)整innodb_old_blocks_time (第一次訪問(wèn)數(shù)據(jù)頁(yè)的時(shí)間窗口,單位MS,在該時(shí)間窗口內(nèi)可以訪問(wèn)頁(yè)面而不將其移到New SubList的頭部),增加此值會(huì)使越來(lái)越多的塊從緩沖池中更快地老化。
- 線程預(yù)讀:根據(jù)順序訪問(wèn)的緩沖池中的頁(yè)面來(lái)預(yù)測(cè)很快需要哪些頁(yè)面。調(diào)整觸發(fā)異步讀取請(qǐng)求所需的順序頁(yè)面訪問(wèn)數(shù)(innodb_read_ahead_threshold)參數(shù)來(lái)執(zhí)行預(yù)讀操作。 InnoDB僅當(dāng)讀取當(dāng)前擴(kuò)展區(qū)的最后一頁(yè)時(shí),才計(jì)算是否對(duì)下一個(gè)擴(kuò)展區(qū)發(fā)出異步預(yù)取請(qǐng)求。如果擴(kuò)展區(qū)順序讀取的頁(yè)面數(shù)大于或等于此參數(shù)則啟動(dòng)整個(gè)后續(xù)擴(kuò)展區(qū)的異步讀取操作。設(shè)值范圍為0-64之間,默認(rèn)為56,。值越高訪問(wèn)檢查越嚴(yán)格。
- 隨機(jī)預(yù)讀:根據(jù)緩沖池中已有的頁(yè)面來(lái)預(yù)測(cè)何時(shí)可能需要該頁(yè)面,而不管這些頁(yè)面的讀取順序如何。需要設(shè)置 innodb_random_read_ahead為on。
如果服務(wù)器資源利用率不高也可以通過(guò)調(diào)整Buffer Pool參數(shù)來(lái)提高資源利用率這里我們就大致說(shuō)幾種(有興趣的話我們單獨(dú)開(kāi)一篇說(shuō)說(shuō)mysql內(nèi)存怎么使用):
- 增加緩沖池實(shí)例大小:在大內(nèi)存機(jī)器上調(diào)整 innodb_buffer_pool_instances來(lái)提高并發(fā)性。
- 增加緩沖池大小:太小會(huì)造成數(shù)據(jù)攪動(dòng),太大會(huì)造成爭(zhēng)用內(nèi)存而導(dǎo)致交換。通常建議將 innodb_buffer_pool_size其配置為系統(tǒng)內(nèi)存的50%到75%。緩沖池大小必須始終等于innodb_buffer_pool_chunk_size* innodb_buffer_pool_instances的倍數(shù)否則Buffer Pool會(huì)自動(dòng)調(diào)整為此規(guī)則。
- 調(diào)整刷盤函數(shù):在某些Linux/Unix版本的系統(tǒng)使用fsync()刷盤時(shí)性能異常差,存在這樣的問(wèn)題可以使用innodb_flush_method參數(shù)設(shè)置為進(jìn)行基準(zhǔn)測(cè)試O_DSYNC。
- noop調(diào)度或時(shí)間調(diào)度程序與本機(jī)AIO一起使用:innodb_use_native_aio(關(guān)于系統(tǒng)調(diào)度程序請(qǐng)參考本文尾部資料:調(diào)整 Linux I/O 調(diào)度器優(yōu)化系統(tǒng)性能)
- 配置緩沖池刷新:緩沖池刷新是由頁(yè)面清理程序線程執(zhí)行的。清理程序線程的數(shù)量由innodb_page_cleaners變量控制默認(rèn)4。 當(dāng)臟頁(yè)百分比達(dá)到innodb_max_dirty_pages_pct_lwm變量定義的低水位標(biāo)記值時(shí),啟動(dòng)緩沖池刷新。默認(rèn)低水位為0,這會(huì)禁用早期的刷新。 盡量提高臟頁(yè)刷盤的利用率。還有innodb_flush_neighbors參數(shù)是指:從緩沖池刷新頁(yè)面是否也刷新其他臟頁(yè)面,0為不刷新,默認(rèn)為1刷新與其連續(xù)的臟頁(yè),2為刷新相同extend上的臟頁(yè)。
- 配置innodb_lru_scan_depth參數(shù):針對(duì)每個(gè)緩沖池實(shí)例指定頁(yè)面清理線程掃描以查找要刷新的臟頁(yè)面的緩沖池LRU列表的下行距離。
我們可以通過(guò)SHOW ENGINE INNODB STATUS來(lái)查看Buffer Pool的狀態(tài):
---------------------- BUFFER POOL AND MEMORY ---------------------- Total large memory allocated 2198863872 Dictionary memory allocated 776332 Buffer pool size 131072 Free buffers 124908 Database pages 5720 Old database pages 2071 Modified db pages 910 Pending reads 0 Pending writes: LRU 0, flush list 0, single page 0 Pages made young 4, not young 0 0.10 youngs/s, 0.00 non-youngs/s Pages read 197, created 5523, written 5060 0.00 reads/s, 190.89 creates/s, 244.94 writes/s Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000 Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s LRU len: 5720, unzip_LRU len: 0 I/O sum[0]:cur[0], unzip sum[0]:cur[0]提示:基于InnoDB上次打印輸出以來(lái)經(jīng)過(guò)的時(shí)間每秒平均值Change Buffer
僅非主鍵索引的二級(jí)索引頁(yè)不在Buffer Pool中時(shí),會(huì)更改這部分緩存,將合并后讀入Buffer Pool再刷到磁盤。先來(lái)看個(gè)圖吧:
非主鍵索引中的插入順序相對(duì)隨機(jī),刪除和修改可能會(huì)影響不相鄰的非主鍵索引頁(yè),最后通過(guò)異步線程將受影響的頁(yè)讀入Buffer Pool時(shí)批量合并更改并寫入磁盤,這將減少每次更改讀取IO的消耗。(如果索引包含降序索引列或主鍵包含降序索引列,則非主鍵索引不會(huì)進(jìn)Change Buffer)。通常情況下當(dāng)我們?cè)诒砩喜僮鱅nsert時(shí)非主鍵索引列的值通常都是未排序的,需要大量IO保證最新?tīng)顟B(tài)。引入Change Buffer后 非主鍵索引的更改將進(jìn)入其中,而不是立即刷新到磁盤。當(dāng)頁(yè)面加載到Buffer Pool時(shí)會(huì)合并更改然后刷盤(適合大量的MDL操作:批量插入等)。當(dāng)然對(duì)于合并率較低的庫(kù)庫(kù)表操作我們可以通過(guò)參數(shù)innodb_change_buffering選擇關(guān)閉或者調(diào)整Change Buffer來(lái)提升性能。它的設(shè)值有以下幾種:
- all:默認(rèn)值:緩沖區(qū)插入,刪除標(biāo)記操作和清除。
- none:關(guān)閉緩沖任何操作。
- inserts:緩沖區(qū)插入操作。
- deletes:緩沖區(qū)刪除標(biāo)記操作。
- changes:緩沖插入和刪除標(biāo)記操作。
- purges:緩沖在后臺(tái)發(fā)生的物理刪除操作。
當(dāng)然根據(jù)庫(kù)表的使用情況,通過(guò)innodb_change_buffer_max_size來(lái)設(shè)置Change Buffer總大小的百分比,默認(rèn)25,最大50。 當(dāng)有大量寫入的操作時(shí)還可以調(diào)整innodb_change_buffer_max_size,否則就出現(xiàn)合并更改跟不上新產(chǎn)生的的條目,從而導(dǎo)致Change Buffer內(nèi)存達(dá)到上限。(可以根據(jù)實(shí)際情況動(dòng)態(tài)設(shè)置)我們可以通過(guò)如下命名查看Change Buffer的狀態(tài):
mysql> SHOW ENGINE INNODB STATUSGChange Buffer狀態(tài)位于INSERT BUFFER AND ADAPTIVE HASH INDEX 標(biāo)題下,內(nèi)容大致如下
------------------------------------- INSERT BUFFER AND? ADAPTIVE HASH INDEX ------------------------------------- Ibuf: size 1, free list len 0, seg size 2, 0 merges merged operations:insert 0, delete mark 0, delete 0 discarded operations:insert 0, delete mark 0, delete 0 Hash table size 4425293, used cells 32, node heap has 1 buffer(s) 13577.57 hash searches/s, 202.47 non-hash searches/sLog Buffer
保存要寫入磁盤上的日志文件的數(shù)據(jù)。日志緩沖區(qū)大小由innodb_log_buffer_size變量定義 。默認(rèn)大小為16MB。Log Buffer的內(nèi)容會(huì)定期刷新到磁盤。較大的日志緩沖區(qū)使大型事務(wù)可以運(yùn)行,而無(wú)需在事務(wù)提交之前將redo log數(shù)據(jù)寫入磁盤。如果您有很多行的寫事務(wù),則增加Log Buffer的大小可以節(jié)省磁盤的IO開(kāi)銷。innodb_flush_log_at_trx_commit 變量控制如何將Log Buffer區(qū)的內(nèi)容寫入并刷新到磁盤。該 innodb_flush_log_at_timeout 變量控制日志刷新頻率。
Adaptive Hash Index
該功能可以在InnoDB不犧牲事務(wù)功能或可靠性的情況下,在工作線程Buffer Pool有足夠內(nèi)存的的系統(tǒng)上充當(dāng)內(nèi)存數(shù)據(jù)庫(kù)使用,使用innodb_adaptive_hash_index 變量啟用。 自適應(yīng)哈希索引是根據(jù)觀察者模式查找由索引關(guān)鍵字前綴構(gòu)建的哈希索引,該前綴可以是任何長(zhǎng)度,可以是Hash Tree索引中僅B Tree中的某些值出現(xiàn)。它是根據(jù)經(jīng)常訪問(wèn)的索引頁(yè)的需求而建立的 ,模糊查找與范圍查找不適用,在并發(fā)情況下回造成資源爭(zhēng)搶。由于很難預(yù)先預(yù)測(cè)自適應(yīng)哈希索引功能是否適合特定的系統(tǒng)和工作負(fù)載,因此請(qǐng)考慮啟用和禁用該功能的基準(zhǔn)測(cè)試。
參考閱讀資料:
- 調(diào)整 Linux I/O 調(diào)度器優(yōu)化系統(tǒng)性能:https://www.ibm.com/developerworks/cn/linux/l-lo-io-scheduler-optimize-performance/index.html
- Benefits of Using InnoDB Tables :https://dev.mysql.com/doc/refman/5.7/en/innodb-benefits.html
總結(jié)
以上是生活随笔為你收集整理的禁用内存清理_MySql那些事儿(二):InnoDB架构介绍之内存篇的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: excel怎么筛选多个条件
- 下一篇: 高一数学集合知识点整理_高一数学知识点总