性能分析之解決 jbd2 引起 IO 高問題
前言
預備知識
jbd2 是什么?
檢查是否存在 jbd2 進程
檢查文件系統的功能
前言
預備知識
jbd2 是什么?
檢查是否存在 jbd2 進程
檢查文件系統的功能
問題現象
問題原因
解決辦法
方案一
方案二
方案三
方案四
bug 的根源
影響版本
前言
之前遇到過 jbd2 引起 IO 高的問題,直接關掉了日志的功能解決的。最近又見類似問題,這里重新整理下對 jbd2 的內容。
預備知識
jbd2 是什么?
The Journaling Block Device (JBD) provides a filesystem-independent interface for filesystem journaling. ext3, ext4 and OCFS2 are known to use JBD. OCFS2 starting from Linux 2.6.28[1] and ext4 use a fork of JBD called JBD2.[2]
文件系統的日志功能,jbd2 是 ext4 文件系統版本。
檢查是否存在 jbd2 進程
[root@7dgroup2 ~]# ps -ef|grep jbd2 root 267 2 0 Aug21 ? 00:06:17 [jbd2/vda1-8] root 24428 22755 0 09:48 pts/0 00:00:00 grep --color=auto jbd2 [root@7dgroup2 ~]#
檢查文件系統的功能
[root@7dgroup2 ~]# dumpe2fs /dev/vda1 | grep has_journal dumpe2fs 1.42.9 (28-Dec-2013) Filesystem features: has_journal ext_attr resize_inode dir_index filetype needs_recovery sparse_super large_file [root@7dgroup2 ~]#
存在 has_journal。
問題現象
在使用 iotop 看的時候,會有如下信息出現。
Total DISK READ: 46.15 M/s | Total DISK WRITE: 8.24 K/s TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND 4036 be/4 search 56.87 K/s 26.45 K/s 0.00 % 87.64 % [jbd2/dm-0-4]
問題原因
磁盤滿
系統 bug
所知 bug 號:Bug 39072 - jbd2 writes on disk every few seconds
即使沒有以上問題。在 ext4 上有一個新加入的參數 barrier,是用來保證文件系統的完整性的。
[Barrier解釋]()。
這個值默認是1,即是打開狀態。在這個狀態下,打開 jbd2 也是會導致性能下降的,這個玩意的設計邏輯就是為了損失掉性能保證文件完整性。
這是個選擇題,要么不用它,要么性能差。但是這個功能不能和設備映射器同時使用,也即是,如果你使用了邏輯卷、軟RAID、多路徑磁盤,則這個值不生效。
解決辦法
方案一
關閉日志功能
tune2fs -o journal_data_writeback /dev/vda1 tune2fs -O "^has_journal" /dev/vda1 e2fsck -f /dev/vda1
如果使用 tune2fs 時候,提示 disk 正在 mount,如果是非系統盤下,你可以使用:
fuser -km /home #殺死所有使用/home下的進程 umount /dev/vda1 #umount
之后在使用上面的命令進行移除 has_journal。
方案二
如果是 bug 的話,可以用這種方式解決。如果是不是 bug,這種方式也解決不了,所以要先判斷下引起問題的原因再選擇解決方案。
升級系統內核:
yum update kernel
方案三
禁用 Barrier 的同時修改 commit 的值。這個方式可以解決 barrier 引起的性能下降,但是解決不了系統 bug 的問題。
修改 commit 值,降低文件系統提交次數或者禁用 barrier 特性;
建議文件系統參數為:
defaults,noatime,nodiratime,barrier=0,data=writeback,commit=60
然后重新掛載
mount -o remount,commit=60 /data
其中 barrier=0 是禁用 barrier 特性,commit=60 是減少提交次數。減少提交次數只能緩解。
方案四
如果不是 bug,并且不想禁用 barrier 時,用此方式緩解。
想盡辦法降低 IO,緩解 IO 壓力。這種方式也會導致其他系統資源用不上去。 比如說在 mysql 中把 syncbinlog 加大,同時將innodbflushlogattrxcommit 增加。 比如說在應用中減少 IO 的讀寫。
bug 的根源
在之前的版本中出現問題有一個原因是 ext4 文件系統出現 bug。 這個 bug 出現的比較早了,我看 kernel tracker 里最早的信息是2011 年,如果如果是用的老版本,我建議先做升級。如果沒有升級條件,只能用上面的關閉日志功能的解決方案。
bug 原因是,在這段代碼中:
int __jbd2_log_start_commit(journal_t *journal, tid_t target) { /* * Are we already doing a recent enough commit? */ if (!tid_geq(journal->j_commit_request, target)) { /* * We want a new commit: OK, mark the request and wakup the * commit thread. We do _not_ do the commit ourselves. */ journal->j_commit_request = target; jbd_debug(1, "JBD: requesting commit %d/%d\n", journal->j_commit_request, journal->j_commit_sequence); wake_up(&journal->j_wait_commit); return 1; } return 0; }
以上代碼中的 tid_geq 的函數是這樣實現的。
static inline int tid_geq(tid_t x, tid_t y) { int difference = (x - y); return (difference >= 0); }
假設 jcommitrequest 值為 2157483647,而 target 的值為0,看上去 if (!tidgeq(journal->jcommit_request, target)) 這個判斷是不會走的。
但是 unsigned int 的 x 減去 0 之后,轉為 difference 時,difference 的定義是 int 型,此時的結果是多少呢?是-2137483649。 為什么呢?因為 unsigned int 類型的最大值是 2147483647。
printf ("%d.\n", 0x7FFFFFFF);
而 2157483647 - 0 的這個結果顯然溢出了,變成了負數。比如,你可以嘗試這樣打印。
printf ("%d.\n", 0x8FFFFFFFF);
結果就變成了:-1。 有興趣的,可以自己寫個簡單的源碼試一下。
#include
執行之后是什么呢?
the diff is -2117515188..
可見在這種情況下,因為溢出的變量導致if (!tidgeq(journal->jcommit_request, target))走到了。
這個 unsigned int 的變量是 jbd2 給每個 transaction 的 tid,tid 是一直增加的,因為這個類型容易溢出,所以用 tidgeq 來判斷下,意思是 2157483647 這個 tid 已經提交了,所以把 1000 號的t ransaction commit 掉,于是執行了 wakeup(&journal->jwaitcommit);。但是執行之后才發現,原來并沒有運行中的事務,于是系統就瘋了。
在 trace jbd2 的可以看到 target 有 0 的情況。實際上,大部分的 target 都不會是 0,這個 0 是因為 ialloc.c 中的i datasynctid沒 有正確賦值,所以使用了默認的0。 idatasynctid 是在創建 inode 或者 ext4iget() 時更新的,如果應用在打開某些文件后就不再關閉,只是一直更新,這時 extent 樹是不變的(ext4 使用 extent 取代了傳統的 block 映射方式),但是 jcommit_request 隨著 jbd2日志的提交而不斷增加,所以最后這個差值會在業務運行到一定時間之后出現負值。
如果是這個 bug 引起的話,可以看到的現象是 jbd2 這個進程長時間占著 99 %的 IO。
影響版本
有此問題的 os 版本,只根據我使用過的版本統計:
CentOS6.5-64bit
CentOS6.9-64bit
內核版本:
2.6.32-131.0.15.el6.x86_64
Linux 任務調度 應用性能調優
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。