【引數】Innodb_io_capacity 對於IO穩定性的一些研究
Innodb_io_capacity 對於IO穩定性的一些研究
背景:最近在做一臺線上伺服器IO負載情況的時候發現了以下現象:
24小時的IO_UTIL 的曲線看似風平浪靜,毛刺較少
但當圖片放大到半小時級別的時候發現IO_UTIL即磁碟使用率出現了規律性的波動,見下圖:
本文就將從這個現象觸發,探究出現這樣規律性波動的原因。
Step1: 伺服器上進行實時IO負載檢視
透過iostat -x 1 每隔一秒對IO使用情況進行一次負載檢視。可以看到UTIL有規律性的波動(10秒1次)。
且負載的主要來源在於寫請求(負載高時,wsec/s 也同步升高)
又由於伺服器是MySQL獨佔,所以比較容易的就可以將原因歸結為是MySQL的資料刷寫導致(log/data)。
看到這裡大神們應該已經不難猜到是MySQL內部 src_master_thread 中10_seconds 迴圈搗的鬼了。
為了保證診斷思路的連貫性,接下來還是把當時的操作複述一遍。
Step2: 確定MySQL write IO 來源
由於目前只知道是MySQL資料刷寫導致,那麼究竟是redo-log還是data page flush造成的現在還不知道。
innodb內部關於write的statistics還是比較有限的。因此比較粗暴的寫了個類似於top的perl指令碼 ,監控這些引數。
指令碼如下,有興趣的同學可以展開閱讀
-
use strict;
-
use warnings;
-
use utf8;
-
use DBI;
-
-
-
my $CONFIG_SERVER_IP ='127.0.0.1';
-
my $CONFIG_SERVER_DB='test';
-
my $CONFIG_SERVER_PORT='3306';
-
my $CONFIG_SERVER_USER='user';
-
my $CONFIG_SERVER_PASS='password';
-
my $conf_dbh = DBI->connect("DBI:mysql:$CONFIG_SERVER_DB;host=$CONFIG_SERVER_IP;port=$CONFIG_SERVER_PORT", $CONFIG_SERVER_USER, $CONFIG_SERVER_PASS,{RaiseError => 1}) || die "Could not connect to database: $DBI::errstr";
-
my %last_value_hash;
-
print "data_write\tdata_written\tdblwr_pages_written\tdblwr_writes\tlog_write_req\tos_log_fsync\tos_log_written\tpages_written\n";
-
while(1){
-
my $conf_sth = $conf_dbh->prepare("show global status like '%innodb%'") || die "Prepare error";
-
$conf_sth->execute();
-
while(my $row=$conf_sth->fetchrow_hashref){
-
my $name=$row->{Variable_name};
-
my $value=$row->{Value};
-
-
if( $name eq 'Innodb_data_writes' || $name eq 'Innodb_data_written'
-
|| $name eq 'Innodb_dblwr_pages_written' || $name eq 'Innodb_dblwr_writes'
-
|| $name eq 'Innodb_log_write_requests' || $name eq 'Innodb_os_log_fsyncs'
-
|| $name eq 'Innodb_os_log_written' || $name eq 'Innodb_pages_written'){
-
$last_value_hash{$name}=0 if( !defined($last_value_hash{$name}) );
-
my $value_step=$value-$last_value_hash{$name};
-
$last_value_hash{$name}=$value;
-
print "$value_step\t";
-
}
-
}
-
print "\n";
-
sleep 1;
- }
最後得到引數的波動情況如下:
可以看到 innodb_data_writes / innodb_data_written / innodb_dblwr_pages_written / innodb_pages_written 都有和IO_UTIL一樣有10秒一次的波動。
再結合上iostat中 wsec/s 較大的數值,基本可以確定IO高負載的元兇是data page的flush,而不是redo log的flush(如果是redo log的flush 應該是1秒一重新整理了)
-
data_write data_written dblwr_pages_written dblwr_writes log_write_req os_log_fsync os_log_written pages_written
-
1 79360 0 0 169 1 79360 0
-
1 72192 0 0 127 1 72192 0
-
1 67072 0 0 139 1 67072 0
-
1 69120 0 0 149 1 69120 0
-
1 74752 0 0 128 1 74752 0
-
1 61952 0 0 134 1 61952 0
-
1 71168 0 0 131 1 71168 0
-
1 62976 0 0 126 1 62976 0
-
1 71168 0 0 109 1 71168 0
-
1388 44870144 1367 14 125 6 75776 1367
-
1 66048 0 0 158 1 66048 0
-
1 73728 0 0 144 1 73728 0
-
1 69632 0 0 126 1 69632 0
-
1 75776 0 0 172 1 75776 0
-
1 88576 0 0 151 1 88576 0
-
1 67584 0 0 134 1 67584 0
-
1 80384 0 0 155 1 80384 0
-
1 86528 0 0 191 1 86528 0
-
1 72704 0 0 135 1 72704 0
-
1525 49385984 1504 13 154 5 102400 1504
- 1 74752 0 0 158 1 74752 0
Step3 : Innodb 什麼時候做dirty data page的flush
由於之前對於innodb的資料刷寫也只是略知一二,網上對於刷寫策略也是眾說紛紜,診斷到了這裡貌似就無法深入了。
其實真相就靜靜的躺在那裡:原始碼閱讀。
Innodb寫磁碟的程式碼路徑非常清晰,比較容易閱讀。主要程式碼在 storage/innodb_plugin/Buf/Buf0flu.c 中
程式碼比較冗長這裡就不貼了,主要敘述下大致的呼叫關係。
buf_flush_batch 呼叫 buf_flush_try_neighbors (嘗試刷寫neighbor page)
buf_flush_try_neighbors 呼叫 buf_flush_page (刷寫單個page)
buf_flush_page呼叫buf_flush_write_block_low (實際刷寫單個page)
buf_flush_write_block_low呼叫buf_flush_post_to_doublewrite_buf (將page放到double write buffer中,並準備刷寫)
buf_flush_post_to_doublewrite_buf 呼叫 fil_io ( 檔案IO的封裝)
fil_io 呼叫 os_aio (aio相關操作)
os_aio 呼叫 os_file_write (實際寫檔案操作)
其中buf_flush_batch 只有兩種刷寫方式: BUF_FLUSH_LIST 和 BUF_FLUSH_LRU 兩種方式的方式和觸發時機簡介如下:
BUF_FLUSH_LIST: innodb master執行緒中 1_second / 10 second 迴圈中都會呼叫。觸發條件較多(下文會分析)
BUF_FLUSH_LRU: 當Buffer Pool無空閒page且old list中沒有足夠的clean page時,呼叫。刷寫髒頁後可以空出一定的free page,供BP使用。
從觸發頻率可以看到 10 second 迴圈中對於 buf_flush_batch( BUF_FLUSH_LIST ) 的呼叫是10秒一次IO高負載的元兇所在。
我們再來看10秒迴圈中flush的邏輯:
透過比較過去10秒的IO次數和常量的大小,以及pending的IO次數,來判斷IO是否空閒,如果空閒則buf_flush_batch( BUF_FLUSH_LIST,PCT_IO(100) );
如果髒頁比例超過70,則 buf_flush_batch( BUF_FLUSH_LIST,PCT_IO(100) );
否則 buf_flush_batch( BUF_FLUSH_LIST,PCT_IO(10) );
可以看到由於SSD對於隨機寫的請求響應速度非常快,導致IO幾乎沒有堆積。也就讓innodb誤認為IO空閒,並決定全力刷寫。
其中PCT_IO(N) = innodb_io_capacity *N% ,單位是頁。因此也就意味著每10秒,innodb都至少刷10000個page或者刷完當前所有髒頁。
updated on 2013/10/31: 在5.6中官方的adaptive flush演算法有所改變,但是空閒狀態下innodb_io_capacity對於刷寫page數量的影響仍然不改變。
具體見:文章連結
Step4: 進一步分析找到解決方案
在多次調整 innodb_adaptive_flushing 和 innodb_adaptive_flushing_method 後發現現象沒有任何變化。
這一點也比較容易解釋:因為大批次刷寫的原因是在於10秒迴圈中,innodb認為IO比較空閒,所以根據innodb_io_capacity 全力刷寫;而adaptive只發生在1秒迴圈中。
所以,調整adaptive相關引數實際上不解決問題。
從Step3中的分析可以得出一個比較明顯的結論,減小innodb_io_capacity 後就能很大程度上解決問題。
當我們把innodb_io_capacity從10000調整到200後,並且新增以下配置後:
innodb_adaptive_flush=OFF;
innodb_adaptive_checkpoint=keep_average
可以看到mysql的data written寫入量大量減少,且保持穩定(見下圖,7:31後是引數調整後的結果)
同時從flashcard的硬體寫入量來看,也大量的減少(見下圖)
在5.1.X版本中,最多隻會重新整理100個髒頁到磁碟、合併20個插入緩衝,即使磁碟有能力處理更多的請求,只能會處理這麼多,這樣在更新量較大的時候,髒頁重新整理就可能跟不上,導致效能下降。
但在5.5.X版本里,innodb_io_capacity引數可以動態調整重新整理髒頁的數量,這在一定程度上解決了這一問題。
innodb_io_capacity預設是200,單位是頁,該引數的設定大小取決於硬碟的IOPS,即每秒每秒的輸入輸出量(或讀寫次數)。
可以動態調整引數:set global innodb_io_capacity=2000;
磁碟配置與innodb_io_capacity引數值
innodb_io_capacity | 磁碟配置 |
200 | 單盤SAS/SATA |
2000 | SAS*12 RAID 10 |
5000 | SSD |
50000 | FUSION-IO |
13.7.7.11. Controlling the Master Thread I/O Rate
The master thread in InnoDB is a thread that performs various tasks in the background. Most of these tasks are I/O related, such as flushing dirty pages from the buffer cache or writing changes from the insert buffer to the appropriate secondary indexes. The master thread attempts to perform these tasks in a way that does not adversely affect the normal working of the server. It tries to estimate the free I/O bandwidth available and tune its activities to take advantage of this free capacity. Historically, InnoDB has used a hard coded value of 100 IOPs (input/output operations per second) as the total I/O capacity of the server.
Beginning with InnoDB storage engine 1.0.4, a new configuration parameter indicates the overall I/O capacity available to InnoDB. The new parameterinnodb_io_capacity should be set to approximately the number of I/O operations that the system can perform per second. The value depends on your system configuration. When innodb_io_capacity is set, the master threads estimates the I/O bandwidth available for background tasks based on the set value. Setting the value to 100 reverts to the old behavior.
You can set the value of innodb_io_capacity to any number 100 or greater, and the default value is 200. You can set the value of this parameter in the option file (my.cnf or my.ini) or change it dynamically with the SET GLOBAL command, which requires the SUPER privilege.
參考:
http://mp.weixin.qq.com/s/fsZ0uwNBbBoXJNmv4Y462A
http://www.cnblogs.com/cenalulu/p/3272606.html --原文
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29096438/viewspace-2134208/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- MySQL 5.6 innodb_io_capacity引數效能測試MySql
- SAP QM 穩定性研究功能研習系列1 - 穩定性研究總流程
- 影響資料庫效能與穩定性的幾個重要引數資料庫
- 穩定性
- 對於質數的研究
- Kafka 的穩定性Kafka
- 排序穩定性排序
- 【穩定性】穩定性建設之依賴設計
- 備份後,對資料庫的穩定性檢查資料庫
- 關於對innodb_flush_log_at_trx_commit引數的一些理解MIT
- 淺談系統的不確定性與穩定性
- 【穩定性】從專案風險管理角度探討系統穩定性
- 對於隨機數的一些分析隨機
- App穩定性測試APP
- 雙11在即,分享一些穩定性保障技術乾貨
- 麒麟960評測:穩定性甚於驍龍821
- 引數校驗與國際化:提高程式碼穩定性和可維護性的重要方法
- 【譯】對Rust中的std::io::Error的研究RustError
- ORALCE的執行計劃穩定性
- kafka-穩定性-事務Kafka
- 土耳其里拉崩潰突出了比特幣的相對穩定性比特幣
- 這是阿里技術專家對 SRE 和穩定性保障的理解阿里
- 【Android】【MonkeyDemons】針對性的進行穩定性測試Android
- 【譯】Effective TensorFlow Chapter12——TensorFlow中的數值穩定性APT
- 有數BI大規模報告穩定性保障實踐
- 如何維持網站穩定性的方式?網站
- FastHook——遠超YAHFA的優異穩定性ASTHook
- ORALCE的執行計劃穩定性(zt)
- Node.js 指南(ABI穩定性)Node.js
- app穩定性測試-iOS篇APPiOS
- 研發效能與穩定性保障
- 一些關於IO流的知識點
- 基於Kubernetes的Serverless PaaS穩定性建設萬字總結Server
- 多利熊基於分散式架構實踐穩定性建設分散式架構
- 應對 DevOps 中的技術債務:創新與穩定性的微妙平衡dev
- SQL引數資料型別text對於replace函式的引數1無效SQL資料型別函式
- 伺服器的穩定性怎麼檢測?伺服器
- 軟體穩定性測試的測試點