是否可以在具有大量元素的 linux 中打开消息队列?

Posted

技术标签:

【中文标题】是否可以在具有大量元素的 linux 中打开消息队列?【英文标题】:Is it possible to open message queue in linux with huge number of elements? 【发布时间】:2015-12-21 19:15:42 【问题描述】:

根据documentation,可以使用/proc/sys/fs/mqueue/msg_max 来增加队列中消息的限制。文档还说,限制不应超过 HARD_MSGMAX,即自 Linux 3.5 以来的 65,536

但是,即使有 500 个元素,尝试打开队列也会失败,EMFILE

#include <stdio.h>
#include <mqueue.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <sys/stat.h>

int main(int argc, char** argv)

    int message_size = argc > 1 ? atoi(argv[1]) : 16;
    int queue_size = argc > 2 ? atoi(argv[2]) : 10000;

    printf("Trying to open queue with msgsize: %d, and maxmsg: %d\n", message_size, queue_size);

    struct mq_attr initial_attributes = (struct mq_attr)
            .mq_msgsize = message_size,
            .mq_maxmsg = queue_size
    ; 

    int open_flags = O_RDWR | O_CREAT | O_EXCL;
    int permissions = S_IWUSR | S_IRUSR;

    const char* name = "/message_queue_name;";
    mqd_t queue = mq_open(name, open_flags, permissions, &initial_attributes);

    if(queue == -1)
    
        printf("Cannot open message queue\n");
        printf("Errno: %d [%s]\n", errno, strerror(errno));
        return 1;
    
    else
    
        printf("Queue has been opened successfully. Closing...\n");
        mq_close(queue);
        mq_unlink(name);
    

    return 0;

测试:

$ cat /proc/sys/fs/mqueue/msg_max
65536

$ ./main 16 300
Trying to open queue with msgsize: 16, and maxmsg: 300
Queue has been opened successfully. Closing...

$ ./main 16 500
Trying to open queue with msgsize: 16, and maxmsg: 500
Cannot open message queue
Errno: 24 [Too many open files]

根据documentation,EMFILE错误码的意思是,该进程已经打开了最大数量的文件和消息队列,虽然这个程序没有打开任何其他文件。

那么,我的问题是:如何打开包含大量元素的消息队列?


UPD [1]

这是我的系统限制:

$ ulimit -a
-t: cpu time (seconds)              unlimited
-f: file size (blocks)              unlimited
-d: data seg size (kbytes)          unlimited
-s: stack size (kbytes)             8192
-c: core file size (blocks)         0
-m: resident set size (kbytes)      unlimited
-u: processes                       62820
-n: file descriptors                1024
-l: locked-in-memory size (kbytes)  unlimited
-v: address space (kbytes)          unlimited
-x: file locks                      unlimited
-i: pending signals                 62820
-q: bytes in POSIX msg queues       819200
-e: max nice                        30
-r: max rt priority                 99
-N 15:                              unlimited

【问题讨论】:

投反对票有什么理由吗? 其他限制?例如检查ulimit -a @KarolyHorvath,嗯。 ulimit -q(即“POSIX 消息队列中的字节数”)是819200,因此,我应该能够在队列中存储大约 50k 16 字节消息。我没有看到任何其他限制 - 它们要么是 unlimited 要么足够大。 顺便说一句,来自main()return -1 是一个错误。 @g-v,已修复,再次感谢您 【参考方案1】:

您的文件描述符似乎用完了。只需检查每个进程的文件描述符的最大数量(ulimit),如果它很低,那么您可以通过使用来增加它以满足您的需求

ulimit -n new_maximim_number

【讨论】:

不幸的是,它不起作用。我每个进程都有1024 文件描述符,甚至将其增加到4096 也不能解决问题。我将在一秒钟内将ulimit -a 输出添加到问题中。不过还是谢谢你的回答 您是否检查过您的程序运行时实际打开了多少文件描述符? ...例如,当您使用 300 启动它时。这只是为了检查每个消息队列是否打开 1 个文件描述符或更多。 另一个限制可能是内存: 刚刚检查过 - 每个消息队列只打开一个文件描述符。 你的意思是,有多少内存可用?我有大约 4GB 的可用内存,所以应该没问题。【参考方案2】:

你遇到了RLIMIT_MSGQUEUE的限制,见mq_overview(7)

资源限制

RLIMIT_MSGQUEUE 资源限制,对 所有消息队列可以使用的空间量 属于一个进程的真实用户ID,在getrlimit(2)中描述。

在调用mq_open()之前增加它,例如像这样:

...
#include <sys/resource.h>

int main(int argc, char** argv)

    struct rlimit rlim;
    rlim.rlim_cur = RLIM_INFINITY;
    rlim.rlim_max = RLIM_INFINITY;

    if (setrlimit(RLIMIT_MSGQUEUE, &rlim) == -1) 
        perror("setrlimit");
        return 1;
    

    ...

你需要 root 权限(或者CAP_SYS_RESOURCE 能力,我猜)。


对于这种情况,Linux 内核确实返回EMFILE,请检查here:

if (u->mq_bytes + mq_bytes < u->mq_bytes ||
    u->mq_bytes + mq_bytes > rlimit(RLIMIT_MSGQUEUE)) 
        spin_unlock(&mq_lock);
        /* mqueue_evict_inode() releases info->messages */
        ret = -EMFILE;
        goto out_inode;

EMFILE 这里的原因可能是它与 POSIX 中的specified 最接近的错误代码; EMFILE 是唯一反映达到每进程限制的错误代码。

POSIX 没有为 RLIMIT_MSGQUEUE 指定更精确的错误代码,因为它是特定于 Linux 的。

【讨论】:

太棒了!似乎这完全解决了我的问题。非常感谢!

以上是关于是否可以在具有大量元素的 linux 中打开消息队列?的主要内容,如果未能解决你的问题,请参考以下文章

是否可以在linux中分配大量虚拟内存?

ActiveMQ:一条待处理消息但队列为空

判断一个元素是不是在队列里

Java中队列

在 Linux 中控制信号量队列中的出队顺序

单调队列单调栈优先队列模板