Discuss New Concept,New Technic,New Tools, Including EAI,BPM,SOA,Tibco,IBM MQ,Tuxedo, Cloud,Hadoop,NoSQL,J2EE,Ruby,Scala,Python, Performance,Scalability,Distributed,HA, Social Network,Machine Learning.

RedHat

Dec 112012
 
 [repost ]RHEL6系列内核writeback问题分析  December 11, 2012  Posted by on December 11, 2012 at 10:11 am RedHat Tagged with: ,  No Responses »

original:http://blog.tao.ma/?p=73

原作者刘峥同学在内网发的帖子,他授权我来发表到blog上。

最近某应用线上机器在升级到2.6.32系列内核后,与此前的2.6.18内核相比,出现磁盘IO持续异常的情况,本文分析了该问题的原因并说明目前的解决方法。

1. 现象

某应用机器近期升级到了淘宝的32内核后,出现磁盘IO较多,磁盘利用率100%的问题。应用预热上线后,开始没有问题,磁盘IO很低,约30秒后,开始出现磁盘IO,主要为写操作,IOPS约为1,000+,写入数据量约每秒15,000个扇区(sector, 1 sector = 512 Bytes),即约7.5M。写入数据量约30-50s后停止,再等待约30秒后重新出现大量磁盘IO。而此前使用的18内核,则没有明显的大量磁盘写IO,并且磁盘利用率很低。

应用的基本情况: mmap了一个大文件,然后对这个文件进行随机的读写。

机器的基本情况:2.6.32-220内核, ext3文件系统

2. 分析:由于是发生了磁盘IO,故推测可能是文件系统或系统回写产生的问题。

2.1 排除文件系统影响
系统使用的是ext3文件系统,由于使用的是mmap(2),故ext3日志系统每5秒一次的提交脏数据对与mmap(2)没有作用,因此排除ext3文件系统存在问题的可能。

2.2 系统回写问题
由于观察到的现象是每30秒出现一次,故在排除文件系统后推测可能是系统30秒一次的脏数据回写造成的问题。

2.2.1 脏页回写说明
在应用程序向mmap(2)过的内存地址写入数据时,系统会产生缺页中断。如果inode的状态不是dirty,则将inode置脏并设置dirted_when为当前时间,以便后面判断脏数据的时间。

2.2.2 18下的脏页回写
18内核下的脏页回写由一个定时器出发(dirty_writeback_centisecs,默认5秒)。在这个过程中,回写线程(pdflush)会遍历所有文件系统上的所有被置脏的inode (sb->s_dirty),然后判断该inode的dirted_when的时间与当前时间的差值是否大于dirty_expire_centisecs(默认30秒),如果大于,则对这个inode的脏页进行回写。回写后,会将inode的状态从dirty置回clean,同时将回写的page从dirty置回clean。

在进行脏页回写的过程中,系统会首先计算出当前系统中所有的脏数据(/proc/meminfo中Dirty Pages的数量),然后循环尝试回写这些脏数据。在循环中,每次仅尝试回写1024个page。如果没有写够且磁盘没有发生拥塞,则认为脏数据已经回写完毕,并返回。

在每次尝试回写1024个page的过程中,会进行上述提到的遍历文件系统脏inode的过程。由于使用了mmap(2),因此每次写入都会将inode重新置脏,因此在写入1024个page后,由于inode的dirted_when已经修改,故不会再进行回写。

可见,18内核在脏页回写的过程中,并没有将所有超过阈值的脏数据都回写到磁盘,因此存在着丢失数据的可能。

2.2.3 32下的脏页回写
32内核脏数据的回写流程与18内核在整体上讲是一致的。但32内核可以保证所有脏数据均写回磁盘。原因是32内核的回写线程 (flusher) 在将脏的inode的数据写回后,当inode仍然有脏页的情况下,并没有将inode放回sb->s_dirty链表中,而是放入了wb->b_more_io链表,这样在循环尝试回写的过程中,会直接尝试回写b_more_io链表上的inode,直到该inode没有脏页为止,所以可以保证所有该inode的脏数据回写到磁盘。

正因上述原因,造成32内核磁盘IO较多。可见,这并不是32内核的bug,而是由于18内核处理脏数据回写流程的不正确,而显得32内核磁盘IO较多。

3. 影响
通过上面分析,可以汇总出会受到此问题影响的应用类型。

3.1 应用类型
1) 使用mmap(2)来处理数据文件
2) 频繁进行覆盖写操作
3) 不进行sync(2)操作来回写脏数据,而是等待系统回写脏数据

3.2 后果
18内核下的此类型应用会在系统掉电后丢失脏数据(默认情况下约系统内存的10%,dirty_background_ratio);

32内核下此类应用的磁盘IO相对18内核可能较高。

4. 解决

4.1 18内核
如果应用可以容忍机器掉电后的数据丢失,则不需要进行任何处理

如果不能容忍数据丢失,则可以升级到32内核,或者需要在写入数据后调用msync(2)操作来手动刷新脏数据。

4.2 32内核
如果应用可以容忍数据丢失,则可以将sysctl中的vm.dirty_writeback_centisecs设置为0

注意:
在将dirty_writeback_centisecs在/etc/sysctl.conf中设置为0后,重启系统出现
fluser线程CPU占用率100%的问题。目前确认这是一个32内核中的bug。该bug仅在
drity_writeback_centisecs设为0时才会出现。目前内核组已经有补丁来解决该问题,线上测试情况良好。

如果应用不能容忍数据丢失,在升级到32内核后,可能造成系统磁盘IO压力较大的情况,这一问题需要应用开发同学进行评估后根据具体应用来进行处理