在 Linux 中消息队列是否已经过时?

我最近一直在使用 Linux 中的消息队列(System v,但是 POSIX 也应该可以) ,它们似乎非常适合我的应用程序,但是在阅读了 Unix编程艺术之后,我不确定它们是否真的是一个好的选择。

Http://www.faqs.org/docs/artu/ch07s02.html#id2922148

System V IPC 的上层消息传递层在很大程度上已经不再使用了。下层由共享内存和信号量组成,在需要执行互斥锁和在同一台机器上运行的进程之间进行一些全局数据共享的情况下,仍然有重要的应用程序。这些 System V 共享内存设施演变为 POSIX 共享内存 API,在 Linux、 BSD、 MacOS X 和 Windows 下受到支持,但不是经典的 MacOS。

Http://www.faqs.org/docs/artu/ch07s03.html#id2923376

System V IPC 工具存在于 Linux 和其他现代 Unix 中。然而,由于它们是遗留的特性,因此并不经常使用。到2003年中期为止,Linux 版本仍然存在 bug。似乎没人愿意修理它们。

在最近的 Linux 版本中,System V 消息队列是否仍然存在 bug?我不确定作者是否意味着 POSIX 消息队列应该没问题?

似乎套接字是几乎任何事情(?)的首选 IPC,但是我看不出用套接字或其他东西实现消息队列如何非常简单。还是我想得太复杂了?

我不知道这是否与我正在使用嵌入式 Linux 有关?

40882 次浏览

我实际上并没有使用 POSIX 消息队列,因为我总是希望保留通过网络分发消息的选项。考虑到这一点,您可以查看更健壮的消息传递接口,如 Zeromq或实现 AMQP的接口。

关于0mq 的一个好处是,当在一个多线程应用程序中从相同的进程空间使用时,它使用了一种无锁的零拷贝机制,这种机制非常快。不过,您也可以使用相同的接口通过网络传递消息。

就我个人而言,我非常喜欢消息队列,并认为它们可以说是 Unix 世界中使用最少的 IPC。他们是快速和容易使用。

一些想法:

  • 有些只是时尚。旧的东西又变成新的了。在消息队列中添加一个闪亮的“爸爸”,它们可能会成为明年最新、最热门的事情。看看谷歌的 Chrome,它的标签页使用的是单独的进程而不是线程。突然之间,人们很兴奋,因为一个标签锁定不会导致整个浏览器崩溃。

  • 共享记忆有点像希曼的光环。如果您没有从机器中挤出最后一个周期,那么您就不是一个“真正的”程序员,而且 MQ 的效率稍微低一些。对于许多(如果不是大多数)应用程序来说,这完全是无稽之谈,但有时候一旦它占据了主导地位,就很难打破心态。

  • MQ 确实不适合具有无限数据的应用程序。像管道或套接字这样的面向流的机制更容易使用。

  • 系统 V 的变种确实已经失宠了。作为一般规则,如果可以的话,请使用 POSIX 版本的 IPC。

是的,我认为消息队列适用于某些应用程序。POSIX 消息队列提供了一个更好的接口,特别是,您可以提供队列名称而不是 ID,这对于故障诊断非常有用(使得更容易看出哪个是哪个)。

Linux 允许您将 posix 消息队列挂载为一个文件系统,并使用“ ls”查看它们,使用“ rm”删除它们,这也很方便(System V 依赖于笨重的“ ipcs”和“ ipcrm”命令)

POSIX 消息队列的最大缺点:

  • POSIX 消息队列不使其成为与 select()兼容的 规定。(它可以在 Linux 中使用 select(),但不能在 Qnx 系统中使用)
  • 有很多惊喜。

UnixDatagram 套接字执行与 POSIX 消息队列相同的任务。并且 Unix 数据报套接字工作在套接字层。它可以与 select()/poll()或其他 IO-wait 方法一起使用。在设计基于事件的系统时,使用 select()/poll()具有一定的优势。这样可以避免繁忙循环。

消息队列中存在意外。想想 mq_notify()。它用于获取接收事件。似乎我们可以通知关于消息队列的某些信息。但它实际上是注册通知,而不是通知任何东西。

更令人惊讶的是,mq_notify()必须在每次 mq_receive()之后调用,这可能会导致竞态条件(当在 mq_receive()mq_notify()之间的其他进程/线程调用 mq_send()时)。

它有一整套 mq_open, mq_send(), mq_receive() and mq_close(),它们有自己的定义,这是冗余的,在某些情况下与套接字 open(),send(),recv() and close()方法规范不一致。

我不认为消息队列应该用于同步。 eventfdsignalfd是适合的。

但是 它(POSIX 消息队列)有一些实时支持。它有优先的功能。

Messages are placed on the queue in decreasing order of priority, with newer messages of the same priority being placed after older messages with the same priority.

但是这个优先级也可以作为带外数据用于套接字!

最后,对我来说,POSIX 消息队列是一个遗留 API。只要不需要实时特性,我总是更喜欢 Unix Datagram 套接字而不是 POSIX 消息队列。

消息队列对于构建本地解耦应用程序非常有用。它们非常快,它们是块组织的(不需要缓冲、剪切等等,这是流式套接字的情况) ,基本上很少的 memcpy ()操作(用户代码复制块到内核,内核复制块到其他进程从 q 读取) ,这就是消息传递的故事。一些业界知名的中间件,如 Oracle Tuxedo 或 Mavimax Enduro/X,使用这些队列来帮助构建负载平衡、高性能、容错分解的分布式应用程序。当多个可执行程序从同一个队列读取数据时,这些队列允许执行负载平衡,而内核调度程序只是将消息分发给处于空闲状态的进程。Linux 的好处是可以在 Posix 队列上进行轮询,这有助于解决某些场景。对于 IBMAIX,可以对 SystemV 队列进行轮询。

例如,两个进程可以通过队列轻松地进行本地通信,吞吐量非常高(约70k req + rply/sec) :

Message sending and reply via queues / performance

如果需要联网,那么例如 Enduro/X 提供 tpbridge 进程,该进程基本上从本地队列读取消息,然后将块发送到其他机器,其中另一端将消息重新注入到本地队列中。

此外,与套接字相比,您不会遇到任何与队列有关的问题,例如,当某些二进制文件崩溃时,忙碌/延迟套接字,也就是说,启动时的程序可以立即开始读取队列并进行处理。