前一篇介绍了使用happybase连接池未关闭连接引起Broken pipe异常
这篇继续分析,当每次我们使用完连接后手动close依然会存在一个问题。
通常我们使用连接池会在全局变量中实例话一个pool对象,后续再通过pool获取连接进行后续操作。
当我们创建连接池对象后,happybase会根据size创建多个connection实例到队列中,同时会将第一个connection连接打开,注释中提到之所以打开一个连接是为了确保如果出现一些找不到主机之类的错误能第一时间发现。
class ConnectionPool(object):
def __init__(self, size, **kwargs):
if not isinstance(size, int):
raise TypeError("Pool 'size' arg must be an integer")
if not size > 0:
raise ValueError("Pool 'size' arg must be greater than zero")
logger.debug(
"Initializing connection pool with %d connections", size)
self._lock = threading.Lock()
self._queue = queue.LifoQueue(maxsize=size)
self._thread_connections = threading.local()
connection_kwargs = kwargs
connection_kwargs['autoconnect'] = False
for i in range(size):
connection = Connection(**connection_kwargs)
self._queue.put(connection)
# The first connection is made immediately so that trivial
# mistakes like unresolvable host names are raised immediately.
# Subsequent connections are connected lazily.
with self.connection():
pass
但是问题就出现在这里,当我们初始化一个连接池后如果没有立即使用,那么第一个连接池中的连接会出现被断开的情况,那么接下来拿到这个连接去操作都会出现broken pipe异常。
这里只探讨对于这个问题可能的解决方法
- 外部使用的时候为方法增加异常重试,连接池中出现异常本身会重置连接
2.第一次不打开连接,如#147处理方案
这个解决新家了一个autoconnect的参数,当autoconnect为False就不执行第一个连接。但是在connection的异常处理中还是会打开一个连接,这样也会出现同样的问题,所以这里也应该加上。
try:
# Open connection, because connections are opened lazily.
# This is a no-op for connections that are already open.
connection.open()
# Return value from the context manager's __enter__()
yield connection
connection.close()
except (TException, socket.error):
# Refresh the underlying Thrift client if an exception
# occurred in the Thrift layer, since we don't know whether
# the connection is still usable.
logger.info("Replacing tainted pool connection")
connection._refresh_thrift_client()
if autoconnect:
connection.open()
3.和1类似,只是在 happybase中处理网络异常重置连接后重试#184