今天发现突然有一台主机无缘无故死机了,于是翻看了/var/log/message日志,发现提示: echo 0 > /proc/sys/kernel/hung_task_timeout_secs;
我们知道进程等待IO时,经常处于D状态,即TASK_UNINTERRUPTIBLE状态,处于这种状态的进程不处理信号,所以kill不掉,如果进程长期处于D状态,那么肯定不正常,原因可能有二: 1)IO路径上的硬件出问题了,比如硬盘坏了(只有少数情况会导致长期D,通常会返回错误); 2)内核自己出问题了。 这种问题不好定位,而且一旦出现就通常不可恢复,kill不掉,通常只能重启恢复了。 内核针对这种开发了一种hung task的检测机制,基本原理是:定时检测系统中处于D状态的进程,如果其处于D状态的时间超过了指定时间(默认120s,可以配置),则打印相关堆栈信息,也可以通过proc参数配置使其直接panic。
完整日志如下:
默认情况下, Linux会最多使用40%的可用内存作为文件系统缓存。当超过这个阈值后,文件系统会把将缓存中的内存全部写入磁盘, 导致后续的IO请求都是同步的。将缓存写入磁盘时,有一个默认120秒的超时时间。
出现上面的问题的原因是IO子系统的处理速度不够快,不能在120秒将缓存中的数据全部写入磁盘。IO系统响应缓慢,导致越来越多的请求堆积,最终系统内存全部被占用,导致系统失去响应。
这个Linux延迟写机制带来的问题,并且在主机内存越大时,出现该问题的可能性更大。这篇文章也提到This is a know bug。
This is a know bug. By default Linux uses up to 40% of the available memory for file system caching. After this mark has been reached the file system flushes all outstanding data to disk causing all following IOs going synchronous. For flushing out this data to disk this there is a time limit of 120 seconds by default. In the case here the IO subsystem is not fast enough to flush the data withing 120 seconds. This especially happens on systems with a lof of memory.
The problem is solved in later kernels and there is not “fix” from Oracle. I fixed this by lowering the mark for flushing the cache from 40% to 10% by setting “vm.dirty_ratio=10” in /etc/sysctl.conf. This setting does not influence overall database performance since you hopefully use Direct IO and bypass the file system cache completely.
链接:nfo-task-blocked-for-more-than-120-seconds
关于脏数据,有几个配置:
vm.dirty_background_ratio 是内存可以填充“脏数据”的百分比。这些“脏数据”在稍后是会写入磁盘的,pdflush/flush/kdmflush这些后台进程会稍后清理脏数据。举一个例子,我有32G内存,那么有3.2G的内存可以待着内存里,超过3.2G的话就会有后来进程来清理它。
那么总结起来,这个问题即因为:业务进程Appxxx出现了段错误,从而需要进行coredump的搜集,同时需要向业务进程发送信号使其终止运行,业务进程在处理信号,退出过程中,需要等coredump搜集完成,从而一直处于D状态,而因为业务进程占用的内存比较大导致收集时间比较长,超过了2分钟,所以出现了阻塞,触发hung task检测,但后来coredump收集完成后就自动恢复了。
vm.dirty_ratio 是绝对的脏数据限制,内存里的脏数据百分比不能超过这个值,如果超过,将强制刷写到磁盘。如果脏数据超过这个数量,新的IO请求将会被阻挡,直到脏数据被写进磁盘。这是造成IO卡顿的重要原因,但这也是保证内存中不会存在过量脏数据的保护机制。
vm.dirty_expire_centisecs 指定脏数据能存活的时间。在这里它的值是30秒。当 pdflush/flush/kdmflush 进行起来时,它会检查是否有数据超过这个时限,如果有则会把它异步地写到磁盘中。毕竟数据在内存里待太久也会有丢失风险。
vm.dirty_writeback_centisecs 指定多长时间 pdflush/flush/kdmflush 这些进程会起来一次;
页高速缓存是Linux kernel使用的主要的磁盘缓存技术。磁盘高速缓存是一种软件机制,它允许系统把存放在磁盘上的一些数据保留在内存中,以便对那些数据的再次访问不再需要访问磁盘。
Kernel在读取磁盘时,如果数据页不再高速缓存当中,就会将读出的磁盘数据填充到页高速缓存当中。通过将数据页在高速缓存当中驻留,从而使进程再使用该页时不再需要访问磁盘。
Kernel在把一页数据写到磁盘之前,首先检查页是否已经在高速缓存当中,如果不在,首先会将页数据填充到高速缓存当中。更新到磁盘I/O的动作不是立即进行的,而是会有一点延时,从而使进程有机会对写入的数据进一步修改,这就是内核的延迟写操作。
进程对页高速缓冲区中的数据修改之后,数据页被标记为”脏数据”,即把PG_Dirty标志置位。Linux系统允许对脏数据写入磁盘块设备的延迟操作,被认为是显著增加了系统I/O能力的一种机制。
在下列条件下,脏数据写入磁盘中:
1 . 页高速缓存空间不足;
2 . 变脏以来,太久没有过更新;
3 . 进程通过系统调用(sync(),fsync(),fdataasync())强行对快设备的更新同步到磁盘,Msync系统调用来将内存映射下的脏数据刷新到磁盘;
Pdflush内核线程负责定期扫描缓存中脏数据,并在合适时候将其更新到磁盘。定时器一般是500分之一秒,可以通过/proc/sys/vm/dirty_writeback_centisecs文件调整这个值。 Pdflush线程的个数是根据情况动态调整的:
1 . 至少有2个,最多有8个pdflush线程。(通过/proc/sys/vm/nr_pdflush_threads参数)可以修改这些变量的值。
2 . 如果最近1s内,没有空闲的pdflush线程,就创建新的。
3 . 如果pdflush的空闲时间超过了1s,就删除一个pdflush。
Cache - 全称page cache。当进程发起对磁盘的读写操作时,主要用来在内存中缓存磁盘中的数据,与磁盘的同步由pdflush负责。
Buffer – 全称block buffer。Block buffer中存放的是bio结构体数据。BIO 结构体是VFS和 block layer之间的接口。通俗的理解,Block buffer是page cache和磁盘驱动器之间打交道的一层缓存。
系统页高速缓存的使用情况可以通过buffer/cache的监控数据来分析。
从文件读写角度来看,buffer多用于缓存文件的管理信息,如目录位置,inode信息等。Cache缓存的是文件内容。
由于CPU不能直接处理外设上的数据,buffer用来标记那些文件的位置等描述信息。Cache主要目的是增加传输性能,用于缓存文件内容。
有一些更复杂的程序(通常称为自缓存应用程序),更愿意自己控制I/O的传输过程(),通过将O_DIRECT标志位置位,I/O数据的传送便绕过了页高速缓存。 出于以下原因,系统页高速缓存技术是有害的:
1 . 处理页高速缓存的多余指令,降低了read(),write()的效率
2 . Read(),write()系统调用不是在磁盘和用户空间直接传送,而是分成两步:在磁盘和内核空间,>在内核空间到用户空间。 与页高速缓存相关的系统参数
3 . /proc/sys/vm/dirty_background_ratio 表示系统可用内存中,最高可用于存储 dirty 数据的百分比。The maximum of percentage of((cache+free)-mapped)。缺省10%。
4 . /proc/sys/vm/dirty_ratio 表示进程产生的脏数据到达系统整体内存的百分比,此时触发pdflush进程把数据回写到磁盘。缺省设置40.
5 . /proc/sys/vm/dirty_expire_centisecs 表示脏数据在内存中驻留超过该值,pdflush会将该数据回写到磁盘。缺省是3000。
6 . /proc/sys/vm/dirty_writeback_centisecs 表示pdflush周期性间隔多久处理脏数据回写。
我们可以从以下思路进行调优:
修改相应参数
临时修改
# sysctl -w vm.dirty_ratio=10
# sysctl -w vm.dirty_background_ratio=5
# sysctl -p
永久修改
#vi /etc/sysctl.conf
写入
vm.dirty_background_ratio = 5
vm.dirty_ratio = 10
sysctl -p
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。