我正在处理点对点通信系统(用python3.5编写和运行)中的分布式“死锁”情况。在这个系统中,每个节点与每个节点保持2个所谓的incon和outconn连接。我使用select.poll()执行多路复用。因此,有时会发生以下死锁:如果两个连接的对等方都试图通过outconn发送到另一个,则每个对等方的select.poll()循环在send()中被阻塞,因此另一方无法在incon连接上接收()
我处理这种死锁的方法是在outconnn的套接字上设置timeout(),这似乎是可行的。然而,有趣的是,消息似乎能够在套接字超时后到达目的地。以下是两个节点的示例日志:
节点A(192.168.56.109)
INFO: [2016-11-02 11:08:05,172] [COOP] Sending ASK_COOP [2016-11-02 11:08:05.172643] to 192.168.56.110 for segment 2.
WARNING: [2016-11-02 11:08:06,173] [COOP] Cannot send to 192.168.56.110. Error: timed out
INFO: [2016-11-02 11:08:06,174] [COOP] Message from 192.168.56.110 is available on 10.
INFO: [2016-11-02 11:08:06,174] [COOP] Get HEARTBEAT [2016-11-02 11:08:04.503723] from 192.168.56.110 for segment 2.
节点B(192.168.56.110)
INFO: [2016-11-02 11:08:04,503] [COOP] Sending HEARTBEAT [2016-11-02 11:08:04.503723] to 192.168.56.109 for segment 2.
WARNING: [2016-11-02 11:08:05,505] [COOP] Cannot send to 192.168.56.109. Error: timed out
INFO: [2016-11-02 11:08:05,505] [COOP] Message from 192.168.56.109 is available on 11.
INFO: [2016-11-02 11:08:05,505] [COOP] Get ASK_COOP [2016-11-02 11:08:05.172643] from 192.168.56.109 for segment 2.
我能知道为什么吗?顺便问一下,我处理这种僵局的方式是一种好的做法吗?如果不是,那么避免这种分布式死锁的最佳实践是什么
根据我的经验,避免此问题的最佳实践是始终使用非阻塞I/O。如果您的应用程序从不在send()或recv()内阻塞,那么就不会出现死锁(至少,不是您描述的那种死锁)
当然,非阻塞I/O带来了它自己的复杂性,特别是,您的代码需要能够正确处理部分发送和部分接收。实际上,这意味着您的应用程序的事件循环可能如下所示(伪代码):
在这种设计中,每当你的应用程序生成了新的数据,它想在套接字上发送,它不应该直接调用send();相反,它应该将该数据附加到与该套接字相关联的FIFO发送缓冲区的末尾,并且上面的事件循环将允许尽快发送数据(当然,在发送任何已经存在于FIFO中的数据之后),而不会阻止事件循环执行它可能具有的任何其他职责
在最坏的情况下(一个非常慢的TCP连接,你想通过它发送大量数据),FIFO可能会变大(使用额外的内存),但它永远不会“死锁”
相关问题 更多 >
编程相关推荐