昨天公司的一台NFS服务器遭遇IO居高不下的情况 ,通过iostat查看,io使用率在80%以上,时常还会直接IO飙满,导致NFS的访问异常。重启主机后问题依旧,最后使用iotop查看后,发现主要是jbd2进程在写导致的。具体见下图iotop的结果:
jbd2是ext4文件系统的一部分。为什么会使用如何此的IO。首先想到的是ext4写日志,不过机器自身文的变动(及写或更新)并不大,后来网上查找后发现。ext4文件系统出现过bug,bug原理大致是,文件的写和请求会导致其中一个int型的值不断增大,最后增大到超出了自身的范围 —— 变成负值 。就会触发该bug ,而想要达到该值并不容易,需要几个月后才会出现。详细的原理不再解释(关键详细的我也看不懂),有兴趣的可以参看如下两篇:
http://blog.donghao.org/2013/03/20/修复ext4日志(jbd2)bug/
http://www.udpwork.com/item/10217.html
在ubuntu论坛上也看到有人反映此类问题: http://ubuntuforums.org/showthread.php?t=2170496
而且以上几个地方都有一个共性的地方,就是提出该情况的时间都是在2013年中旬的时候。所以综合以上信息得出的结果就是这是一个内核ext4文件系统的bug,时间已经过去四五个月的时间。既然当时网上已经有人提供了临时修复补丁 ,官方kernel里也应该做了相应的更新。所以处理该问题的优先级为:
1、yum升级kernel ,重启查看是否有效。(在此之前先要做好备机使用的准备工作)
2、重 装系统分区,完成后重新挂载数据分区。
3、验证临时补丁的可用性。并在现网修复。
最终在使用第一部 yum update更新kernel后,重启主机 。发现IO恢复正常 。jbd2进程的使用恢复到正常水平
之前遇到过 jbd2 引起 IO 高的问题,直接关掉了日志的功能解决的。写了一个文章,但写的不够细。最近又见类似问题,这里重新整理下对 jbd2 的内容。
什么原因会导致jbd2引起IO高?
1. 磁盘满 .
2. 系统 bug ;所知 bug 号: Bug 39072 – jbd2writes on disk every few seconds 。
3. 即使没有以上问题。在 ext4 上有一个新加入的参数 barrier ,是用来保证文件系统的完整性的。 [Barrier 解释 ] ( https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/block/barrier.txt?id=09d60c701b64b509f328cac72970eb894f485b9e )。
这个值默认是 1 ,即是打开状态。在这个状态下,打开 jbd2 也是会导致性能下降的,这个玩意的设计逻辑就是为了损失掉性能保证文件完整性。
这是个选择题,要么不用它,要么性能差。
但是这个功能不能和设备映射器同时使用,也即是,如果你使用了逻辑卷、软 RAID 、多路径磁盘,则这个值不生效。
jbd2 是个什么?
1. The Journaling Block Device (JBD) provides a filesystem-independent interface for filesystem journaling. ext3, ext4 and OCFS2 areknown to use JBD. OCFS2 starting from Linux 2.6 . 28 [ 1 ] and ext4 use a fork ofJBD called JBD2.[ 2 ]
文件系统的日志功能,jbd2是ext4文件系统版本。
检查是否存在jbd2进程
1. [root@7dgroup2~]# ps -ef|grep jbd2
2. root 267 2 0 Aug21 ? 00 : 06 : 17 [jbd2/vda1- 8 ]
3. root 24428 22755 0 09 : 48 pts/ 0 00 : 00 : 00 grep --color= auto jbd2
4. [root@7dgroup2~]#
检查文件系统的功能
1. [root@7dgroup2~]# dumpe2fs /dev/vda1 | grep has_journal
2. dumpe2fs 1.42 . 9 ( 28 - Dec - 2013 )
3. Filesystem features: has_journalext_attr resize_inode dir_index filetype needs_recovery sparse_super large_file
4. [root@7dgroup2~]#
存在has_journal。
问题现象
在使用iotop看的时候,会有如下信息出现。
1. Total DISK READ: 46.15 M/s | Total DISK WRITE: 8.24 K/s
2. TID PRIO USER DISKREAD DISK WRITE SWAPIN IO> COMMAND
3. 4036 be/ 4 search 56.87 K/s 26.45 K/s 0.00 % 87.64 % [jbd2/dm- 0 - 4 ]
解决方案一
关闭日志功能。
1. tune2fs -ojournal_data_writeback /dev/vda1
2. tune2fs -O "^has_journal" /dev/vda1
3. e2fsck -f /dev/vda1
如果使用tune2fs时候,提示disk正在mount,如果是非系统盘下,你可以使用
1. fuser -km /home # 杀死所有使用/home下的进程
2. umount /dev/vda1 #umount
之后在使用上面的命令进行移除has_journal。
解决方案二
如果是bug的话,可以用这种方式解决。如果是不是bug,这种方式也解决不了,所以要先判断下引起问题的原因再选择解决方案。
升级系统内核。
1. yum updatekernel
解决方案三
禁用Barrier的同时修改commit的值。这个方式可以解决barrier引起的性能下降,但是解决不了系统bug的问题。
修改commit值,降低文件系统提交次数或者禁用barrier特性; 建议文件系统参数为:
1. defaults,noatime,nodiratime,barrier= 0 ,data=writeback,commit= 60
然后重新挂载。
1. mount -o remount,commit= 60 /data
其中barrier=0是禁用barrier特性,commit=60是减少提交次数。 减少提交次数只能缓解。
解决方案四
如果不是bug,并且不想禁用barrier时,用此方式缓解。
想尽办法降低IO,缓解IO压力。这种方式也会导致其他系统资源用不上去。比如说在 mysql 中把syncbinlog加大,同时将innodbflushlogattrxcommit增加。 比如说在应用中减少IO的读写。
bug 的根源
在之前的版本中出现问题有一个原因是ext4文件系统出现bug。 这个bug出现的比较早了,我看kerneltracker里最早的信息是2011年,如果如果是用的老版本,我建议先做升级。如果没有升级条件,只能用上面的关闭日志功能的解决方案。
bug 原因是: 在这段代码中:
1. int __jbd2_log_start_commit( journal_t *journal, tid_t target)
2. {
3. /*
4. * Are we alreadydoing a recent enough commit?
5. */
6. if (!tid_geq(journal->j_commit_request,target)) {
7. /*
8. * We want a new commit: OK, mark the request and wakup the
9. * commit thread. We do _not_ do the commit ourselves.
10. */
11. journal->j_commit_request = target;
12. jbd_debug( 1 , "JBD:requesting commit %d/%dn" ,
13. journal->j_commit_request,
14. journal->j_commit_sequence);
15. wake_up(&journal->j_wait_commit);
16. return 1 ;
17. }
18. return 0 ;
19. }
中的tid_geq的函数是这样实现的。
1. static inline int tid_geq( tid_t x, tid_t y)
2. {
3. int difference = (x - y);
4. return (difference >= 0 );
5. }
假设jcommitrequest值为2157483647,而target的值为0,看上去 if (!tidgeq(journal->jcommit_request,target))这个判断是不会走的。 但是unsigned int的x减去0之后,转为difference时,difference的定义是int型,此时的结果是多少呢?是-2137483649。 为什么呢?因为unsigned int类型的最大值是2147483647。
1. printf ( "%d.n" , 0x7FFFFFFF );
而2157483647 – 0的这个结果显然溢出了,变成了负数。比如,你可以尝试这样打印。
1. printf ( "%d.n" , 0x8FFFFFFFF );
结果就变成了:-1。 有兴趣的,可以自己写个简单的源码试一下。
1. #include <stdio.h>
2.
3. int main( void )
4. {
5. unsigned int x= 2157483647 ;
6. unsigned int y= 0 ;
7. int diff= 0 ;
8. diff = x - y;
9. printf ( "the diff is %ld.n" , diff);
10. return 0 ;
11. }
执行之后是什么呢?
1. the diff is - 2117515188. .
可见在这种情况下,因为溢出的变量导致if(!tidgeq(journal->jcommit_request, target))走到了。
这个unsigned int的变量是jbd2给每个transaction的tid,tid是一直增加的,因为这个类型容易溢出,所以用tidgeq来判断下,意思是2157483647这个tid已经提交了,所以把1000号的transaction commit掉,于是执行了wakeup(&journal->jwaitcommit);。但是执行之后才发现,原来并没有运行中的事务,于是系统就疯了。在trace jbd2的可以看到target有0的情况。实际上,大部分的target都不会是0,这个0是因为ialloc.c中的idatasynctid没有正确赋值,所以使用了默认的0。 idatasynctid是在创建inode或者ext4iget()时更新的,如果应用在打开某些文件后就不再关闭,只是一直更新,这时extent树是不变的(ext4使用extent取代了传统的block映射方式),但是jcommit_request随着jbd2日志的提交而不断增加,所以最后这个差值会在业务运行到一定时间之后出现负值。如果是这个bug引起的话,可以看到的现象是jbd2这个进程长时间占着99%的IO。
影响版本
有此问题的os版本,只根据我使用过的版本列的:
1. CentOS6 . 5 - 64bit
2. CentOS6 . 9 - 64bit
内核版本:
1. 2.6 . 32 - 131.0 . 15.el6.x86 _64
以上所述就是小编给大家介绍的《centos6下jbd2进程占用大量IO处理》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Google's PageRank and Beyond
Amy N. Langville、Carl D. Meyer / Princeton University Press / 2006-7-23 / USD 57.50
Why doesn't your home page appear on the first page of search results, even when you query your own name? How do other web pages always appear at the top? What creates these powerful rankings? And how......一起来看看 《Google's PageRank and Beyond》 这本书的介绍吧!
随机密码生成器
多种字符组合密码
XML、JSON 在线转换
在线XML、JSON转换工具