昨天公司的一台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处理》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- .NET/C# 如何获取当前进程的 CPU 和内存占用?如何获取全局 CPU 和内存占用?
- 使用python实现统计Nginx进程所占用的物理内存
- shell脚本监控系统中占用CPU,内存最大的进程
- 原 荐 java计算对象占用内存大小:lucene专用于计算堆内存占用大小的工具类
- mariadb 内存占用优化
- MariaDB内存占用优化
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
精通CSS与HTML设计模式
Michael Bowers / 刘申 朱瑜敏 鲁奇 / 人民邮电出版社 / 2008-9 / 69.00元
本书是一部非常实用的CSS 与HTML(XHTML)解决方案手册。书中包含了350 多种可以立即使用的设计模式(涉及文本、背景、边框、图片、表格、布局等多方面),并介绍了每种模式的原理和使用。每种设计模式、示例和源代码都经过了精心设计,易于实现和使用。通过阅读此书,可大大提高读者在 Web 设计和开发中的效率和创造力。 本书结构清晰,示例丰富,实践性强,适用于所有Web 开发和设计人员......一起来看看 《精通CSS与HTML设计模式》 这本书的介绍吧!