一愚铡、 基本概念:
1、當內存數據頁跟磁盤數據頁內容不一致的時候胡陪,稱這個內存頁為“臟頁”茂附。內存數據寫入到磁盤后(內存里的數據寫入磁盤的過程叫做flush。)督弓,內存和磁盤上的數據頁的內容就一致了,稱為“干凈頁”乒验。不論是臟頁還是干凈頁愚隧,都在內存中。
2、平時執(zhí)行很快的更新操作狂塘,其實就是在寫內存和日志录煤,而MySQL偶爾“抖”一下的那個瞬間,可能就是在刷臟頁(flush)荞胡。
3妈踊、引發(fā)數據庫的flush過程的四種情況:
?1)、第一種情況是InnoDB的redo log寫滿了泪漂。這時候系統會停止所有更新操作廊营,把checkpoint往前推進,redo log留出空間可以繼續(xù)寫萝勤。checkpoint可不是隨便往前修改一下位置就可以的露筒。在把checkpoint位置從CP推進到CP'時,就需要將兩個點之間的日志對應的所有臟頁都flush到磁盤上敌卓。之后慎式,之前可以寫入redo log的區(qū)域就從圖中從write pos到CP之間變?yōu)榱藦膚rite pos 到CP'。
? 2)趟径、第二種情況是系統內存不足瘪吏。當需要新的內存頁,而內存不夠用的時候蜗巧,就要淘汰一些數據頁掌眠,空出內存給別的數據頁使用。如果淘汰的是“臟頁”惧蛹,就要先將臟頁寫到磁盤扇救。如果刷臟頁一定會寫盤,就保證了每個數據頁有兩種狀態(tài):
? ?a香嗓、一種是內存里存在迅腔,內存里就肯定是正確的結果,直接返回靠娱;
? ?b沧烈、另一種是內存里沒有數據,就可以肯定數據文件上是正確的結果像云,讀入內存后返回锌雀。這樣的效率最高。
? 3)第三種情況是MySQL認為系統“空閑”的時候迅诬。當然腋逆,即使是系統“忙碌”的時候,也要見縫插針地找時間侈贷,只要有機會就刷一點“臟頁”惩歉。
? 4)、第四種情況是MySQL正常關閉的時候。這時候撑蚌,MySQL會把內存的臟頁都flush到磁盤上上遥,這樣下次MySQL啟動的時候,就可以直接從磁盤上讀數據争涌,啟動速度會很快粉楚。
4、引發(fā)數據庫的flush過程的四種情況對性能的影響:
? 1)亮垫、“redo log寫滿了模软,要flush臟頁”,這種情況是InnoDB要盡量避免的包警。因為出現這種情況的時候撵摆,整個系統就不能再接受更新了,所有的更新都必須堵住害晦。如果你從監(jiān)控上看特铝,這時候更新數會跌為0。
? 2)壹瘟、“內存不夠用了鲫剿,要先將臟頁寫到磁盤”,這種情況其實是常態(tài)稻轨。InnoDB用緩沖池(buffer pool)管理內存灵莲,緩沖池中的內存頁有三種狀態(tài):第一種是,還沒有使用的殴俱;第二種是政冻,使用了并且是干凈頁;第三種是线欲,使用了并且是臟頁明场。InnoDB的策略是盡量使用內存,因此對于一個長時間運行的庫來說李丰,未被使用的頁面很少苦锨。而當要讀入的數據頁沒有在內存的時候,就必須到緩沖池中申請一個數據頁趴泌。這時候只能把最久不使用的數據頁從內存中淘汰掉:如果要淘汰的是一個干凈頁舟舒,就直接釋放出來復用;但如果是臟頁呢嗜憔,就必須將臟頁先刷到磁盤秃励,變成干凈頁后才能復用。
? 3)吉捶、因為系統處于“空閑”的狀態(tài)中莺治,所以不需要關心其對性能的影響廓鞠。
? 4)、因為數據庫本來就要關閉了谣旁,所以不需要關心其對性能的影響。
5滋早、刷臟頁會明顯影響性能的情況:
? 1)榄审、一個查詢要淘汰的臟頁個數太多,會導致查詢的響應時間明顯變長杆麸;
? 2)搁进、日志寫滿,更新全部堵住昔头,寫性能跌為0饼问,這種情況對敏感業(yè)務來說,是不能接受的揭斧。
二莱革、InnoDB刷臟頁的控制策略:
首先,測試出InnoDB所在主機的IO能力讹开,這樣InnoDB才能知道需要全力刷臟頁的時候盅视,可以刷多快。也就是innodb_io_capacity這個參數旦万,它的作用是告訴InnoDB你的磁盤能力闹击。這個值建議設置成磁盤的IOPS。磁盤的IOPS可以通過fio這個工具來測試成艘,下面的語句是用來測試磁盤隨機讀寫的命令:
fio -filename=$filename -direct=1 -iodepth 1 -thread -rw=randrw -ioengine=psync -bs=16k -size=500M -numjobs=10 -runtime=10 -group_reporting -name=mytest
又因為磁盤能力不能只用來刷臟頁赏半,還需要服務用戶請求。所以InnoDB會控制引擎按照“全力”的百分比來刷臟頁淆两。
1断箫、InnoDB的刷盤速度就是要參考的兩個因素:
?①臟頁比例,參數innodb_max_dirty_pages_pct是臟頁比例上限琼腔,默認值是75%瑰枫。要合理地設置innodb_io_capacity的值,并且平時多關注臟頁比例丹莲,不要讓它經常接近75%光坝。其中,臟頁比例是通過Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total得到甥材。
?②redo log寫盤速度盯另。
2、InnoDB的刷盤速度的計算方法:
InnoDB會根據當前的臟頁比例(假設為M)洲赵,算出一個范圍在0到100之間的數字鸳惯,記為F1(M)商蕴。InnoDB每次寫入的日志都有一個序號,當前寫入的序號跟checkpoint對應的序號之間的差值(假設為N)芝发。InnoDB會根據這個N算出一個范圍在0到100之間的數字绪商,這個計算公式可以記為F2(N)。N越大辅鲸,算出來的值越大格郁。根據上述算得的F1(M)和F2(N)兩個值,取其中較大的值記為R独悴,之后引擎就可以按照innodb_io_capacity定義的能力乘以R%來控制刷臟頁的速度例书。
3、flush臟頁時的鄰居連坐機制:
??在準備刷一個臟頁的時候刻炒,如果這個數據頁旁邊的數據頁剛好是臟頁决采,就會把這個“鄰居”也帶著一起刷掉;而且這個把“鄰居”拖下水的邏輯還可以繼續(xù)蔓延坟奥,也就是對于每個鄰居數據頁树瞭,如果跟它相鄰的數據頁也還是臟頁的話,也會被放到一起刷筏勒。在InnoDB中移迫,innodb_flush_neighbors 參數就是用來控制這個行為的,值為1的時候會有上述的“連坐”機制管行,值為0時表示不找鄰居厨埋,自己刷自己的。找“鄰居”這個優(yōu)化在機械硬盤時代是很有意義的捐顷,可以減少很多隨機IO荡陷。機械硬盤的隨機IOPS一般只有幾百,相同的邏輯操作減少隨機IO就意味著系統性能的大幅度提升迅涮。而如果使用的是SSD這類IOPS比較高的設備的話废赞,建議把innodb_flush_neighbors的值設置成0。因為這時候IOPS往往不是瓶頸叮姑,而“只刷自己”唉地,就能更快地執(zhí)行完必要的刷臟頁操作,減少SQL語句響應時間传透。
三耘沼、如果一個高配的機器,redo log設置太小朱盐,會發(fā)生什么情況群嗤?
??因為每次事務提交都要寫redo log,如果設置太小兵琳,很快就會被寫滿狂秘,write pos一直追著CP骇径。這時候系統不得不停止所有更新,去推進checkpoint者春。這時破衔,你看到的現象就是磁盤壓力很小,但是數據庫出現間歇性的性能下跌钱烟。