[尽管我使用 perl 工作,但我认为这个问题与 Linux System V IPC API 和限制有关,而与 perl 特有的任何内容无关。]
我有两台 Centos 机器,每台都运行 CentOS Linux 版本 7.9.2009(核心)。
我有一个程序,它分叉一个子程序,然后使用 System V IPC 消息与子程序通信,子程序准备答案并将其发送给父程序。
在一台机器上,我们看到了预期的行为。子进程生成一批消息,父进程消费这些消息。有时子进程比父进程运行得快一点,因此可能会填满队列,然后子进程等待,直到父进程消费一些消息并继续。
我们可以使用 ipcs -q 检查队列大小,发现偶尔会达到每个队列 10 条消息的默认限制,子进程会暂停,然后我们会看到队列如预期般为空。
我们认为队列限制在文件中指定/proc/sys/fs/mqueue/例如最大消息数被视为预期的 10。这两台机器上的这些值是相同的。
我们还可以使用以下方法查看与队列相关的用户 ulimitulimit -q并且在两台机器上都看到超过 800,000 字节的值。
令人困惑的是,在第二台机器上,我们看到子进程向队列写入三条消息,并尝试写入第四条消息,然后等待 - 我们故意不设置超时。就好像写入器认为队列已满,即使 ipcs -q 显示队列中只有 3 个项目。此时父进程尚未尝试读取消息。
------ Message Queues --------
key msqid owner perms used-bytes messages
0x0000002a 1474560 dave 600 15020 3
问题是:除了队列已满之外,还有什么原因会导致 msgsnd() 暂停?暂停似乎会无限期地持续下去,当父进程变得活跃并读取一些消息时,子进程会继续执行。
我们有许多机器运行此代码,没有问题。但在三台新机器上失败了。可能存在一些与我们的代码交互的特定于环境的功能?
perl 代码使用系统调用之上的薄库(细节省略)
$mQueue = msgget(IPC_PRIVATE, IPC_CREAT | S_IRUSR | S_IWUSR);
msgsnd( $mQueue, pack("l! a*", length($msg), $msg);
答案1
问题是默认队列最大大小内核设置被设为一个低值。
可以使用 ipcs 的 -l 选项来查看它。
ipcs -q -l
------ Messages Limits --------
max queues system wide = 3671
max size of message (bytes) = 8192
default max size of queue (bytes) = 16384
有问题的内核设置存储在
/proc/sys/kernel/msgmnb
并可以使用命令进行更改(以 root 身份)
sysctl -w kernel.msgmnb=65536
kernel.msgmnb = 65536