嚴重的寫入性能問題
$$ Sorry, I tried to stay short but it just was not possible $$ 我在 Fujitsu Siemens Primergy RX200 S3 上執行 Linux 2.6.22.19 和linux - vserver 2.3.0.34用於開發目的。Intel(R) Xeon(R) 5140 @ 2.33Ghz,4GB RAM(其中大部分 500MB 仍然可用)。伺服器有兩個熱插拔 250GB 用於鏡像 RAID 配置:
dev:~# mpt-status --newstyle ioc:0 vol_id:0 type:IM raidlevel:RAID-1 num_disks:2 size(GB):231 state: OPTIMAL flags: ENABLED ioc:0 phys_id:0 scsi_id:1 vendor:ATA product_id:WDC WD2500JS-55N revision:2E01 size(GB):232 state: ONLINE flags: NONE sync_state: 100 ASC/ASCQ:0xff/0xff SMART ASC/ASCQ:0xff/0xff ioc:0 phys_id:1 scsi_id:8 vendor:ATA product_id:WDC WD2500JS-55N revision:2E01 size(GB):232 state: ONLINE flags: NONE sync_state: 100 ASC/ASCQ:0xff/0xff SMART ASC/ASCQ:0xff/0xff scsi_id:0 100% scsi_id:1 100%
我正在執行LVM和 ext3。
我們從 2007 年 7 月/8 月左右開始使用這台機器,除了同一天修復的損壞的 RAM 之外,沒有任何問題。而且,基本上,一切都比我們以前的機器好。
然而,性能問題是在 2008 年 8 月左右首次發現的,直到最近我才對問題的出處充滿信心。現在平均有七台虛擬伺服器在執行(三台 MySQL 機器、兩台 tomcat、三台 Apache、Hudson、CruiseControl、MediaWiki、Samba 等)。但不要產生錯誤的印象,就開發人員和其他訪問伺服器的人而言,我們是一家小公司,所以沒有那麼多事情發生(瀏覽 MediaWiki,Hudson 自動化在晚上執行,大多數 Apache/PHP 應用程序有很多靜態內容)。
安裝 munin 後,我開始看到有趣的東西,尤其是在夜間。由於在每個虛擬伺服器中都在
find
執行(同時,無處不在)負載猛增到像 15、17 或 20 這樣的虛數。但最終問題不僅存在於夜間(我開始禁用查找工作,反正沒有使用),而且在白天,特別是當我們最近開始一個項目時,我們必須使用數據庫一個 500MB 的 MySQL 轉儲文件。
我第一次在工作時間導入轉儲文件(
mysql < dump.sql
; 在我們的一個執行 MySQL 實例的虛擬伺服器中),定時輸出是:real 71m28.630s user 0m15.477s sys 0m10.185s
由於我沒有註意並且正在開會,所以只是我的同事問我伺服器出了什麼問題,因為他非常慢。
我在晚上重新進行了測試,在主機上安裝了一個 vanilla Debian MySQL(不是在來賓內部;關閉所有這些)並達到以下數字:
real 48m33.067s user 0m15.397s sys 0m13.517s
我還是覺得是的,很好,這是 500MB 的轉儲文件;轉儲到 InnoDB 空間大約需要 1GB,這是相當多的數據。我做了一些測試,比如在這樣的測試期間將一行寫入文件
vim
並使用 strace 擷取它:0.000048 write(1, "\33[?25l\"foo\" \33[78;7H\33[K", 22) = 22 0.000033 stat64("foo", 0xbfda1f04) = -1 ENOENT (No such file or directory) 0.000033 open("foo", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4 0.000035 write(4, "thios isthis ia a testa\n", 24) = 24 0.000144 fsync(4) = 0 7737.631089 stat64("foo", {st_mode=S_IFREG|0664, st_size=24, ...}) = 0 0.000084 close(4) = 0 0.000117 write(1, "\33[78;7H[New] 1L, 24C written", 28) = 28 0.000051 lseek(3, 0, SEEK_SET) = 0 0.000022 write(3, "b0VIM 7.0\0\0\0\0\20\0\0\0\0\0\0\0\0\0\0!\21\0\0mark"..., 4096) = 4096 0.000052 select(1, [0], NULL, [0], {0, 0}) = 1 (in [0], left {0, 0})
這對我來說是一個令人難以置信的事實數字。似乎 stat64 系統呼叫被迫等待轉儲操作完成。更不用說在這樣的轉儲期間在 MediaWiki 中提供頁面也需要幾分鐘。
無論如何,我與我們的託管公司安排了一個測試時間框架,在晚上在我們的生產伺服器上進行測試,我得到了完全不同的畫面:
real 7m4.063s user 0m2.690s sys 0m30.500s
我被吹走了。我還獲得了 Amazon EC2 的測試批准,而且我得到的數字更低(在 m1.large 實例上大約 5 分鐘,其中 MySQL 數據被寫入 EBS 卷以保持永久狀態)。
此外,在導入數據時,其他所有操作都會變得如此緩慢,以至於事情變得無法使用,並且負載迅速上升到 5 或 7(儘管似乎並沒有發生太多事情;看起來程序開始相互阻塞現在的理由)。
然後我開始做bonnie++ 測試,看起來像這樣(我實際上從去年開始進行了一次測試,但我幾乎忘記了)。所以這裡是2008 年 10 月:
Version 1.03 ------Sequential Output------ --Sequential Input- --Random- -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks-- Machine Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP /sec %CP vserver-host 8G 12332 21 12600 3 10290 2 48519 74 52431 6 235.8 0 ------Sequential Create------ --------Random Create-------- -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete-- files /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP 16 +++++ +++ +++++ +++ +++++ +++ +++++ +++ +++++ +++ +++++ +++ vserver-host,8G,12332,21,12600,3,10290,2,48519,74,52431,6,235.8,0,16,+++++,+++,+++++,+++,+++++,+++,+++++,+++,+++++,+++,+++++,+++
這是2009 年 4 月的目前版本:
Version 1.03 ------Sequential Output------ --Sequential Input- --Random- -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks-- Machine Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP /sec %CP vserver-host 8G 9705 16 7268 1 4823 1 29620 45 41336 5 73.1 0 ------Sequential Create------ --------Random Create-------- -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete-- files /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP 16 11678 15 +++++ +++ +++++ +++ +++++ +++ +++++ +++ 27739 31 vserver-host,8G,9705,16,7268,1,4823,1,29620,45,41336,5,73.1,0,16,11678,15,+++++,+++,+++++,+++,+++++,+++,+++++,+++,27739,31
我不知道在哪裡調整什麼來擺脫問題,因為我還不完全確定真正的問題在哪裡/是什麼。我想我開始看不到樹木了。
更新1:
感謝到目前為止的回饋,我首先選擇了可以輕鬆測試而無需安排維護時間的東西。
首先,我測試了 MySQL 轉儲
/dev/null
:dev01:~$ time mysqldump -u root -h db01 database-p >/dev/null Enter password: real 0m18.871s user 0m12.713s sys 0m0.512s
系統負載幾乎不引人注意:
10:27:18 up 77 days, 9:10, 7 users, load average: 0.16, 0.75, 0.67 [...] 10:27:33 up 77 days, 9:10, 7 users, load average: 0.52, 0.79, 0.69
此測試期間的
sar
輸出也沒有顯示任何特別之處:12:11:45 PM DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util 12:11:46 PM dev8-0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 12:11:46 PM dev254-0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 12:11:46 PM dev254-1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 12:11:46 PM DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util 12:11:47 PM dev8-0 5.00 0.00 200.00 40.00 0.18 36.00 20.00 10.00 12:11:47 PM dev254-0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 12:11:47 PM dev254-1 25.00 0.00 200.00 8.00 0.74 29.60 4.00 10.00
然後我在轉儲到文件時執行測試:
dev01:~$ time mysqldump -u root -h db01 database -p >foo.sql real 1m7.527s user 0m13.497s sys 0m2.724s
它所花費的時間對我來說並不奇怪,轉儲以一個 570MB 的文件結束。
但是,負載非常有趣…
10:30:49 up 77 days, 9:14, 7 users, load average: 0.76, 0.89, 0.75 10:30:57 up 77 days, 9:14, 7 users, load average: 1.34, 1.01, 0.79 10:31:05 up 77 days, 9:14, 7 users, load average: 2.13, 1.19, 0.85 10:31:13 up 77 days, 9:14, 7 users, load average: 2.68, 1.32, 0.89 10:31:21 up 77 days, 9:14, 7 users, load average: 3.79, 1.60, 0.99 10:31:29 up 77 days, 9:14, 7 users, load average: 4.05, 1.69, 1.02 10:31:37 up 77 days, 9:14, 7 users, load average: 4.82, 1.93, 1.10 10:31:45 up 77 days, 9:15, 7 users, load average: 4.54, 1.97, 1.12 10:31:53 up 77 days, 9:15, 7 users, load average: 4.89, 2.08, 1.16 10:31:57 up 77 days, 9:15, 7 users, load average: 5.30, 2.22, 1.21 10:32:01 up 77 days, 9:15, 7 users, load average: 5.12, 2.23, 1.22 10:32:05 up 77 days, 9:15, 7 users, load average: 5.03, 2.26, 1.24 10:32:13 up 77 days, 9:15, 7 users, load average: 4.62, 2.22, 1.23
……就像
sar
……12:16:47 PM DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util 12:16:48 PM dev8-0 116.00 0.00 21712.00 187.17 134.04 559.31 8.62 100.00 12:16:48 PM dev254-0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 12:16:48 PM dev254-1 3369.00 0.00 26952.00 8.00 3271.74 481.27 0.30 100.00 12:16:48 PM DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util 12:16:49 PM dev8-0 130.00 0.00 17544.00 134.95 143.78 752.89 7.69 100.00 12:16:49 PM dev254-0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 12:16:49 PM dev254-1 1462.00 0.00 11696.00 8.00 2749.12 1407.78 0.68 100.00 12:16:49 PM DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util 12:16:50 PM dev8-0 128.00 0.00 18400.00 143.75 143.68 1593.91 7.84 100.40 12:16:50 PM dev254-0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 12:16:50 PM dev254-1 810.00 0.00 6480.00 8.00 1598.99 4911.94 1.24 100.40
在這個測試中,我很快開始
vim
做一個簡單的寫測試。自身的載入vim
也很緩慢,但我無法從strace
. 只有掛起的stat64
呼叫再次清晰可見:0.000050 stat64("bla", 0xbf98caf4) = -1 ENOENT (No such file or directory) 0.000038 open("bla", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4 0.000053 write(4, "fooo\n", 5) = 5 0.000051 fsync(4) = 0 5.385200 stat64("bla", {st_mode=S_IFREG|0664, st_size=5, ...}) = 0 0.000073 close(4) = 0
我會盡快追加進一步的文件系統測試。
更新 2 / 解決方案:
根據 Mihai 關於 MTP 設備和 RAID 配置的回饋,我對該主題進行了深入研究。通過
lspci
我檢索到 RAID 控制器資訊:dev:~$ sudo lspci|grep -i lsi 05:05.0 SCSI storage controller: LSI Logic / Symbios Logic SAS1068 PCI-X Fusion-MPT SAS (rev 01)
出乎意料的是,a 在http://www.ask.com/web?q=linux+problem+performance+SAS1068上試了一下,發現LSI Logic SAS1068 存在寫入性能問題。錯誤描述進一步連結到部落格談論DELL PE860 性能問題,該問題也使用 SAS1068。
文章提到了LSIUtil 的使用,可從 lsi.com 獲得。這篇文章還
lsiutil
詳細介紹了描述如何打開寫入記憶體的菜單。毫不奇怪,事實證明這對性能有重大影響。啟動前:
dev:~# time (dd if=/dev/zero of=bigfile count=1024 bs=1M; sync) 1024+0 records in 1024+0 records out 1073741824 bytes (1.1 GB) copied, 180.902 seconds, 5.9 MB/s real 3m8.472s user 0m0.004s sys 0m3.340s
啟用寫記憶體後:
dev:~# time (dd if=/dev/zero of=bigfile count=1024 bs=1M; sync) 1024+0 records in 1024+0 records out 1073741824 bytes (1.1 GB) copied, 43.7899 seconds, 24.5 MB/s real 0m46.413s user 0m0.000s sys 0m3.124s
這就像白天和黑夜,黑白。有時感覺自己很愚蠢是可以的。我可能應該知道 RAID 控制器預設禁用寫記憶體。
更新 3:
我偶然發現了一個名為diskstat的 munin 外掛,它為所有塊設備提供了詳細的 IO、讀/寫/等待等圖表。作者還有一篇非常不錯且詳細的博文,標題為Graphing Linux Disk I/O statistics with Munin。
這裡有一些來自其他海報的關於排除軟體和調整 RAID 性能的好建議。值得一提的是,如果您的工作負載寫入繁重,那麼如果您正在考慮更換套件,那麼選擇具有電池支持的寫入記憶體的硬體可能是正確的做法。
這對我來說是一個令人難以置信的事實數字。似乎 stat64 系統呼叫被迫等待轉儲操作完成。
這就是你要找的線索。我敢打賭,這裡的罪魁禍首是 ext3。預設情況下,在 ext3 下,任何使用者帳戶下的任何應用程序發出的任何 fsync 都會強制將整個日誌寫入磁碟。如果您正在執行經常需要發出 fsync() 呼叫的數據庫,這尤其令人討厭。在不支持寫屏障的 RAID 設備上執行時,這更加煩人(不知道 MPT 設備是否支持它們,抱歉。)
如果您對 UPS 和伺服器的穩定性有相當的把握,請嘗試使用
data=writeback
mount 選項而不是預設的data=ordered
. 面對伺服器崩潰,您將犧牲可靠性,但如果您的性能受到如此糟糕的影響,那也不是什麼大損失。不過,長期的解決方案可能是切換到更好的文件系統。目前我會推薦 XFS。我已經使用了多年,沒有出現大問題。唯一的缺點是它不能像 ext2/3 一樣被縮小——雖然它可以被擴展。