性能分析解決 jbd2 引起 IO 高問題

      網友投稿 1225 2022-05-28

      前言

      預備知識

      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);

      性能分析之解決 jbd2 引起 IO 高問題

      結果就變成了:-1。 有興趣的,可以自己寫個簡單的源碼試一下。

      #include int main( void ) { unsigned int x=2157483647; unsigned int y=0; int diff=0; diff = x - y; printf ("the diff is %ld.\n", diff); return 0; }

      執行之后是什么呢?

      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小時內刪除侵權內容。

      上一篇:C語言_Linux基本命令與C語言基礎
      下一篇:C++奧賽一本通遞歸題解
      相關文章
      xvideos亚洲永久网址| 亚洲天堂2016| 亚洲av午夜电影在线观看| 久久亚洲精品成人AV| 亚洲精品无码乱码成人| 久久亚洲av无码精品浪潮| 亚洲一级特黄大片在线观看 | 国产亚洲午夜精品| www亚洲精品久久久乳| 极品色天使在线婷婷天堂亚洲| 欧美亚洲国产SUV| 国产成人亚洲精品无码AV大片| 精品亚洲国产成人av| 亚洲?V乱码久久精品蜜桃| 亚洲狠狠爱综合影院婷婷| 久久久久国产亚洲AV麻豆| 国产亚洲精品成人AA片新蒲金| 亚洲欭美日韩颜射在线二| 亚洲国产另类久久久精品小说| 亚洲va无码专区国产乱码| 久久亚洲精品中文字幕| 亚洲精品永久www忘忧草| 久久精品国产亚洲av麻豆蜜芽| 久久精品国产亚洲αv忘忧草| 国产亚洲玖玖玖在线观看| 亚洲乱码中文字幕在线| 国产亚洲综合一区二区三区| 久久亚洲高清综合| 久久91亚洲精品中文字幕| 久久亚洲熟女cc98cm| 亚洲成年网站在线观看| 久久久亚洲精华液精华液精华液| 国产精品亚洲专一区二区三区| 亚洲乱亚洲乱少妇无码| 亚洲国产另类久久久精品| 亚洲精品成人久久| 亚洲中文字幕乱码熟女在线| 国产精品亚洲lv粉色| 国产亚洲AV手机在线观看| 亚洲成人午夜在线| va天堂va亚洲va影视中文字幕 |