文章目录
1. 问题说明
在国庆的最后一天夜里,服务器突然报警,爆的是内存不够使用了,剩余不到5%。因为该服务器上暂时只运行了一个logstash节点,服务器内存是31g,logstash的jvm堆的大小设置的是24g。看到报警第一反应是,我靠,又发生堆外内存泄漏了?上了服务器,使用top一看,对应的logstash确实只使用24g,对应的其他进程的消耗都很小,加起来不过25g的样子,但是使用free -h
一看,却是已经使用了比较高的内存。显示只有1g的缓存了,对应top
的话有5g左右的差距,系统按说不应该占用这么多啊。没办法,先解决报警吧。就临时将logstash的jvm内存调整到22g,然后重启。后面再慢慢的排查这个问题。
下面的排查数据都是重启后的,但是依然可以说明问题
1.使用top,free查看相关信息
top -n1
...
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
24407 deploy 20 0 28.0g 19g 17m S 59.4 61.5 6873:35 java
14900 deploy 20 0 1389m 306m 8632 S 29.7 1.0 2905:33 node
6352 deploy 20 0 3324 1356 536 R 4.0 0.0 0:00.02 jq-linux64
1 root 20 0 19348 1192 880 S 0.0 0.0 0:39.53 init
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
3 root RT 0 0 0 0 S 0.0 0.0 6:24.71 migration/0
...
这里从RES可以看到用户进程最多消耗的内存是19g+306m 可以认为不到20g
我们再来看看free命令的情况
free -h
total used free shared buffers cached
Mem: 31G 29G 2.3G 204K 392M 4.5G
-/+ buffers/cache: 24G 7.2G
Swap: 0B 0B 0B
可以看到从用户角度看到的进程使用的总内存是24G,这里面有4G左右的偏差,理论上系统不可能占用这么多,而且也会再top中显示的啊。
2.系统内核
cat /etc/issue
CentOS release 6.8 (Final)
cat /proc/version
Linux version 2.6.32-642.6.2.el6.x86_64 (mockbuild@worker1.bsys.centos.org) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-17) (GCC) ) #1 SMP Wed Oct 26 06:52:09 UTC 2016
2. 折腾之路
这4g的内存到底去了哪里了呢,不知道的话心里总是很痒,难受。首先,这里的表现是top
和free
显示不一致,想要搞明白这俩命令的统计原理有点费劲,google一下,没有找到。后来同事帮忙用free可用内存偏少
关键字找到了这样一篇文章,这才解开了这个问题的面纱。
原来是free相对top没有专门统计Slab。这也是导致两者差别的主要原因。
这个时候想到可以看看内存的具体的数据对照一下
可以使用 cat /proc/meminfo
看到内存的更具体的使用情况
cat /proc/meminfo |sort -nr -k2
VmallocTotal: 34359738367 kB
VmallocChunk: 34359647340 kB
MemTotal: 32880228 kB
DirectMap1G: 31457280 kB
Committed_AS: 25446604 kB
Active: 22905908 kB
AnonPages: 20760828 kB
Active(anon): 20760796 kB
AnonHugePages: 20178944 kB
CommitLimit: 16440112 kB
Cached: 4765532 kB
# 这里可以看到这一项,确实是4g
Slab: 4262432 kB
SReclaimable: 4225944 kB
Inactive: 3022820 kB
Inactive(file): 3022640 kB
MemFree: 2416988 kB
Active(file): 2145112 kB
DirectMap2M: 2091008 kB
Buffers: 402364 kB
VmallocUsed: 68888 kB
Mapped: 50108 kB
PageTables: 48848 kB
SUnreclaim: 36488 kB
KernelStack: 6176 kB
DirectMap4k: 5992 kB
Hugepagesize: 2048 kB
Shmem: 204 kB
Inactive(anon): 180 kB
Dirty: 152 kB
WritebackTmp: 0 kB
Bounce: 0 kB
...后面还有一些都是0,忽略了
2.1 Slab简介
Slab是内核中使用的数据结构,为了适应更小的数据分配(比页小很多,页通常是4k)。
更加具体的可以参看这里
2.1.1 Slab有两个主要作用:
- Slab对小对象进行分配,不用为每个小对象分配一个页,节省了空间。
- 内核中一些小对象创建析构很频繁,Slab对这些小对象做缓存,可以重复利用一些相同的对象,减少内存分配次数。
2.1.2 Slab的信息记录
** 1.Slab的统计信息 **
统计信息记录在/proc/meminfo
中对应的项是
Slab,SReclaimable,SUnreclaim
其中Slab=SReclaimable+SUnreclaim,SReclaimable表示可回收使用的内存。
cat /proc/meminfo |egrep "Slab|SReclaimable|SUnreclaim"
Slab: 4262724 kB
SReclaimable: 4226028 kB
SUnreclaim: 36696 kB
** 2. Slab 详情 **
Slab详细包含的项存储在/proc/slabinfo
当中
cat /proc/slabinfo|sort -nr -k2
#名称 active对象 总对象 对象大小
# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
dentry 20060551 20061020 192 20 1 : tunables 120 60 8 : slabdata 1003051 1003051 0
buffer_head 1053268 1053390 104 37 1 : tunables 120 60 8 : slabdata 28470 28470 0
ext3_inode_cache 58426 58445 800 5 1 : tunables 54 27 8 : slabdata 11689 11689 0
size-64 48788 50209 64 59 1 : tunables 120 60 8 : slabdata 851 851 480
radix_tree_node 43129 43204 560 7 1 : tunables 54 27 8 : slabdata 6172 6172 0
size-32 19176 19488 32 112 1 : tunables 120 60 8 : slabdata 174 174 0
ext4_inode_cache 11222 20140 1000 4 1 : tunables 54 27 8 : slabdata 5035 5035 0
inotify_inodm.. 10037 10080 120 32 1 : tunables 120 60 8 : slabdata 315 315 0
sysfs_dir_cache 9280 9288 144 27 1 : tunables 120 60 8 : slabdata 344 344 0
selinux_inod.. 7610 7844 72 53 1 : tunables 120 60 8 : slabdata 148 148 0
vm_area_struct 7212 9044 200 19 1 : tunables 120 60 8 : slabdata 476 476 24
anon_vma_chain 6202 8701 48 77 1 : tunables 120 60 8 : slabdata 113 113 24
inode_cache 5952 5952 592 6 1 : tunables 54 27 8 : slabdata 992 992 0
proc_inode_cache 5839 6072 656 6 1 : tunables 54 27 8 : slabdata 1012 1012 0
anon_vma 4234 5762 56 67 1 : tunables 120 60 8 : slabdata 86 86 0
filp 2167 4110 256 15 1 : tunables 120 60 8 : slabdata 274 274 480
size-192 1985 2120 192 20 1 : tunables 120 60 8 : slabdata 106 106 0
size-128 1982 2220 128 30 1 : tunables 120 60 8 : slabdata 74 74 0
size-1024 1913 2136 1024 4 1 : tunables 54 27 8 : slabdata 534 534 118
这里主要介绍一下前几个列的含义,如上中文注释,这个文件显示了slab使用的详细分布。这里可以看到dentry 占用的是最大的,他占用的内存可以这样计算
20061020*192/1024=3851727kb 可以得到对应的kb size 。
这个文件还有一个更简单的命令可以看:slabtop
这里可以看到各个维度的总结性信息以及详情,而且自动排序了。同样也是dentry占用最多,但是对应的是cache-size
和上面计算出来的不一样,不清楚是不是因为slab是从页中分配出来的所以导致页有空闲导致的。
slabtop -o|head -20
Active / Total Objects (% used) : 21372898 / 21401792 (99.9%)
Active / Total Slabs (% used) : 1062385 / 1062554 (100.0%)
Active / Total Caches (% used) : 99 / 177 (55.9%)
Active / Total Size (% used) : 3982075.22K / 3995162.08K (99.7%)
Minimum / Average / Maximum Object : 0.02K / 0.19K / 4096.00K
OBJS ACTIVE USE OBJ-SIZE SLABS OBJ/SLAB CACHE-SIZE NAME
20061120 20060914 99% 0.19K 1003056 20 4012224K dentry
1054685 1054592 99% 0.10K 28505 37 114020K buffer_head
58550 58528 99% 0.78K 11710 5 46840K ext3_inode_cache
51271 48907 95% 0.06K 869 59 3476K size-64
43218 43152 99% 0.55K 6174 7 24696K radix_tree_node
20140 11226 55% 0.98K 5035 4 20140K ext4_inode_cache
19488 19057 97% 0.03K 174 112 696K size-32
10080 10037 99% 0.12K 315 32 1260K inotify_inode_mark_entry
9633 7502 77% 0.20K 507 19 2028K vm_area_struct
9288 9280 99% 0.14K 344 27 1376K sysfs_dir_cache
8701 6437 73% 0.05K 113 77 452K anon_vma_chain
7844 7610 97% 0.07K 148 53 592K selinux_inode_security
6114 5955 97% 0.64K 1019 6 4076K proc_inode_cache
可以看到,这里的dentry 是最多的,那么dentry又是什么东西呢?
2.2 dentry 简介
dentry (directory entry),目录项缓存。也就是内核中用来作为目录的索引,和inode 共同标识了文件系统,inode 存储的是文件的元信息,dentry存储的是文件名加目录的信息,为了快速定位文件。
所以在文件特别多的情况下有可能会导致dentry量比较大。具体介绍参看这里
在文件比较多或者频繁删除创建文件的时候可能会导致dentry比较多。这个是最直接的原因。如何查看系统的文件,inode数量。
df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/vda1 3276800 714264 2562536 22% /
/dev/vdb 5242880 90647 5152233 2% /home
inodes的数量就代表了dentry的最大数量,可以看到3276800和dentry的数量完全不在一个数量级,所以肯定不是因为系统中的文件太多导致。
但是具体是哪些进程使用了dentry有些难以判断,系统没有直接的信息进行记录。这个时候需要使用大杀器 SystemTap
了。
2.2.1 dentry清空方案
系统默认内存回收配置在/proc/sys/vm/drop_caches中
0:不做任何处理,由系统自己管理
1:清空pagecache
2:清空dentries和inodes
3:清空pagecache、dentries和inodes
所以如果想清空dentry,只需要
echo "2" > /proc/sys/vm/drop_caches
等待slab有效下降以后,再恢复
echo "0" > /proc/sys/vm/drop_caches
2.3 SystemTap简介
SystemTap是一个Linux非常有用的调试(跟踪/探测)工具,常用于Linux
内核或者应用程序的信息采集,比如:获取一个函数里面运行时的变
量、调用堆栈,甚至可以直接修改变量的值,对诊断性能或功能问题非
常有帮助。SystemTap提供非常简单的命令行接口和很简洁的脚本语
言,以及非常丰富的tapset和例子。 类似于java的btrace一样,可以用来调试c的调用等。
这个玩意儿太强大了,只是我用的还不是很熟悉,后面有机会了需要继续学习。简单介绍一下安装吧。
2.3.1 SystemTap 安装
安装步骤不算太难,但是网上说的乱七八糟的,很坑,总结一下我的吧。
1. 安装依赖包
SystemTap有一些依赖包,所以要先装这些依赖包。
依赖包有以下3个
- kernel-debuginfo
- kernel-debuginfo-common
- kernel-devel
这三个包都是和操作系统的内核版本相关的,所以要先查看内核版本
uname -a
Linux 2.6.32-642.6.2.el6.x86_64 #1 SMP Wed Oct 26 06:52:09 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
所以对应的三个包分别是
kernel-debuginfo-2.6.32-642.6.2.el6.x86_64.rpm
kernel-debuginfo-common-x86_64-2.6.32-642.6.2.el6.x86_64.rpm
kernel-devel-2.6.32-642.6.2.el6.x86_64.rpm
建议直接google,然后找到对应的ftp服务器wget下载,我这边也示例以下吧
wget http://ftp.riken.jp/Linux/scientific/6.2/archive/debuginfo/kernel-debuginfo-2.6.32-642.6.2.el6.x86_64.rpm
wget http://ftp.riken.jp/Linux/scientific/6.2/archive/debuginfo/kernel-debuginfo-2.6.32-642.6.2.el6.x86_64.rpm
wget http://ftp.riken.jp/Linux/scientific/6.2/archive/debuginfo/kernel-debuginfo-common-x86_64-2.6.32-642.6.2.el6.x86_64.rpm
然后安装这三个包
rmp -ivh *.rpm
2. yum 安装SystemTap
接下来就简单了
为了部署 SystemTap,需要安装以下两个 RPM 包:
- systemtap
- systemtap-runtime
echo "y" | yum install systemtap systemtap-runtime
2.4. 使用systemTap来监控对dentry的使用
2.4.1 从用户进程调用上来统计
这两个函数对应的是对dentry的申请和释放,所以通过对这两个函数的调用可以看到对应的对dentry的使用情况。
cat name_record.stp
probe kernel.function("d_alloc")
{
printf("%s[%ld] %s %s\n", execname(), pid(), pp(), probefunc())
}
probe kernel.function("d_free")
{
printf("%s[%ld] %s %s\n", execname(), pid(), pp(), probefunc())
}
probe timer.s(600)
{
exit()
}
使用命令 stap name_record.stpn > name.log
即可获取相关的信息,name.log中的内容是下面这个样子的。
vim name.log
YDService[26276] kernel.function("d_alloc@fs/dcache.c:968") d_alloc
YDService[26276] kernel.function("d_free@fs/dcache.c:89") d_free
...
05.nodes_only_b[10880] kernel.function("d_free@fs/dcache.c:89") d_free
05.nodes_only_b[10531] kernel.function("d_free@fs/dcache.c:89") d_free
05.nodes_only_b[10531] kernel.function("d_alloc@fs/dcache.c:968") d_alloc
...
curl[10650] kernel.function("d_alloc@fs/dcache.c:968") d_alloc
curl[10650] kernel.function("d_free@fs/dcache.c:89") d_free
curl[10650] kernel.function("d_alloc@fs/dcache.c:968") d_alloc
curl[10650] kernel.function("d_free@fs/dcache.c:89") d_free
可以看到是哪个进程调用了这两个函数。这两个函数是进程可以主动进行调用的。
统计一下对应的进程调用
# 总量26w
wc -l name.log
269715 name.log
# 按照进程排序
awk '{print $1}' name.log|sort |uniq -c|sort -n -k1 |tail -n30
1563 05.nodes_only_b[1698]
1563 05.nodes_only_b[19280]
1563 05.nodes_only_b[4655]
1563 05.nodes_only_b[7605]
1564 05.nodes_only_b[16327]
1564 05.nodes_only_b[25307]
1644 kk-superman-age[23735]
2166 sadc[13116]
2299 sadc[16307]
2299 sadc[22276]
2299 sadc[25301]
2299 sadc[4659]
2300 sadc[1697]
2300 sadc[19281]
2300 sadc[28249]
2300 sadc[31200]
2300 sadc[7594]
2320 barad_agent[3897]
4250 falcon-agent[21818]
5574 curl[27094]
6503 curl[15143]
6759 curl[30036]
6796 curl[516]
6860 curl[9376]
6956 curl[6437]
7024 curl[21094]
7055 curl[24071]
7063 curl[18113]
7148 curl[3494]
72149 YDService[26276]
可以看到如果按照进程来算的话是YDService 是最多的。先验证一下这个服务。
$ cat name.log |grep "YD"|grep 'd_free'|wc -l
36467
$ cat name.log |grep "YD"|grep 'd_alloc'|wc -l
36572
可以看到这个服务free和alloc的量基本上是一致的,所以没有啥问题。
然后我们再来校验一下curl
(因为之前看文档说curl在请求https的时候某写版本是有问题的,所以将所有的curl请求当做一个进程来处理)
$ cat name.log |grep "curl"|grep 'd_alloc'|wc -l
68294
$ cat name.log |grep "curl"|grep 'd_free'|wc -l
738
这一个看,差的好大,估计就是这个了,计算一下按照这个量每分钟产生的大小。
(68294-738)*192/1024/10=1266kb
然后写了一个脚本来记录每分钟的slab,dentry的变换量
#/bin/bash
log_file="$(cd $(dirname $0);pwd)/log_slab.log"
if [ ! -e $log_file ] ;
then
echo "time slab-kb dentry-kb diff dentry_add" > $log_file
echo "2019.10.09-21:01:19 2929348 2685424 243924" >> $log_file
fi
dentry_size=$( /usr/bin/slabtop -o|grep dentry |awk '{print $7}'|sed -e "s/K//g")
slab_size=$( cat /proc/meminfo | grep Slab|awk '{print $2}')
cur_time=$(date +'%Y.%m.%d-%H:%M:%S')
diff_s_d=$(echo "${slab_size}-${dentry_size}"|bc)
lastest_dentry=$(tail -n1 ${log_file}|awk '{print $3}')
diff_dentry=$(echo "${dentry_size} - ${lastest_dentry}"|bc)
res="${cur_time} ${slab_size} ${dentry_size} ${diff_s_d} ${diff_dentry}"
echo "$res" >> ${log_file}
然后加到定时任务当中
crontab -e
* * * * * bash /home/xx/dentry_record_/record.sh
后面可以看到每分钟的增量大概是
[deploy@bj3-search-log-logstash01 dentry_record_]$ head -30 log_slab.log
time slab-kb dentry-kb diff dentry_add
2019.10.09-21:16:01 2950764 2707576 243188 0
2019.10.09-21:17:01 2951940 2708652 243288 1076
2019.10.09-21:18:01 2953528 2710272 243256 1620
2019.10.09-21:19:01 2955564 2711804 243760 1532
2019.10.09-21:20:01 2956880 2713420 243460 1616
2019.10.09-21:21:01 2958904 2715032 243872 1612
可以看到的是和上面计算的1266kb也是比较接近的。
这个时候发现我的定时任务中有一个监控脚本,里面是对es集群的监控(每分钟运行一次),curl
请求获取es信息使用的是http方式,之前做过一些测试http是不会导致dentry上升的。里面用到https的地方就是如果集群由问题会使用钉钉进行报警,请求钉钉的时候使用的是https的方式。所以一开始没有怀疑这个脚本,这个时候尝试把对应的定时任务关了,结果上面那个脚本显示的结果真的不增加了,看来真的是这个脚本的锅…
这个时候感觉好奇怪,钉钉上也灭有啥信息啊,不可能每分钟都发信息啊。手动运行了一下脚本,发现发送钉钉之后返回的错误码显示是消息格式有问题,所以不会显示,又因为没有发送成功就会每隔一分钟发送一次。。。,因为是一个过时的监控,所以一直没有注意过,结果埋了一个坑。。
到此,谜底才真正解开,舒服多了,总结一下就是自己写的一个监控脚本有bug,正好触发了curl请求的一个底层bug,导致内核取dentry的分配消耗很大,
2.4.2 curl请求bug的发现
上面的排查过程说明了curl请求的锅,这里聊一下自己验证curl请求的锅的时候使用的脚本。
** 1. 大量发送curl请求的脚本 **
有些时候请求量小的话不太容易看出来
/bin/egrep 'Slab|claim' /proc/meminfo ; /usr/bin/slabtop -o | /bin/egrep 'Slab|SLAB|dent' ; /bin/sh -c 'for i in `seq 300`; do echo -e ".\c" ; /usr/bin/curl --silent https://www.baidu.com > /dev/null ;done ';echo -e "\n" ; /usr/bin/slabtop -o | /bin/egrep 'Slab|SLAB|dent' ; /bin/egrep 'Slab|claim' /proc/meminfo
Slab: 2327552 kB
SReclaimable: 2274480 kB
SUnreclaim: 53072 kB
Active / Total Slabs (% used) : 577915 / 578012 (100.0%)
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
7297080 7280735 99% 0.19K 364854 20 1459416K dentry
............................................................................................................................................................................................................................................................................................................
Active / Total Slabs (% used) : 581810 / 581956 (100.0%)
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
7365320 7365320 100% 0.19K 368266 20 1473064K dentry
Slab: 2344412 kB
SReclaimable: 2288276 kB
SUnreclaim: 56136 kB
测试中发现这个不一定每次都会大量增加,可能因为某些时间点的回收导致的,但是如果是量足够大的话,比如上万次,肯定会增加的比较大。
同时,我们还可以辅助用一个脚本来判断。
** 2. 跟踪dentry分配的细节 **
为了确认有dentry分配,当然,我们可以使用上面的那个跟踪d_alloc的脚本实现,还有一种是可以跟踪dentry具体对应的目录,当然,还是使用强大的systemTap
cat detail_dentry.stp
probe kernel.function("dentry_lru_add")
{
printf("%s - %s - tid: %d, pid: %ld , ppid: %d, path: /%s\n",
tz_ctime(gettimeofday_s()), execname(),tid(),pid(), ppid(),
reverse_path_walk($dentry))
}
使用 stap detail_dentry.stp > d05.log &
来进行记录
然后查看对应文件的记录数据。
head d05.log
Fri Oct 11 12:15:02 2019 CST - curl - tid: 30581, pid: 30581 , ppid: 30217, path: /etc/pki/nssdb/.3851895983_dOeSnotExist_.db
Fri Oct 11 12:15:02 2019 CST - curl - tid: 30581, pid: 30581 , ppid: 30217, path: /etc/pki/nssdb/.3851895984_dOeSnotExist_.db
Fri Oct 11 12:15:02 2019 CST - curl - tid: 30581, pid: 30581 , ppid: 30217, path: /etc/pki/nssdb/.3851895985_dOeSnotExist_.db
Fri Oct 11 12:15:02 2019 CST - curl - tid: 30581, pid: 30581 , ppid: 30217, path: /etc/pki/nssdb/.3851895986_dOeSnotExist_.db
Fri Oct 11 12:15:02 2019 CST - curl - tid: 30581, pid: 30581 , ppid: 30217, path: /etc/pki/nssdb/.3851895987_dOeSnotExist_.db
Fri Oct 11 12:15:02 2019 CST - curl - tid: 30581, pid: 30581 , ppid: 30217, path: /etc/pki/nssdb/.3851895988_dOeSnotExist_.db
Fri Oct 11 12:15:02 2019 CST - curl - tid: 30581, pid: 30581 , ppid: 30217, path: /etc/pki/nssdb/.3851895989_dOeSnotExist_.db
Fri Oct 11 12:15:02 2019 CST - curl - tid: 30581, pid: 30581 , ppid: 30217, path: /etc/pki/nssdb/.3851895990_dOeSnotExist_.db
Fri Oct 11 12:15:02 2019 CST - curl - tid: 30581, pid: 30581 , ppid: 30217, path: /etc/pki/nssdb/.3851895991_dOeSnotExist_.db
Fri Oct 11 12:15:02 2019 CST - curl - tid: 30581, pid: 30581 , ppid: 30217, path: /etc/pki/nssdb/.3851895992_dOeSnotExist_.db
根据对应的 ** /etc/pki/nssdb/.3851895989_dOeSnotExist_.db** 关键字也能够google出对应的bug来。
这个bug对应的记录在这里
从这里综合的信息来看,这个bug描述来看,好像是nss的一个bug,出现在3.14.3-4.el6_4.x86_64,如果想要彻底修复,需要经NSS 升级到3.16.1-4
但是实际上在低一些的版本也提供了修复方案,只有是版本大于等于nss-softokn-3.14.3-12.el6 即可通过设置一个变量 export NSS_SDB_USE_CACHE=yes
来解决
查看本机的版本
curl --version
curl 7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
yum list nss-softokn
...
Installed Packages
nss-softokn.x86_64 3.14.3-23.el6_7 @anaconda-CentOS-201605220104.x86_64/6.8
...
可以看到本机是nss-softokn 版本是3.14.3-23.el6_7 属于bug修复的版本,但不是终极修复版本。
通过在监控脚本的开头添加
export NSS_SDB_USE_CACHE=yes
最终解决问题。
3 . 数据样例附
cat log_slab.log
time slab-kb dentry-kb diff
2019.10.09-21:01:19 2929348 2685424 243924
2019.10.09-21:01:28 2929204 2685424 243780
2019.10.09-21:01:30 2928804 2685424 243380
2019.10.09-21:01:31 2928736 2685424 243312
2019.10.09-21:06:01 2935132 2691656 243476
#log_file="/home/deploy/search/test_data/systemtap_dependency/dentry_record_/log_slab.log"
log_file="$(cd $(dirname $0);pwd)/log_slab.log"
echo "$log_file"
if [ ! -e $log_file ] ;
then
echo "not exist"
echo "2019.10.09-21:01:19 2929348 2685424 243924" > $log_file
fi
dentry_size=$( /usr/bin/slabtop -o|grep dentry |awk '{print $7}'|sed -e "s/K//g")
slab_size=$( cat /proc/meminfo | grep Slab|awk '{print $2}')
cur_time=$(date +'%Y.%m.%d-%H:%M:%S')
diff_s_d=$(echo "${slab_size}-${dentry_size}"|bc)
lastest_dentry=$(tail -n1 ${log_file}|awk '{print $3}')
diff_dentry=$(echo "${dentry_size} - ${lastest_dentry}"|bc)
res="${cur_time} ${slab_size} ${dentry_size} ${diff_s_d} ${diff_dentry}"
#echo "$res" >> /home/deploy/search/test_data/systemtap_dependency/dentry_record_/log_slab.log
echo "$res" >> ${log_file}
参考
感谢大家分享,让我得以查到这个问题
https://blog.csdn.net/mans1516/article/details/51434408
https://zhuanlan.zhihu.com/p/43133085
https://blog.arstercz.com/centos-%E7%B3%BB%E7%BB%9F-slab-dentry-%E8%BF%87%E9%AB%98%E5%BC%95%E8%B5%B7%E7%B3%BB%E7%BB%9F%E5%8D%A1%E9%A1%BF%E5%88%86%E6%9E%90%E5%A4%84%E7%90%86/