每个线程或每个调用一个 ZeroMQ 套接字?

2023-12-07

众所周知,ZeroMQ套接字不得共享应用程序线程之间.
context_t但实例可以。

我有一个多线程应用程序,我想让每个线程不时与一个线程交换消息REQ/REP-socket 对方(事件、异常等),取决于他们正在做什么(他们正在做非 ZeroMQ 的事情)。

发送消息给我的REQ/REP-socket 我使用以下功能
(半C++半伪代码):

sendMessage:

bool sendMessage(std::string s)
{
    zmq::socket_t socket(globalContext(), ZMQ_REQ);
    socket.connect("ipc://http-concentrator");

    zmq::message_t message(s.size());
    memcpy(message.data(), s.data(), s.size());
    if (!socket.send(message))
        return false;

    // poll on socket for POLLIN with timeout

    socket.recv(&message);
    // do something with message

    return true;
}

当需要时,每个线程都会调用此函数。它创建本地套接字、连接、发送消息并接收响应。在退出时,套接字被断开连接并被删除(至少我假设它已关闭)。

这样,我就不需要费心在每个线程中维护一个套接字。这是以每次调用此函数时创建和连接为代价的。

我已经强调了这段代码,并且我没有看到重用一个套接字和此重新连接实现之间有多大区别。 (我有20kREP/REQ每秒事务数,包括用例两侧的 JSON 解码/编码)

Q:有更正确的 ZeroMQ 方法吗?


Nota Bene: this answer was posted before O/P was changed from 20k TPS to 140k TPS on ipc:// transport-class

Q: 有没有more正确的 ZeroMQ 做法this?

A:Not easy to say what is "this" and what are the parameters of the "correctness"-metric

鉴于,
以下几点将更加普遍
并适用于系统设计阶段推理:


避免资源利用开销

这一点是一把双刃剑。一些管理费用始终与基础设施元素的设置和处置(是的,甚至是关闭和拆除)相关。REQ- 访问点REQ/REP-pattern 和相关的基于套接字的传输类给两者带来了一些显着的开销REQ端主机以及REP-side.

您注意到,您在大约 20k TPS 的水平上对此进行了一些定量测试,并且没有观察到这种方法的任何不利影响,这是公平的。尚不清楚的是,是否还在同一 SUT(被测系统)上对任何其他场景进行了体内测试,以便为每个设计的比较提供一些基线(并允许确定开销的差异)本身)。

虽然设计良好的框架向用户维护的代码隐藏了这部分系统内部行为,但这并不意味着,这一切都是廉价的,更不是免费的处理。

很明显,在幕后有一些工作在进行Context()-实例线程(...是的,这里使用复数是正确的,因为某些高性能代码可能会受益于每个线程使用多个 I/O 线程Context()实例并通过模式套接字与其各自的 I/O 线程处理程序之间显式定义的关联映射来积极影响工作负载分配(以便以某种方式平衡(如果无法确定性地调整)预期的 I/O 吞吐量,包括.所有相关的管理费用)。

如果仍然有疑问,人们应该永远记住,命令式编程风格的函数或面向对象的方法主要是外部调用者的受害者,外部调用者决定在哪一刻以及多久这样一次“被奴役的“代码执行单元被值班调用并被执行。该函数/方法没有任何自然手段来回溯(抑制)来自外部调用者的调用频率,并且健壮的设计根本无法保持仅依赖乐观的假设,即此类调用不会比 XYZ-k TPS 更频繁(上面引用的 20k 对于体外测试可能没问题,但实际部署可能会改变几个数量级的操作(无论是人为的 - 在测试期间)或不 - 在某些高峰时段或用户(系统)恐慌期间或由于某些技术错误或硬件故障(我们都多次听说过 NIC 卡淹没 L1/L2 流量超出所有可想象的限制等) - 我们只是不知道也不可能知道下次它会在何时何地再次发生)。

避免阻塞风险

其中提到的REQ/REP可扩展的正式通信模式因其陷入外部无法解决的分布式内部死锁的风险而闻名。这始终是需要避免的风险。缓解策略可能取决于实际用例的风险价值(需要认证医疗仪器、金融科技用例、控制循环用例、学术研究论文代码或私人爱好玩具)。

Ref.: REQ/REP死锁>>>https://stackoverflow.com/a/38163015/3666197

Fig.1:为什么使用 naive 是错误的REQ/REP
所有情况当[App1]in_WaitToRecvSTATE_W2R + [App2]in_WaitToRecvSTATE_W2R
主要是不可挽救的分布式相互死锁REQ-FSA/REP-FSA(两个有限状态自动机都等待“另一个”移动)并且永远不会到达“下一个”in_WaitToSendSTATE_W2S内部状态。

               XTRN_RISK_OF_FSA_DEADLOCKED ~ {  NETWORK_LoS
                                         :   || NETWORK_LoM
                                         :   || SIG_KILL( App2 )
                                         :   || ...
                                         :      }
                                         :
[App1]      ![ZeroMQ]                    :    [ZeroMQ]              ![App2] 
code-control! code-control               :    [code-control         ! code-control
+===========!=======================+    :    +=====================!===========+
|           ! ZMQ                   |    :    |              ZMQ    !           |
|           ! REQ-FSA               |    :    |              REP-FSA!           |
|           !+------+BUF> .connect()|    v    |.bind()  +BUF>------+!           |
|           !|W2S   |___|>tcp:>---------[*]-----(tcp:)--|___|W2R   |!           |
|     .send()>-o--->|___|           |         |         |___|-o---->.recv()     |
| ___/      !| ^  | |___|           |         |         |___| ^  | |!      \___ |
| REQ       !| |  v |___|           |         |         |___| |  v |!       REP |
| \___.recv()<----o-|___|           |         |         |___|<---o-<.send()___/ |
|           !|   W2R|___|           |         |         |___|   W2S|!           |
|           !+------<BUF+           |         |         <BUF+------+!           |
|           !                       |         |                     !           |
|           ! ZMQ                   |         |   ZMQ               !           |
|           ! REQ-FSA               |         |   REP-FSA           !           |
~~~~~~~~~~~~~ DEADLOCKED in W2R ~~~~~~~~ * ~~~~~~ DEADLOCKED in W2R ~~~~~~~~~~~~~
|           ! /\/\/\/\/\/\/\/\/\/\/\|         |/\/\/\/\/\/\/\/\/\/\/!           |
|           ! \/\/\/\/\/\/\/\/\/\/\/|         |\/\/\/\/\/\/\/\/\/\/\!           |
+===========!=======================+         +=====================!===========+

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

每个线程或每个调用一个 ZeroMQ 套接字? 的相关文章

随机推荐