摘要
利用systemtap脚本分析系统中dentry SLAB占用过高问题
原创文章:来自systemtap脚本分析系统中dentry SLAB占用过高问题
背景
长时间运行着的tengine主机有内存占用75%以上的报警.
操作系统版本: 2.6.32.el6.x86_64
原因定位
收集内存使用的相关信息如下:
因内存占用率报警mem:76.28%先看一下内存的总体使用状况,从下图中可以看出used占用较高,buffers/cached占用较少(关于cached占用过高的分析处理请参见另一篇文章), 这时首先想到是不是有进程内存泄漏,经查询tengine和别的进程没有发现有占用大量内存即不存在内存泄漏。
cat /proc/meminfo细化查看内存各部分的使用,可以发现slab占用过高约40GB,同时也可以观察到SReclaimable也很高,即SReclaimable指可收回Slab的大小。
详细查看slab中各部分内存的占用,可以看出dentry占用的很多,大约在40GB内存。
dentry的作用:当读写文件时内核会为该文件对象建立一个dentry,并将其缓存起来,方便下一次读写时直接从内存中取出提高效率。
再详细查看一下dentry的使用情况:
$cat /proc/sys/fs/dentry-state
209815031 209805757 45 0 0 0
从上查看dentry使用数量,可以发现有大量unused dentries占用率很高,没有释放掉。
以上数据的详细含义可以man proc查看,下边是可以从网上查到的中文含义
dentunusd:在缓冲目录条目中没有使用的条目数量.
file-nr:被系统使用的文件句柄数量.
inode-nr:使用的索引节点数量.
pty-nr:使用的pty数量.
1)dentunusd
dentunusd数据的数据来源是/proc/sys/fs/dentry-state的第二项数据.
要弄明白它的意义,我们首先要弄明白dcache(目录高速缓存),因为系统中所有的inode都是通过文件名来访问的,而为了解决文件名到inode转换的时间,就引入了dcache.
它是VFS层为当前活动和最近使用的名字维护的一个cache.
dcache中所有处于unused状态和negative(消极)状态的dentry对象都通链入到dentry_unused链表中,这种dentry对象在回收内存时可能会被释放.
如果我们在系统中运行ls -ltR /etc/会看到dentunusd的数量会多起来.
而通过mount -o remount /dev/sda1会看到dentunusd会迅速会回收.
2)file-nr
file-nr的的数据来源是/proc/sys/fs/file-nr文件的第一项数据.
实际上file-nr不是一个准确的值,file-nr每次增加的步长是64(64位系统),例如现在file-nr为2528,实际上可能只打开了2527个文件,而此时你打开两个文件后,它就会变成2592,而不是2530.
3)inode-nr
inode-nr的数据来源是/proc/sys/fs/inode-nr文件的第一项数据减去第二项数据的值.
inode-nr文件的第一项数据是已经分配过的INODE节点.第二项数据是空闲的INODE节点.
例如,inode-nr文件里的值为:13720 7987
我们新建一个文件file1,此时inode-nr第一项数据会加1,就是13721,表示系统里建立了这么多的inode.
我们再删除掉file1,此时就会变成13720.
空闲的INODE节点表示我们已经里这么多的INODE节点曾经有过被利用,但没有被释放.
所以INODE节点总数减去空闲的INODE,就是正在被用的INODE.
最后通过使用mount -o remount /dev/sda1命令,空闲节点会被刷新,所以inode-nr的值会有所变化.
4)pty-nr
pty-nr的数据来源是/proc/sys/kernel/pty/nr
表示登陆过的终端总数,如果我们登录过10回,退出了3回,最后的结果还是10回.
也可用于sar命令查看dentunusd以秒为间隔查看dentry的变化。
$sar -v 1
12:07:09 AM dentunusd file-nr inode-nr pty-nr
12:07:10 AM 183107848 1088 42210 44
12:07:11 AM 183107871 1088 42245 44
12:07:12 AM 183116550 1152 42290 44
12:07:13 AM 183116581 1088 42343 44
12:07:14 AM 183116617 1216 42396 44
12:07:15 AM 183116059 1216 40585 44
关于linux dentry的介绍可以搜出来一大把,包括dentry占用过高,不外乎两种处理方法,一种是直接通过proc系统清理dentry,命令如下:
sudo sh -c "echo 2 > /proc/sys/vm/drop_caches"
缺点是执行命令过程容易hang住几分钟,而且redhat官方也不建议使用这种方式清理cache等;另外一种方法是通过调整内核参数vm.vfs_cache_pressure,含义如下,先调整为vm.vfs_cache_pressure=10000观察一天也没有发现能使dentry降下去。
vm.vfs_cache_pressure控制内核回收用于dentry和inode cache内存的倾向。 默认值是100,内核会根据pagecache和swapcache的回收情况,让dentry和inode cache的内存占用量保持在一个相对公平的百分比上。减小vfs_cache_pressure会让内核更倾向于保留dentry和inode cache。当vfs_cache_pressure等于0,在内存紧张时内核也不会回收dentry和inode cache,这容易导致OOM。如果vfs_cache_pressure的值超过100,内核会更倾向于回收dentry和inode cache。
细节分析
即然上述两个办法都不是完美的方法,就需要确认这么多unused dentries到底是那些文件占用的? 按正常理解情况下linux内核不太可能释放不了dentry。
首先通过查看内核dentry结构部分的代码(fs/dcache.c),搞清楚了所有的unused dentries挂在了super_blocks 结构的s_dentry_lru链表上,可以通过遍历此链表上的节点输出这些节点代表的文件名,就可以知道dentries被那些文件占用。
思路:用systemtap工具做内核探测,将每个节点的文件名写入到log文件。guru模式关键代码如下:
if (!list_empty(&sb->s_dentry_lru)) {
list_for_each_entry(dent, &sb->s_dentry_lru, d_lru) {
spin_lock(&dent->d_lock);
if (dent->d_flags & DCACHE_REFERENCED) {
dcache_referenced_nr++;
}
spin_unlock(&dent->d_lock);
memset(path, 0, 2048);
cp = dentry_path_stp(dent, path, 1024); //解析每个dentry的文件路径,参考char *dentry_path(struct dentry *dentry, char *buf, int buflen)的实现
if (!IS_ERR(cp)) {
if(strlen(cp))
//offset += snprintf(buf+offset, PAGE_SIZE-offset, "%s", cp);
;
else
cp = path+1024;
}
pp = path+1024;
pp += sprintf(path+1024, "%d ", dcache_referenced_nr);
if (offset + (pp-cp) + 3 >= PAGE_SIZE) {//\r\n space
fp->f_op->write(fp, buf, offset, &fp->f_pos); //将文件路径写log
offset = 0;
memset(buf,0,PAGE_SIZE);
}
offset += snprintf(buf+offset, PAGE_SIZE-offset, "%s %s\r\n", cp, path+1024);
}//end list_for
日志分析
查看某一台主机上的dentry条目如下,约3.3亿。
$cat /proc/sys/fs/dentry-state
338031179 338022259 45 0 0 0
systemtap脚本执行完成后,生成日志文件,经分析/etc/pki/nssdb/xxxx,占用量最大1点多亿条dentry.
$sudo grep "/etc/pki/nssdb" dcache.log |wc -l
131071404
$grep '/etc/pki/nssdb' dcache.log | more
/etc/pki/nssdb/._dOeSnotExist_-869749107.db 223
/etc/pki/nssdb/._dOeSnotExist_-869749108.db 224
/etc/pki/nssdb/._dOeSnotExist_-869749109.db 225
/etc/pki/nssdb/._dOeSnotExist_-869749110.db 226
/etc/pki/nssdb/._dOeSnotExist_-869749111.db 227
/etc/pki/nssdb/._dOeSnotExist_-869749112.db 228
/etc/pki/nssdb/._dOeSnotExist_-869749113.db 229
/etc/pki/nssdb/._dOeSnotExist_-869749114.db 230
/etc/pki/nssdb/._dOeSnotExist_-869749115.db 231
/etc/pki/nssdb/._dOeSnotExist_-869749116.db 232
/etc/pki/nssdb/._dOeSnotExist_-869749117.db 233
/etc/pki/nssdb/._dOeSnotExist_-869749118.db 234
/etc/pki/nssdb/._dOeSnotExist_-869749119.db 235
/etc/pki/nssdb/._dOeSnotExist_-869749120.db 236
/etc/pki/nssdb/._dOeSnotExist_-869749121.db 237
/etc/pki/nssdb/._dOeSnotExist_-869749122.db 238
/etc/pki/nssdb/._dOeSnotExist_-869749123.db 239
/etc/pki/nssdb/._dOeSnotExist_-869749124.db 240
/etc/pki/nssdb/._dOeSnotExist_-869749125.db 241
/etc/pki/nssdb/._dOeSnotExist_-869749126.db 242
/etc/pki/nssdb/._dOeSnotExist_-869749127.db 243
/etc/pki/nssdb/._dOeSnotExist_-869749128.db 244
/etc/pki/nssdb/._dOeSnotExist_-869749129.db 245
/etc/pki/nssdb/._dOeSnotExist_-869749130.db 246
……
从上边可能看出只有/etc/pki/nssdb/._dOeSnotExist_ 的使用不明确搜索一把,发现redhat 6系列的系统中存在的问题, bug分析详细参考:
Can curl HTTPS requests make fewer access system calls?
https://bugzilla.redhat.com/show_bug.cgi?id=1044666
因为tengine主机上调用了大量的curl https做探测(curl的版本7.19),使用如下命令做了一下分析可以明确发现一次curl有上百次的访问/etc/pki/nssdb/.xxx文件产生大量的dentry,
sudo strace -f -e trace=access curl 'https://www.taobao.com'
另外由于agent周期性的在拉取配置文件这些配置文件以当前时刻做文件名,也造成大量的dentry。两者加起来的数量基本符合/proc/sys/fs/dentry-state查出来的数量。
至此问题的两个主要原因已经比较清楚。
相关推荐
SystemTap是一种用于Linux内核调试和性能分析的工具,它允许用户编写脚本来检查运行中的内核。SystemTap脚本使用一种专门的脚本语言,提供了丰富的功能用于内核数据的采集和分析。本文档详细介绍了SystemTap脚本编写...
Language Reference.pdf // 详细说明systemtap脚本的语法规则 Tapset Refernce Manual.pdf // 脚本库,详细说明每个function的功能 tutorial.pdf // systemtap 脚本初级教材,介绍脚本的一些用途 Beginners_Guide....
总之,SystemTap是Linux环境下性能分析和故障排除的重要工具,通过简单的脚本即可实现对内核和系统调用的深入监控,极大地简化了内核调试和分析的过程。但是,它同样需要谨慎使用,避免由于不当脚本导致的系统问题。
在Linux服务器性能分析系统的设计中,SystemTap起到了关键作用。系统通过SystemTap动态跟踪各个进程/线程的状态,包括它们之间的通信状况以及对CPU、磁盘、网络接口卡等资源的占用情况。这种跟踪机制有助于重现...
SystemTap是一款强大的Linux调试工具,它允许用户编写脚本来收集和分析系统运行时的数据,而无需修改源代码或重新编译。在Android平台上使用SystemTap,可以深入理解系统的内部运作,帮助开发者解决性能问题,诊断...
SystemTap是一个强大的Linux内核调试工具,它允许开发者和管理员通过编写脚本来监控和分析Linux系统的行为。它是由Red Hat公司开发和支持的,被广泛用于Linux社区,用以简化内核和用户空间程序的调试过程。SystemTap...
systemTap是一款强大的Linux系统诊断工具,它允许用户以脚本方式收集、分析系统运行时的信息,主要用于解决性能问题和功能故障。这个压缩包文件“systemTap英文文档集合.7z”包含了多份关于systemTap的重要参考资料...
SystemTap是一款强大的性能分析和调试工具,它允许开发者和系统管理员通过编写简单的脚本来深入检查活动的Linux系统。SystemTap的工作原理是通过命名事件并在事件发生时给予它们处理器(handlers)。一旦定义的事件...
SystemTap是一个用于Linux系统的调试和性能监控工具,它允许用户无需修改内核代码或重启系统,就能对内核中的函数调用、变量等进行监控和分析。SystemTap的实现原理基于动态追踪技术,它能够插入预定义的探测点...
SystemTap是Linux下的一个诊断和性能分析工具,它允许用户无需修改内核代码或重新编译,就能收集运行中的内核和用户程序的性能数据,分析系统的运行情况。SystemTap支持多种分析技术,包括utrace、backtrace、dtrace...
SystemTap和Elfutils是Linux系统调试和性能分析的两个重要工具。SystemTap提供了一种高级的脚本语言,使得开发者可以方便地编写诊断和监控脚本,而无需深入理解底层的内核代码。Elfutils则是一组用于处理ELF...
SystemTap是Linux操作系统中的一款强大的动态诊断工具,它允许用户以脚本语言的方式对系统进行监控和调试。在CentOS 7.4.1708这个特定的环境中,SystemTap通过RPM(Red Hat Package Manager)包的形式提供,使得用户...
SystemTap是一个开源的动态跟踪工具,它允许开发者无需重新编译内核或重启系统,就能对Linux内核和运行中的应用程序进行深入分析。SystemTap的基本工作原理是允许用户编写脚本,这些脚本由SystemTap工具编译和运行,...
有用的systemtap脚本。 只是为了学习。 ubuntu的设置: 1.install systemtap $sudo apt-get install systemtap $sudo apt-get install systemtap-runtime 2.install kernel-debug-info use source-list: (1)...
这一特性使得SystemTap成为监控和调试复杂系统,尤其是像Nginx这样的高性能服务器的理想工具。 nginx-systemtap-toolkit正是利用了SystemTap的这一优势,为Nginx开发了一系列脚本,用于实时监控Nginx的运行状态,...