BUG日寄 —— Python中TCP重连机制未设置好导致线程池队列满
BUG原因:部分组件停用,做测试时未注意TCP重连机制问题。
BUG现象:在一段时间正常运行后,进程中的线程池队列溢出,建立TCP连接的线程阻塞整个线程池,所有线程无法正常运行,但进程不受影响。
BUG解决:在进程间进行TCP连接的过程中,应避免让重置连接的方法自我迭代,并尽可能采用短链接的方式建立连接。
出错的代码片段如下:
import socket
import log
class TcpClient(object):
def __init__(self, service_ip, service_port):
self.conn = None
self.service_ip = service_ip
self.service_port = service_port
def connect(self):
try:
self.conn = socket.socket()
self.conn.connect((self.service_ip, self.service_port))
log.info("Tcp connect success!")
except Exception as e:
time.sleep(1)
self.connect()
log.warning("Tcp connect failed!")
def work(self):
try:
self.conn.send("test".encode())
self.conn.close()
except Exception as e:
log.warning("Work failed!")
在这个代码片段中,在发生异常无法建立连接时会睡眠1秒然后再次调用connect函数尝试再次建立连接。
而实际上在连接无法正常建立时,该代码会进入死循环。
又由于连接方式是短链接,在多线程调用模式下调用connect()方法的线程会越来越多,会导致线程池队列阻塞进而阻碍线程池中所有线程功能的正常运行。
正常情况下可将重连机制放在连接建立的业务处实现,不在组件封装的位置添加,使用阻塞式的方法来建立连接,防止出现线程池阻塞的情况。
示例:
import socket
from concurrent.futures import ThreadPoolExecutor
import socket
import log
import time
class TcpClient(object):
def __init__(self, service_ip, service_port):
self.conn = None
self.service_ip = service_ip
self.service_port = service_port
def connect(self):
try:
self.conn = socket.socket()
self.conn.connect((self.service_ip, self.service_port))
log.info("Tcp connect success!")
return True
except Exception as e:
log.warning("Tcp connect failed!")
return False
def work(self):
try:
self.conn.send("test".encode())
self.conn.close()
except Exception as e:
log.warning("Work failed!")
if __name__ == "__main__":
executor = ThreadPoolExecutor(max_workers=10)
tc = TcpClient("1.1.1.1",5000)
while 1:
if tc.connect:
executor.submit(tc.work())
break
else:
time.sleep(1)
PS:在采用长连接的模式与硬件编码设备进行沟通时,会出现接收请求时间过长的问题,问题原因未找到,换成短链接后解决。