DBA某資料庫叢集每日17:00左右會出現一個性能陡降的現象,在10~20秒內主庫出現大量慢查詢。這些查詢本身沒有效能問題,也沒有任何關聯,可以認為是由於資料庫系統負載較重,由於併發導致的慢查詢。通過對全日誌的梳理,已經查明每日17:00左右導致主庫效能下降的問題原因是該時段在執行某定時任務中的一個Update語句。該update語句一次性會對約70萬個row進行更新,引發大量資料庫寫入,是導致資料庫效能下降的直接原因。

1、問題描述 但是還存在一個疑點,那就是該定時任務每天會執行三次,零點,12點和17點,資料的更新量幾乎一致,其中12點和17點均是業務的高峰期,為何只有下午17點會出現大量慢查詢,而上午12點資料庫受到的影響相對較小,沒有出現慢查詢呢? 2、監控資料分析 DBA對當時資料庫系統的狀態進行了分析,12點與17點都存在一個突發的大量資料寫入,對比兩個時間段的innodb效能引數,可以發現:

(1) 兩個時間段Innodb log buffer均有一個突發的寫入

(2) 兩個時間段innodb_log file均有一個突發的寫入

注:對int32高於2^31的資料都顯示為負數,13:30左右的陡降為監控系統的bug,請忽略。

分析 (1),(2) 說明該時間點有一個影響行數較高的突發的寫入操作。

(3) 12點時innodb buffer dirty page有一個突增,但17點左右innodb buffer dirty page 有一個突降

(4) 12點時innodb的資料檔案寫入速度維持在一個相對平緩的水平,而17點左右innodb的資料檔案寫入速度有一個突增。 注:對int32高於2^31的資料都顯示為負數,13:30左右的陡降為bug,請忽略。

(5) 12點時系統IO的BI略有增長,但是不大,而17點時BI有非常大的增長,對系統IO效能有很大的影響。

分析 (3),(4)說明該時間點確實有大量資料寫入,但是12點左右的時候資料以髒頁的形式儲存在buffer pool中,而17點的時候髒頁被大量寫入到磁碟中。通過(5)可以看出12點的時候髒頁是在update操作結束後緩緩刷入磁碟,而17點的時候髒頁被直接刷入磁碟。可見導致資料庫效能陡降的原因就是髒頁刷盤,12點的時候效能沒有明顯相加的原因就是沒有突發的髒頁刷盤。
3、InnoDB資料儲存 InnoDB資料儲存主要分為資料部分和日誌部分。 資料部分稱為tablespace,記錄資料和索引資料都儲存在tablespace中,最小物理儲存單位是page。InnoDB中每一個page的預設大小為16K。tablespace一般使用檔案來儲存,5.1版本中可以將tablespace存放在磁碟裸分割槽中。總之innoDB資料儲存的物理結構是一個以page為最小單位的資料空間。 相對於tablespace資料空間,innoDB通過一個log group作為日誌空間。log group由至少兩個日誌檔案組成,日誌空間每一條記錄都儲存一個tablespace中資料的變化,稱為為mini transaction。日誌空間是一個環狀的結構,寫滿後會從頭部開始寫入。每一條記錄都會按寫入日誌的累積長度(單位為位元組)分配一個記錄號,稱為Log Sequence Number (LSN)。與日誌對應,資料空間中每一個page的頭結構中也記錄著該page對應的LSN,即表明了該資料的新舊程度。 InnoDB資料庫的資料空間和日誌空間都有兩種存在形式,持久化在磁碟上的磁碟資料和記憶體中的buffer資料。 資料檔案的buffer是由Innodb_buffer_pool_size定義的,快取的是執行時正在被使用的資料空間page,其中被寫請求更新,但沒有同步到磁碟上page,稱為dirty page; 日誌檔案的buffer是由Innodb_log_buffer_size定義的,快取的是執行時正在被使用的日誌空間page。日誌buffer刷盤的策略由innodb_flush_log_at_trx_commit確定。 資料buffer和日誌buffer在一些時機會同步到磁碟的對應空間中去,即flush。進行flush的時機包括三種:overflow,checkpoint和commit。 InnoDB認為資料是日誌的一種冗餘,所以日誌寫盤必須早於對應的資料寫盤,這種思想在這三個時機都有體現。 overflow:log buffer是一個環狀結構,最後一個記錄寫滿後會從第一個位置開始寫。日誌記錄被覆蓋之前會被寫入到日誌檔案中去。日誌空間在磁碟上寫入的方式也是環形佇列方式,log group被寫滿後也會覆蓋最早的日誌記錄。InnoDB的checkpoint機制能保證資料必定會在日誌記錄被覆蓋之前寫入到磁碟中去。 當data buffer寫滿後,InnoDB會使用LRU策略清除部分快取。在清除每個buffer page之前都會檢查該page的LSN是否比磁碟上最大的LSN大,即data buffer寫盤速度是否寫的比log buffer快。InnoDB不允許data buffer 比log buffer 寫盤快,當這種情況發生時,InnoDB會觸發log buffer的寫盤,直到log buffer寫盤進度比data buffer快才會進行data buffer page的寫盤。 checkpoint:InnoDB有獨立執行緒負責定期進行checkpoint。InnoDB使用一種叫做Fuzzy Checkpoint的策略,它並不保證所有資料都被完全同步到磁碟上,而是隻能保證: (a) log buffer和data buffer不會超過buffer總量的一定閾值,這保證了buffer可用空間 (b) log buffer寫盤進度比data 寫盤快,InnoDB寫盤基本原則 (c)確保日誌檔案中日誌記錄被覆蓋前,日誌記錄對應的資料page一寫先被寫盤,確保保證log overflow時不存在沒有同步到磁碟上的資料。 commit:commit的時候InnoDB只會對log buffer進行寫盤,而不會寫入對應的data buffer,這一過程交由overflow觸發。

由於innodb對log的空間有預留策略,部分page使用還有其他的用途,實際可用的空間只有80%左右。 4、分析checkpoint增長情況 回到我們出現效能問題的資料庫上來,該資料庫InnoDB log大小為100M*2=200M,實際可用與儲存日誌空間約為160M.

分析innodb log的增長情況。採集了4月20日12點和4月21日17點的innodb狀態資料。此資料通過show engine innodb status\G獲得。 4月20日12點innodb log的增長情況: Update前:10-04-20 11:55:57 Log sequence number 1016 342557090 Log flushed up to 1016 342557090 Last checkpoint at 1016 302781061

Update後:10-04-20 11:56:12 Log sequence number 1016 427706865 Log flushed up to 1016 427706865 Last checkpoint at 1016 302792380

LSN增長了80M左右,checkpoint與最新LSN差距約120M,沒有達到160M,所以checkpoint沒有較大變化。

4月21日17點innodb log的增長情況: Update前:10-04-21 17:04:58 Log sequence number 1018 345302625 Log flushed up to 1018 345301911 Last checkpoint at 1018 243759516

Update後:10-04-21 17:05:14 Log sequence number 1018 426144696 Log flushed up to 1018 426144696 Last checkpoint at 1018 278852487

LSN增長約55M,但checkpoint與最新的LSN差距180M超過160M, log被寫滿,多出的20M log由上述checkpoint規則(c)觸發了這20M日誌對應的dirty pages強制寫盤(監控表明約12000個page被刷盤)。 處於刷盤量峰值的17:05:14採集的innodb status資料顯示存在大量鎖等待的query,而前後10秒的innodb status中幾乎沒有等待的query,即刷盤操作對請求處理有較大影響。 所以在這個資料庫中,增長innodb log file size,則可以儲存更多的log,容忍更多的dirty page在buffer pool中,能減少由於log寫滿觸發的髒頁刷盤情況。 由此可見,innodb buffer pool中的髒頁不僅僅只是由innodb_max_dirty_pages_pct來控制髒頁對於整個buffer pool的最大比例, innodb_log_file_size*innodb_log_files_in_group得到的日誌空間大小也能控制dirty page的總量。當然日誌大小和資料大小沒有一個絕對的比例,這個會由日誌記錄的更新內容的不同而不同。 mysql手冊上說明了innodb的日誌空間(innodb_log_file_size*innodb_log_files_in_group)可以設定為1M至整個innodb buffer pool的大小。 日誌空間大的優點是,checkpoint觸發資料flush的機率小,能容忍更多的髒頁,有更多的機會進行髒頁的merge,最終達到平滑IO,節省IO的目的。 日誌空間大的缺點是:意味著innodb關閉或在crash後的恢復時間會非常慢。 出現異常的資料庫擁有4G innodb buffer pool,但只設置了200M的日誌空間,該值偏小是導致17點出現innodb大量物理寫盤的一個主要原因。 5、總結 導致效能下降的根本原因是資料庫的innodb_log_file_size 設定過小導致。

[該問題的解決方案] 推動業務修改定時任務指令碼,通過分解大操作量的語句或其他方式,平滑資料庫寫入速度,減小資料庫突發寫入量。 調整資料庫innodb_log_file_size,設定為一個更大的值,保證不要出現由於日誌空間的overflow導致的髒頁刷盤。

完成以上調整後,該資料庫叢集的效能陡降問題完全消失。