2014-12-11 wcdj
后台程序使用SystemV消息队列遇到的资源泄漏问题
目录
0 问题背景
后台某程序在使用SystemV消息队列进行IPC通信,一段时间后发现部署此程序机器的消息队列资源被耗尽了(可以查看/proc/sys/kernel/msgmni),从而导致进程创建新的消息队列返回ENOSPC错误。
注释
ENOSPC A message queue has to be created but the system limit for the maximum number of message queues (MSGMNI) would be exceeded.
1 原因分析
通过ipcs –q命令可以看到本机存在很多键值为0x00000000的消息队列。受到之前共享内存nattch(the number of currently attached processes)思维的影响,以为此问题是消息队列创建完成后被ipcrm删除,且当前使用消息队列的进程没有退出导致的(实际上,消息队列被ipcrm后会立刻删除,进程在下次使用时就会报错)。后来把所有进程都干掉了,发现问题依旧。
再查看下man msgget的解释,找到了问题原因。
A message queue identifier, associatedmessage queue, and data structure (see <sys/msg.h>), shall be created forthe argument key if one of the following is true:
* The argument key is equal to IPC_PRIVATE.
* The argument key does not already have a message queue identifier associatedwith it, and (msgflg & IPC_CREAT) is non-zero.
问题程序会从XML配置文件中读取两个key1和key2值并分别创建消息队列,但是配置文件中少指定了一个key2从而导致程序在调用msgget创建消息队列的key为0,即man中所说的IPC_PRIVATE。而程序本意是使用一个显式固定的key进行IPC通信的,且此消息队列创建后程序不会主动将其删除,从而导致了前文所描述的问题。对于IPC_PRIVATE而言,通常的用法是在两个相关的父子进程间通信使用的,并且在使用后会通过msgid调用msgctl将消息队列从系统中删除。
find /usr/include -name "*.h" |xargs grep "IPC_PRIVATE"
./usr/include/bits/ipc.h:#defineIPC_PRIVATE ((__key_t) 0) /* Private key. */
./usr/include/linux/ipc.h:#defineIPC_PRIVATE ((__kernel_key_t) 0)
2解决方法
(1) 在配置文件里将缺失的key分配一个非零且合法的键值;
(2) 将程序服务停止;
(3) 清理泄漏不用的0x00000000 key;
ipcs -q | grep program | grep "0x00000000" | awk '{print $2}' | while read f;do ipcrm -q $f;done
(4) 将程序服务拉起;