Hbase提供Thrift實(shí)現(xiàn)多語言的支持,python的happybase就是其中一個(gè)實(shí)現(xiàn)粘茄。
最近在使用happybase出現(xiàn)TTransportException和Broken pipe的異常戒职,記錄一下解決方案。
環(huán)境:
python:3.6.2
happbase:1.1.0
hbase:1.2.4
現(xiàn)象:要每幾分鐘左右往HBase插入一條數(shù)據(jù)韵丑,但是侯谁,在大約1分鐘過后,被服務(wù)器斷開了連接堡称,然后再嘗試插入的時(shí)候瞎抛,拋出broken pipe.
復(fù)現(xiàn)代碼:
import happybase
import time
def put(pool,data):
with pool.connection() as conn:
table = conn.table('Log')
row_key = str(int(time.time())) + '000001'
data = data
table.put(row_key, data)
if __name__ == '__main__':
pool = happybase.ConnectionPool(size=3, host='127.0.0.1', table_prefix='TL')
put(pool,{})
time.sleep(60) # 模擬間隔時(shí)間
put(pool, {})
分析:Broken pipe往往是因?yàn)榭蛻舳撕头?wù)器的TCP連接斷開引起的。
通過google發(fā)現(xiàn)hbase thrift server有一個(gè)超時(shí)的配置hbase.thrift.server.socket.read.timeout却紧,當(dāng)客戶端和服務(wù)器的連接超過該值沒有收到消息的時(shí)候桐臊,該連接會(huì)被斷開,默認(rèn)值為60秒晓殊,正好跟本次現(xiàn)象發(fā)生的場景一致断凶,每隔60秒連接斷開。參考[HBASE-14926]https://issues.apache.org/jira/browse/HBASE-14926
查看happybase連接池相關(guān)的代碼發(fā)現(xiàn)在with完成后connection并沒有close巫俺,直接返回到連接池當(dāng)中认烁。
@contextlib.contextmanager
def connection(self, timeout=None):
connection = getattr(self._thread_connections, 'current', None)
return_after_use = False
if connection is None:
return_after_use = True
connection = self._acquire_connection(timeout)
with self._lock:
self._thread_connections.current = connection
try:
connection.open()
yield connection
except (TException, socket.error):
logger.info("Replacing tainted pool connection")
connection._refresh_thrift_client()
connection.open()
raise
finally:
if return_after_use:
del self._thread_connections.current
self._return_connection(connection)
而問題就出現(xiàn)在這里,返回到連接池中的connection在1分鐘后沒有使用介汹,被斷開了連接却嗡,當(dāng)下一次再拿這個(gè)connection去請求資源就會(huì)出現(xiàn)Broken pipe的異常。
接下來就到了解決問題的時(shí)候嘹承,一般來講可以有兩個(gè)解決方案:
1.配置hbase.thrift.server.socket.read.timeout窗价,增加超時(shí)時(shí)間
2.在使用connection后關(guān)閉連接
import happybase
import time
def put(pool,data):
with pool.connection() as conn:
table = conn.table('Log')
row_key = str(int(time.time())) + '000001'
data = data
table.put(row_key, data)
conn.close() # 關(guān)閉連接
if __name__ == '__main__':
pool = happybase.ConnectionPool(size=3, host='127.0.0.1', table_prefix='TL')
put(pool,{})
time.sleep(60) # 模擬間隔時(shí)間
put(pool, {})