使用zmq进行多线程发布

时间:2014-10-03 16:28:55

标签: c++ multithreading zeromq

我有一个问题,关于在ZMQ中从多个线程发布到单个订户的最佳方式是。我有一个用C ++编写的Web服务器,对于每个连接,都需要向订阅者发送ZMQ消息。这些服务器可以有数百到数千个并发连接,所以我很好奇写入这个用户的最有效方法是什么。我可以想到三种不同的方式。

分享连接

我不相信这种方式会起作用,但基本上只有一个连接指针,并将其传递给所有线程。我假设(当我在ZMQ网站上搜索时找不到太多信息),这将导致竞争条件,因为我不认为zmq_msg_send()是线程安全的。我可以在send上放一个互斥来解决这个问题,但我担心速度,因为我的服务器需要尽可能快。

共享队列

这类似于共享连接,但是以不同的方式,而不是在zmq_msg_send()周围放置一个互斥体,而是在一个共享的消息向量周围发送一个互斥量,并有一个写入线程来处理所有这些消息。我相信这会比之前的方法更快,因为写入向量可能比做zmq_msg_send()快得多,但是,如果可能的话,我想避免等待。

每个帖子的连接

我能想到避免互斥等待的唯一方法是每个线程打开一个zmq连接(这意味着我进入每个连接,作为每个线程一个用户连接的进程)。这可能是可行的,虽然我不知道zmq_connect是如何工作的。在建立连接之前会阻塞吗?理想情况下,我的流程会是这样的:

user_connection()
{
    createZMQConnection();
    doWork();
    sendData();        
}

但是,如果创建连接块,则最好使用共享队列。

有没有人提出类似的申请,或者有人知道推荐的模式是什么?任何见解将不胜感激。

编辑:

感谢您的回复,我只是在查看zmq文档,发现了很多你在谈论的内容,但也许你可以澄清一下。

至于我的基础设施,我有很多酒吧到单子。酒吧是连接和sub绑定。

我有多个负载均衡的盒子,每个盒子运行多个线程。总的来说,我看到大约30,000条消息/秒。每盒,我可能会看到大约2,000-4,000条消息/秒。我每次请求的通常处理时间大约是40ms,因此我经常会打开大约100-200个并发实例。我不确定是否会打开200个并发套接字对象,或者这是否是ZMQ做事的方式。根据事物的声音,我应该将zmq :: context传递给每个线程并在那里创建套接字。

这就是我想象的代码将如何流动,如果这看起来正确,请告诉我

void receiveConnection()
{
    zmq::context_t context(1);
    doWorkClass c(context);
    c.run();
}

doWorkClass(context)
{
    socket(context, ZMQ_PUB);
}

void doWorkClass::run()
{
    sendString = doWork();
    s_send(socket,sendString);
}

所以我为所有套接字使用一个上下文,并为每个线程创建一个套接字,完成我的工作,并发送我的消息。

2 个答案:

答案 0 :(得分:4)

ZeroMQ的思维方式有点不同

从您的想法中可以看出,您尝试优化资源并尝试避免访问它们的竞争条件。

ZeroMQ确实看起来“相似”,但工作方式略有不同。忘记指针,忘记阻塞和类似的问题。

ZeroMQ是一个依赖

的抽象层

这意味着,您可以将多个线程创建为 PUB ,并且有一个 SUB (或几个,具有负载均衡设计) ),它消耗所有传入的事件流。

根据给出的信息集,似乎需要一个设置,其中:

  • 一个中央流程(如果已分发,则使用已知的ip:端口地址)为该“中心”创建 SUB -archetype, .bind() 点“并将其自己的订阅(以避免任何过滤)设置为 ""
  • 所有ad-hoc创建的线程将其自己的 PUB 原型和 .connect() 实例化为“中心节点”
  • 可能希望添加任何其他信令/状态控制/自己协议握手消息传递原型,并行操作,以满足您的系统要求。

零共享原则

ZeroMQ不鼓励与ZeroMQ套接字共享接入点,这不是一种线程安全的方法,原则上应该避免使用。

零阻塞原则

ZeroMQ也不鼓励所有“低级别”和系统信令/阻塞手段。

如果需要,可以为线程到线程的软SIG信令创建另一层。状态的控制。

您的所有消息流都可以设计为非阻塞(确实可以轻松地降低性能)。如您所示,您的服务器需要速度。

  

您的MSG / msec&的峰值速率和持续速率是多少? MB /毫秒有点量化吗?

您可以在StackOverflow和ZeroMQ Web上找到ZeroMQ层的合理性能测试,以便进行比较。

答案 1 :(得分:2)

最佳(我相信单一或最正确)实现目标的方法是使用每线程连接方法。

您需要在线程体中创建新的套接字(作为客户端),建立连接,确保通过实现简单的握手程序并且仅在开始推送数据后才连接。

此处的握手非常重要,因为zmq_connect无法保证在呼叫结束后套接字就可以立即传输。

我通常使用ZMQ_PAIR套接字(当应用程序期望在单个主机上运行时),父级和子级之间共享URL,或者分布式环境使用REQ / REP。