Linux

嚴重的寫入性能問題

  • November 19, 2009

$$ 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=writebackmount 選項而不是預設的data=ordered. 面對伺服器崩潰,您將犧牲可靠性,但如果您的性能受到如此糟糕的影響,那也不是什麼大損失。

不過,長期的解決方案可能是切換到更好的文件系統。目前我會推薦 XFS。我已經使用了多年,沒有出現大問題。唯一的缺點是它不能像 ext2/3 一樣被縮小——雖然它可以被擴展。

引用自:https://serverfault.com/questions/1276