(1)报错信息:
thrift.transport.TTransport.TTransportException: TSocket read 0 bytes
(2)产生原因:
可能是因为thrift 的server端和client端的协议不匹配造成的。
Python要使用TCompactProtocol,而不能使用TBinaryProtocol。
TBinaryProtocol:缺省简单的二进制序列化协议。
TCompactProtocol:高效的二进制序列化协议。
是hbase该版本自带的问题
原因1: 客户端链接hbase时传输协模式与协议与thriftpy服务端不匹配。可更改为 h_conn = happybase.Connection( host=“host”,port=port, transport=‘framed’, protocol=‘compact’ )
原因二:操作完hbase时with不会默认close thriftpy的socket链接,而HBASE的服务端有默认为60秒的超时后会主动断开,而操作者的连接池不知道,导致TTransportException(type=4, message=‘TSocket read 0 bytes’) 这个错误
原因三:第三个原因与第二个类似,但是现象有所不同。我简单的描述一下现象:当首次初始化好happybase连接池后,一直未操作查数据,过一会后,大概60秒再操作会出现标题中的问题。 原因是,happybase默认初始化链接池后,会默认去向hbase做一次链接(如下图),但为close,我个人认为这也是happybase这个包的bug。解决这个问题的办法就是,初始化好链接后,立刻做一次查询(比如查看hbase有哪些表)后close掉这个链接。可能大家会问,做查询的这个链接怎么保证就是happybase初始化的那个链接,其实只要看看源码就知道,happybase的连接池是维护的一个队列,所以第一次查询肯定是这个happybase包默认初始化而未释放的链接
(3)解决办法:
1.在服务端修改hbase-site.xml,增加TFramedTransport和TCompactProtocol功能,即:
<property>
<name>hbase.regionserver.thrift.framed</name>
<value>true</value>
</property>
<property>
<name>hbase.regionserver.thrift.compact</name>
<value>true</value>
</property>
2.然后重启thrift:$HBASE_HOME/bin/hbase-daemon.sh restart thrift
3.在客户端建立连接时增加protocol,transport参数:
conn = happybase.Connection(host="10.255.111.92",port=9090)
#修改为:
conn = happybase.Connection(host="10.255.111.92",port=9090,protocol='compact',transport='framed')
即在hbase-site.xml增加了如下内容,并重新启动thrift和hbase,问题得到解决
-
<property>
<name>hbase.thrift.server.socket.read.timeout</name>
<value>6000000</value>
</property>
<property>
<name>hbase.thrift.connection.max-idletime</name>”
<value>86400000</value>
</property>
也可以尝试使用hbase连接池的方式
原因:想保持hbase 默认的配置不动,代码里 就来一个新的数据 就新建一个连接 等写入hbase之后 就把这个连接关掉
import happybase import json # 通过size控制连接池中的连接数量 pool = happybase.ConnectionPool(size=3,host="10.255.111.92",port=9090,protocol='compact',transport='framed') # 从连接池中取出一个连接 with pool.connection() as conn: table = conn.table('test_table') # TODO 执行操作 pass # 操作完成 及时close 保证每次操作都是一个新启动的连接 conn.close() import json# 通过size控制连接池中的连接数量pool = happybase.ConnectionPool(size=3,host="10.255.111.92",port=9090,protocol='compact',transport='framed')# 从连接池中取出一个连接with pool.connection() as conn: table = conn.table('test_table') # TODO 执行操作 pass # 操作完成 及时close 保证每次操作都是一个新启动的连接 conn.close()
但我使用连接池还出现了这个问题,可能原因:再次打开连接的时候,我们就可以重用上次的连接。如果在这个时间内没有连接请求(打开连接),这个数据库连接将被关闭,并从连接池中移除这个连接实例。如果池中连接到达了最大连接数,请求进入等待队列直到空闲连接可用。如果在可获取连接对象之前超时期限已过(由 Connect Timeout 连接字符串属性来决定),则将出错。
Timeout:
HBase之超时机制 客户端超时设置对整个系统的稳定性以及敏感性至关重要,一旦没有超时设置或超时时间设置过长,服务器端的长时间卡顿必然会引起客户端阻塞等待,进而影响上层应用。好在HBase提供了多个客户端参数设置超时,主要包括 hbase.rpc.timeout / hbase.client.operation.timeout/ hbase.client.scanner.timeout.period
问题:
1.hbase60s服务端关闭,会自动重启连接吗?还是代码重启
2.应用连接池可以创建多个连接,但还会报这个错的原因是:同一时刻创建的连接池都同时超时还没来得及新建连接吗?