title: Python 讀寫 hbase 數據的正確姿勢(四)
tags:
- hbase
- happybase
- python
categories:
- ?Hbase
comments: true
date: 2017-10-08 16:00:00
問題4: 查詢異常 TApplicationException: Missing result
在上一篇文章中討論了線上測試時出現 [Errno 32] Broken pipe
錯誤,這里繼續分析另一個錯誤 TApplicationException: Missing result
。
問題描述
在解決了問題 3 后,又遇到了古怪的錯誤:在查詢的過程中,出現了大量的 TApplicationException: Missing result
錯誤:
File "/usr/local/lib/python2.7/site-packages/happybase/table.py", line 402, in scan
self.name, scan, {})
File "/usr/local/lib/python2.7/site-packages/thriftpy/thrift.py", line 198, in _req
return self._recv(_api)
File "/usr/local/lib/python2.7/site-packages/thriftpy/thrift.py", line 234, in _recv
raise TApplicationException(TApplicationException.MISSING_RESULT)
thriftpy.thrift.TApplicationException: Missing result
而且,在大量出現此類錯誤之前伴有 timeout: timed out
超時:
File "/usr/local/lib/python2.7/site-packages/happybase/table.py", line 415, in scan
scan_id, how_many)
File "/usr/local/lib/python2.7/site-packages/thriftpy/thrift.py", line 198, in _req
return self._recv(_api)
File "/usr/local/lib/python2.7/site-packages/thriftpy/thrift.py", line 210, in _recv
fname, mtype, rseqid = self._iprot.read_message_begin()
File "thriftpy/protocol/cybin/cybin.pyx", line 429, in cybin.TCyBinaryProtocol.read_message_begin (thriftpy/protocol/cybin/cybin.c:6325)
File "thriftpy/protocol/cybin/cybin.pyx", line 60, in cybin.read_i32 (thriftpy/protocol/cybin/cybin.c:1546)
File "thriftpy/transport/buffered/cybuffered.pyx", line 65, in thriftpy.transport.buffered.cybuffered.TCyBufferedTransport.c_read (thriftpy/transport/buffered/cybuffered.c:1881)
File "thriftpy/transport/buffered/cybuffered.pyx", line 69, in thriftpy.transport.buffered.cybuffered.TCyBufferedTransport.read_trans (thriftpy/transport/buffered/cybuffered.c:1948)
File "thriftpy/transport/cybase.pyx", line 61, in thriftpy.transport.cybase.TCyBuffer.read_trans (thriftpy/transport/cybase.c:1472)
File "/usr/local/lib/python2.7/site-packages/thriftpy/transport/socket.py", line 108, in read
buff = self.sock.recv(sz)
timeout: timed out
服務端沒有任何異常。
問題分析
看起來這種情況和上文問題 3 中Broken pipe
+ TTransportException
的錯誤組合模式比較類似,所以猜測timeout 是導致這種現象的導火索,為了驗證猜想,嘗試在測試環境手動復現錯誤場景:
conn_pool = None
TABLE = 'article'
# 本地環境 timeout 設置為1 時 超時較多
# 生產環境為 10
def get_connetion_pool(timeout=1):
global conn_pool
if conn_pool is None:
conn_pool = happybase.ConnectionPool(1, timeout=timeout)
return conn_pool
def recent_events_v3(start, end, table=None, filter_str=None, limit=2000):
with get_connetion_pool().connection() as conn:
if table is not None:
t = conn.table(table)
else:
t = conn.table(TABLE)
start_row = 'ARTICLE' + str(start * 1000000)
end_row = 'ARTICLE' + str(end * 1000000)
return t.scan(row_start=start_row, row_stop=end_row, filter=filter_str, limit=limit)
def main():
# 問題4復現
for i in range(100):
# 有timeout,有 Missing result,有正常查詢
try:
results = recent_events_v3(start=0, end=1505646570, table="test_article_java_2")
print len([i for i in results])
except Exception as e:
print e
print '#########################################'
運行結果如下:
而當把 timeout 增加到一個較大值時則不會出現這種情況。印證了猜想 TApplicationException: Missing result
異常前一定出現過 timeout
。
解決問題
增大 timeout 后,可以很大程度上減少這樣的情況發生,但是 timeout
不同于問題 3 的 IllegalArgumentException
錯誤,可以主動控制,使用 scan 的查詢場景以及網絡環境本身(在穩定的場景,仍有可能出現抖動導致超時) 難以避免的會出現 timeout,所以僅僅增加 timeout 值,仍然后可能會出現這種情況。
問題 3 會出現 Broken Pipe
錯誤是因為之前發生錯誤導致連接失效,后續再使用異常連接時則會報錯。問題 4 是否也是因為 timeout 后導致連接出問題,然后出現這種情況呢?
嘗試驗證這種猜想:在發生 timeout 時,catch 住并重新初始化連接池然后重試:
def main():
# 問題4修復
for i in range(30):
# 沒有 Missing result,只有 timeout 和 有正常查詢
try:
results = recent_events_v3(start=0, end=1505646570, table="test_article_java_2")
print len([i for i in results]) # 期望值為2, 實際報錯
except socket.timeout:
conn_pool = None # catch timeout 后, 清空連接池,下次使用時重新初始化, 僅限單線程模型 !
print 'time out: reinit conn pool!'
# print traceback.format_exc()
# 不會在出現 `TApplicationException: Missing result` 錯誤
print '#########################################'
修改后運行測試代碼只會出現 timeout,不會出現其他錯誤:
因為生產環境是多容器,每個容器單進程,在這種場景下連接池和一個全局變量連接的意義相差不大,整個連接池同一時刻只會被一個進程使用(所以連接池只初始化了 1 條連接),所以直接重置連接池是可以的,此時可以徹底避免 Missing results
~
繼續思考
上文文末提到一個疑惑 :為什么一條異常的連接會出現在 connect pool 中,而且總會拿到這條連接 ? 。
這次同樣還有另一個問題值得思考:timeout 后為什么會出現大量的 Missing results
錯誤?是否如同猜測的那樣 timeout 后連接池中的連接失效了?
下篇文章見~