一條SQL語(yǔ)句埋涧,正常執(zhí)行時(shí)候特別快,有時(shí)候會(huì)突然變得特別慢僵刮,而且很難復(fù)現(xiàn)递礼,它不只是隨機(jī)而且持續(xù)時(shí)間很短。 看上去像數(shù)據(jù)庫(kù)抖了一下 – 原因就是MySQL在刷臟頁(yè)到磁盤盾计。
當(dāng)內(nèi)存數(shù)據(jù)頁(yè)和磁盤數(shù)據(jù)頁(yè)內(nèi)容不一致的時(shí)候售担,這個(gè)數(shù)據(jù)頁(yè)被稱為“臟頁(yè)”。內(nèi)存數(shù)據(jù)寫(xiě)入磁盤后署辉,內(nèi)存和磁盤的數(shù)據(jù)頁(yè)的內(nèi)容就一致了族铆,稱為“干凈頁(yè)”。 不論臟頁(yè)還是干凈頁(yè)哭尝,都存在內(nèi)存里哥攘。
觸發(fā)數(shù)據(jù)庫(kù)的刷臟頁(yè)時(shí)機(jī)
InnoDB的redo log寫(xiě)滿了。這時(shí)候系統(tǒng)會(huì)停止所有更新操作去刷盤材鹦。這種情況應(yīng)該盡量避免逝淹,因?yàn)槌霈F(xiàn)這種情況的時(shí)候,整個(gè)系統(tǒng)就不能再接受更新桶唐,所有更新唄堵住栅葡。
內(nèi)存不足。當(dāng)需要新的內(nèi)存頁(yè)尤泽,內(nèi)存不夠用的時(shí)候欣簇,就要淘汰一些數(shù)據(jù)頁(yè)规脸,空出內(nèi)存給別的數(shù)據(jù)頁(yè)使用。如果淘汰的是“臟頁(yè)”熊咽,就要將臟頁(yè)寫(xiě)到磁盤莫鸭。
InnoDB用緩沖池buffer pool來(lái)管理內(nèi)存,緩沖池中的內(nèi)存頁(yè)有三種狀態(tài):
- 還沒(méi)使用
- 使用了并且是干凈頁(yè)
- 使用了并且是臟頁(yè)
InnoDB的策略是盡量使用內(nèi)存横殴,因此對(duì)于一個(gè)長(zhǎng)時(shí)間運(yùn)行的庫(kù)來(lái)說(shuō)被因,未被使用的頁(yè)面很少。當(dāng)要讀入的數(shù)據(jù)頁(yè)沒(méi)有在內(nèi)存的時(shí)候滥玷,就必須到緩沖池中申請(qǐng)一個(gè)數(shù)據(jù)頁(yè)氏身。這時(shí)候只能把最久不使用的數(shù)據(jù)頁(yè)從內(nèi)存中淘汰掉:如果要淘汰的是一個(gè)干凈頁(yè),就直接釋放出來(lái)復(fù)用惑畴;當(dāng)如果是臟頁(yè)蛋欣,就必須先講臟頁(yè)刷盤,變成干凈頁(yè)后才能復(fù)用如贷。所以刷臟頁(yè)是常態(tài)陷虎。
但是出現(xiàn)以下情況會(huì)明顯影響性能:
- 一個(gè)查詢要淘汰的臟頁(yè)個(gè)數(shù)太多,就會(huì)導(dǎo)致查詢的響應(yīng)事件明顯變長(zhǎng)杠袱。
- 日志寫(xiě)滿尚猿,更新全部堵住,寫(xiě)性能跌為0楣富,這種對(duì)于敏感業(yè)務(wù)來(lái)說(shuō)凿掂,是不能接受的。
- 系統(tǒng)空閑時(shí)候纹蝴。
- MySQL正常關(guān)閉時(shí)候庄萎。
刷盤策略
InnoDB 需要有控制臟頁(yè)比例的機(jī)制,來(lái)盡量避免性能的影響塘安。
-
設(shè)置InnoDB所在主機(jī)的IO能力糠涛,這樣InnoDB可以獲知全力刷臟頁(yè)可以多快。
| innodb_io_capacity = IOPS
case: 如果出現(xiàn)MySQL寫(xiě)入速度很慢兼犯,TPS很低忍捡,而數(shù)據(jù)庫(kù)主機(jī)IO壓力并不大,很可能就是這個(gè)原因切黔。
- InnoDB控制引擎按照“全力”的百分比刷臟頁(yè) - 刷盤速度砸脊。
參考
https://time.geekbang.org/column/article/71806
https://gsmtoday.github.io/2019/02/08/flush/