一文講清MySQL的innodb_log_write_ahead_size參數(shù)
一文講清MySQL的innodb_log_write_ahead_size參數(shù)
MySQL調(diào)優(yōu)的時(shí)候會(huì)遇到一個(gè)參數(shù)innodb_log_write_ahead_size,這個(gè)參數(shù)如果對(duì)計(jì)算機(jī)存儲(chǔ)系統(tǒng)不了解的話很難理解,網(wǎng)上很多文章說的又不是很清晰,所以本文對(duì)該參數(shù)做一個(gè)解析;
要想知道innodb_log_write_ahead_size參數(shù)怎么配置,最重要的就是先了解這個(gè)參數(shù)解決了什么問題,那么這個(gè)參數(shù)是解決什么問題的呢?官網(wǎng)對(duì)該參數(shù)的描述 如下:
Defines the write-ahead block size for the redo log,
in bytes. To avoid “read-on-write”, set innodb_log_write_ahead_size
to match the operating system or file system cache block
size. The default setting is 8192 bytes. Read-on-write occurs
when redo log blocks are not entirely cached to the operating
system or file system due to a mismatch between write-ahead
block size for the redo log and operating system or file system
cache block size.
譯文:
為了避免read-on-write,為redo log定義了write-ahead block size,
單位byte,請(qǐng)將innodb_log_write_ahead_size參數(shù)的大小設(shè)置為操作系
統(tǒng)或者文件系統(tǒng)的緩存塊(對(duì)應(yīng)的就是page cache),默認(rèn)設(shè)置大小是8K,如果該參數(shù)大小設(shè)置的與page cache不匹配那么將會(huì)發(fā)生Read-on-write;
翻譯過來每個(gè)字都認(rèn)識(shí),但是這些字連起來是什么意思呢?如果懂這段話的意思,說明你對(duì)文件系統(tǒng)有一定的了解,那么后邊的內(nèi)容大概率你已經(jīng)知道了,如果 不懂,那么后面就是解釋這句話的意思;
首先,上邊提到的了innodb_log_write_ahead_size主要是解決read-on-write問題的,看來我們需要先知道什么是read-on-write,read-on-write 的描述如下(個(gè)人理解,如果錯(cuò)各位大佬可以指出):
現(xiàn)代操作系統(tǒng)對(duì)磁盤的最小操作單位是page,每次讀取、寫出都
是按照一個(gè)page一個(gè)單位操作的,讀取的時(shí)候沒有特別的問題,但是在寫出的時(shí)候會(huì)有問題,如果要寫出的數(shù)據(jù)所在的磁盤上
的page(邏輯)沒有在內(nèi)存中,那么需要先將磁盤上該page的
數(shù)據(jù)加載到內(nèi)存然后才能寫出,這個(gè)就叫做read-on-write;
read-on-write的簡(jiǎn)要流程圖:

從流程中很容易看出發(fā)生read-on-write的時(shí)候系統(tǒng)會(huì)比沒有read-on-write的時(shí)候多一次read IO,相當(dāng)于原來只需要一次write IO的現(xiàn)在變成了先read IO 然后在write IO,一下工作量翻倍,單這一個(gè)點(diǎn)就造成了我們系統(tǒng)速度下降一半(毛估,還有很多其他因素);如果想要針對(duì)這點(diǎn)優(yōu)化,只要我們不讓這次read IO發(fā)生 不就行了?那如何不讓這次read IO發(fā)生呢?有兩種辦法:
確保寫出數(shù)據(jù)所在的磁盤page已經(jīng)緩存在內(nèi)存中了,而要確保這個(gè)只能先進(jìn)行一次read將數(shù)據(jù)緩存到內(nèi)存,這跟上邊的read-on-write差不多了,只不過是我們手 動(dòng)調(diào)用了一次read IO,雖然沒有發(fā)生系統(tǒng)層面的read-on-write,但實(shí)際上是等效的,所以這個(gè)方案不行;
利用系統(tǒng)的另外一個(gè)特性,即如果IO滿足以下兩個(gè)條件則也不會(huì)發(fā)生
read-on-write:該IO的目的地址是磁盤上某個(gè)page的起始偏移地址;
該IO的數(shù)據(jù)大小是page大小的整數(shù)倍;
為什么如果沒有緩存時(shí)必須發(fā)生一次read-on-write呢?其實(shí)很簡(jiǎn)單,因?yàn)橄到y(tǒng)寫出的最小單位是page,如果不先把磁盤上指定區(qū)域的內(nèi)容加載上來,那么在本次 寫出的時(shí)候會(huì)將舊數(shù)據(jù)覆蓋了,這樣就可能會(huì)導(dǎo)致數(shù)據(jù)丟失,所以只能將原有數(shù)據(jù)加載上來,然后與本次要寫出的數(shù)據(jù)合并然后一次寫出;而第二個(gè)方案的前提條件 其實(shí)就是如果你的數(shù)據(jù)正好把這個(gè)page整個(gè)都覆蓋了,那么無論內(nèi)存中是否有該page的緩存,都可以直接寫磁盤,因?yàn)槟憔褪且采w磁盤上整個(gè)page的區(qū)間,不 存在丟失原有數(shù)據(jù)的問題;
第二個(gè)方案就比較好實(shí)現(xiàn)了,我們不用額外的IO就能讓我們的寫出數(shù)據(jù)滿足該條件,而MySQL中用的也是該方案,而innodb_log_write_ahead_size就是我們告訴 MySQL我們的系統(tǒng)實(shí)際的page size是多少,該值最小要等于page size,如果比page size小就可能會(huì)發(fā)生read-on-write,可以比實(shí)際的page size大,但 是必須是page size的整數(shù)倍;默認(rèn)值是8K,一般大多數(shù)系統(tǒng)的page size都是4K,所以大多數(shù)情況下默認(rèn)值是可以避免read-on-write發(fā)生的;當(dāng)MySQL要寫 出數(shù)據(jù)時(shí),如果寫出數(shù)據(jù)小于innodb_log_write_ahead_size則會(huì)在后邊補(bǔ)0,然后將整個(gè)innodb_log_write_ahead_size的數(shù)據(jù)一次性寫出,使他滿足上邊 的兩個(gè)不觸發(fā)read-on-write機(jī)制的條件從而達(dá)到優(yōu)化IO提高性能的目的(第一個(gè)條件MySQL可以控制滿足,第二個(gè)條件是否真的能滿足就看我們配置的 innodb_log_write_ahead_size 的值,如果配置的不符合條件則也不會(huì));
不加write_ahead機(jī)制的寫出示意圖:




加了write_ahead機(jī)制的寫出示意圖:


innodb_log_write_ahead_size解決什么問題現(xiàn)在已經(jīng)很清楚了,那么到底配多少合適呢?上邊只是說了最小要等于文件系統(tǒng)的的page size,也可以是page size 的整數(shù)倍,那調(diào)整大點(diǎn)兒會(huì)有影響嘛?根據(jù)上邊的圖示可以看出,無論我們寫出多少數(shù)據(jù),MySQL都會(huì)將整個(gè)write_ahead_buffer寫出,也就是如果write_ahead_buffer 值太大的話可能會(huì)對(duì)系統(tǒng)IO有輕微的影響,畢竟本來只需要寫出一個(gè)page就可以的結(jié)果因?yàn)榕渲玫倪^大導(dǎo)致寫了兩個(gè)page甚至更多,還是會(huì)有輕微影響的(實(shí)測(cè)影響確 實(shí)很輕微,配置2-4倍幾乎是無影響的 ),官網(wǎng)對(duì)于這個(gè)也是有說明的,說明如下:
Setting the innodb_log_write_ahead_size value too low
in relation to the operating system or file system cache
block sizeresults in “read-on-write”. Setting the valuetoo high may have a slight impact on fsync performance
for log file writesdue to several blocks being written
at once.
思考
MySQL可以使用這個(gè)優(yōu)化跟MySQL的文件結(jié)構(gòu)有關(guān),MySQL寫出是append write而不是random write的,這個(gè)很重要,如果是random write那么這個(gè)策略就會(huì) 失效,各位可以作為一個(gè)拓展思考回去自己想下,有知道原因的可以在評(píng)論區(qū)打出來;
聯(lián)系我
作者微信:JoeKerouac
微信公眾號(hào)(文章會(huì)第一時(shí)間更新到公眾號(hào),如果搜不出來可能是改名字了,加微信即可=_=|):Java初學(xué)者
GitHub:https://github.com/JoeKerouac
參考文獻(xiàn)
innodb_log_write_ahead_size官方解釋:https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_log_write_ahead_size
