ZeroMQ 在 context.term() 调用中阻塞。为什么?如何预防?

ZeroMQ blocked in a context.term() call. Why? How to prevent?

我有一个使用 ZeroMQ 的 java 程序。

但我发现程序在 context.term(); 中被阻止,如果接收到 message( recvMsg() ) 超时!

ZMQ.Context context = ZMQ.context(1);  
ZMQ.Socket socket = context.socket(ZMQ.REQ);  
socket.connect(mAddress);         

ZMsg ZM = new ZMsg();
ZM.add(qString);
ZM.send(socket, true);

socket.setReceiveTimeOut(mTimeout);     
ZMsg receivedZM = ZMsg.recvMsg(socket);

if(receivedZM != null) {
    System.out.println(receivedZM.getFirst().toString());   
}      
socket.close();  
context.term(); 

阻塞是什么原因?

以及如何解决这个问题?

根据API,http://api.zeromq.org/4-2:zmq-term,当还有消息要传输时,它会阻塞。这表明您是其他机器或进程,将打开 REP 套接字的那个;不是 运行.

ZeroMQ 是一个在 Context()-factory

背后使用许多技巧的系统

我一直提倡在 Socket 实例化时自动设置 .setsockopt( ZMQ_LINGER, 0 ),正是由于这些类型的行为,否则将保留在您的本地代码之外控制域。一个挂起的 Context-instance IO-thread(s)(尽管所有 socket-instances 尚未成功 .close(),但已发出编程的 .term() , 在这个 Context 实例下实例化 .term() 是为了拆除并释放所有系统资源,或者是一个未处理的异常情况,当事情直接发生破坏时)是这样的一种 - s.

请随意遵循教科书和在线 hacks/snippet 示例,但认真的分布式系统设计人员应该采取所有合理的步骤和措施,以防止 her/his 系统代码陷入任何死锁状态(少成不可救药)。


这是什么原因?

如文档所述 - 它是 ZeroMQ 的内置功能:

attempting to terminate the socket's context with zmq_ctx_term() shall block until all pending messages have been sent to a peer.

任何情况下,.send()-已分派(刚刚分派——绝不意味着它已经被发送到电汇)消息仍在本地队列中以供任何已识别的(并且可能断开连接或忙碌或...)对等节点,刚刚默认配置的 .term() 无法继续并将阻塞。


解决方法是什么:

较新的 API 版本开始说,默认的 LINGER 值不再是 -1 == INFINITY,但你永远不知道,哪个版本将与您的代码交互,对 .setsockopt( ZMQ_LINGER, 0 ) 方法的显式(手动)调用是一个自律步骤,可以提高您的团队对如何构建可靠的分布式系统代码的认识。

使用try: / except: / finally: syntax-handlers 这里就不用提了。您只是在设计时始终要考虑到故障和碰撞,不是吗?