背景
随着我们中心服务部署的越来越多,一台B6服务器上面的Java应用也越来越多, 内存也所剩无几,但是物理内存还可以使用20个gb的时候 ,突然收到了内存报警邮件,也不得不让我们重视。
现象:
- 应用内存使用量是40gb。但是实际可用量仅剩下5gb 如图:
这时第一的反应就是有应用程序溢出了,但是使用ps命令相加后。发现各个应用的内存是出奇的稳定 。 查看内存的相关使用数据后,发现
$ cat /proc/meminfo
Slab: 21286092 kB
SReclaimable: 87980 kB
SUnreclaim: 66232 kB
这个时候发现 ,slab的内存已经将近使用掉了20个gb的内存了,这是啥概念,基本可以顶一个头像服务了(头像服务也需要16gb的内存),在这种使用率的情况下,具体再看了一下redhat对这一块内存使用的简介:
Slab Allocation是Linux 2.2之后引入的一个内存管理机制,专门用于缓存内核的数据对象,可以理解为一个内核专用的对象池,可以提高系统性能并减少内存碎片。(Linux 2.6.23之后,SLUB成为了默认的allocator。)
其实发现 ,这一块内存是用于非常 小的一些文件做缓存使用的, 查看当前的服务器的slab的使用情况下来看是:
image.png
发现有可能是打开的文件太多, 在三点的时候 ,反而是我们业务的低峰,到底是啥东西占着呢?
继续看监控会发现 ,其实三点的时候 。 会有不少的请求打过来,会重新连接ssl, 这个时候 发现 ,可能是ssl连接的时候 ,使用了这么多内存?
带着比较疑惑的感情,在redhat的bug上面找了一下,好像aliyun和huawei的工程师也都发现了这个毛病,具体的bug如下:
是由于nss 组件 ,在centos 6的这个版本下,会有问题,具体的代码如下:
env = PR_GetEnv("NSS_SDB_USE_CACHE");
if (env && PORT_Strcasecmp(env,"no") == 0) {
enableCache = PR_FALSE;
} else if (env && PORT_Strcasecmp(env,"yes") == 0) {
enableCache = PR_TRUE;
} else {
char *tempDir = NULL;
PRUint32 tempOps = 0;
/*
* Use PR_Access to determine how expensive it
* is to check for the existance of a local file compared to the same
* check in the temp directory. If the temp directory is faster, cache
* the database there. */
tempDir = sdb_getTempDir(sqlDB);
if (tempDir) {
tempOps = sdb_measureAccess(tempDir);
PORT_Free(tempDir);
/* There is a cost to continually copying the database.
* Account for that cost with the arbitrary factor of 10 */
enableCache = (PRBool)(tempOps > accessOps * 10);
}
}
主要的情况还是这个地方 ,在证书sll验证的时候 ,若是证书链的话。会为每一个session会话存储一个cache的,这里若是没有配置环境变量的话。就会走到这里( 老的版本,新的版本增加了下层的校验,不作path空校验), 证书链上面的每一个key都会缓存
tempOps = sdb_measureAccess(tempDir);
所以上图中有那么多entry 就是由于 这里导致的
解决办法 :
1、在cenots 6的版本中升级nss *的所有的组件,需要在环境变量中,增加NSS_SDB_USE_CACHE =yes( 强制清除slab风险很高,请不要操作,容易炸 ,请不要操作)
2、 升级centos 7
最终的内存线图(右边的上升是正常的上升,服务发布了)
image.png
网友评论