在使用HBase的时候客户端偶尔会出现超时等问题,所以本文打算简单分析下HBase客户端相关的源码,初步了解其中比较核心的机制。
客户端连接源码分析:
Connection的创建:
程序中设置好HBase相关连接属性之后,调用ConnectionFactory.createConnection(conf)方法连接HBase。内部是使用反射的方法初始化对应类的:
该类内部有三个比较重要的属性:
//负责RPC调用
RpcClient rpcClient;
//用于获取集群的基本信息,例如meta region location
Registry registry;
//用于同步处理批量请求
AsyncProcess asyncProcess;
getTable():
Connection是线程安全的,而HTable是非线程安全的,看一下getTable内部做了什么操作:
可以看到,在默认情况下会创建线程数为256的线程池,这个线程池注释说是For Multi & Scan,即在批量操作(例如gets)和scan操作时候使用。
MultiAction中每个操作都会封装成一个Runnable任务提交到这个线程池里面执行:
客户端以及租约超时问题分析:
之前写过一篇文章《Spark拉取HBase数据时遇到的问题》,当时遇到的问题是,客户端超时以及RegionServer端Lease过期,里面提到了一些超时参数,但是没有到源码层面进行深入的研究,此处从源码层面进行超时机制的一些分析:
RPC超时机制相关配置:
hbase.rpc.timeout:
一次rpc请求的超时时间,如果某次RPC请求超过该值,客户端就会主动管理Socket。
hbase.client.retries.number:
HBase执行RPC失败之后会执行重试操作,该值表示客户端重试的最大次数.默认是35。个人觉得应该设置小一点,没必要设置的这么多。
hbase.client.pause:
失败重试时等待时间,注意,随着重试次数增多,重试等待时间会增长。
Lease租约机制如下:
在HBase服务端会为每个Scan都生成一个Lease,这个代表当前Scan和RegionServer的一个租约。
如果当前Scan拉取数据超过一定时间(例如数据都在磁盘上,要一次性拉取10W条,超过了默认Lease超时时间60s),这个Lease就会被认为是失效删除掉。当数据加载完成后,客户端拿这已经任务失效的Scan再去取数据的时候,HBase的RegionServer端就会报LeaseException错误:
但是租约过期之后,为了客户端的Scan还能继续获取到数据,服务器端会再创建一个Lease,LeaseName使用的还是原来的名称,如果此时不增加上面说到的RPC超时时间,客户端还是会报Lease不存在错误。
所以如果RegionServer端报Lease不存在问题时,需要同时提高RPC超时时间以及Lease租约过期时间。Lease租约过期时间由hbase.client.scanner.timeout.period属性控制:
hbase.client.scanner.timeout.period:
专门为Scan操作设置的超时机制,该参数是表示HBase客户端发起一次scan操作的rpc调用至得到响应之间总的超时时间。
一次scan操作是指发起一次regionserver rpc调用的操作,hbase会根据scan查询条件的cacheing、batch设置将scan操作会分成多次rpc操作。比如满足scan条件的rowkey数量为10000个,scan查询的cacheing=200,则查询所有的结果需要执行的rpc调用次数为50个。两次RPC请求之前的值不能超过这个数…就是说在这个时间之内,这一批数据要获取到并且处理完。
其他一些超时时间说明:
hbase.client.operation.timeout:
该参数表示HBase客户端发起一次数据操作直至得到响应之间总的超时时间,数据操作类型包括get、append、increment、delete、put等。很显然,hbase.rpc.timeout表示一次RPC的超时时间,而hbase.client.operation.timeout则表示一次操作的超时时间,有可能包含多个RPC请求。
参考:
https://my.oschina.net/u/2244820/blog/1620967
https://wenku.baidu.com/view/828bd30103d8ce2f00662300.html
https://www.2cto.com/database/201504/387156.html
https://aperise.iteye.com/blog/2372350