网易视频云是网易倾力打造的一款基于云计算的分布式多媒体处理集群和专业音视频技术,为客户提供稳定流畅、低时延、高并发的视频直播、录制、存储、转码及点播等音视频的 PaaS 服务。在线教育、远程医疗、娱乐秀场、在线金融等各行业及企业用户只需经过简单的开发即可打造在线音视频平台。现在,网易视频云与大家分享一下 HBase 最佳实践-客户端超时机制。
除了重试机制外,业务童鞋最关心的就是超时机制了。客户端超时设置对整个系统的稳定性以及敏感性至关重要,一旦没有超时设置或超时时间设置过长,服务器端的长时间卡顿必然会引起客户端阻塞等待,进而影响上层应用。好在 HBase 提供了多个客户端参数设置超时,主要包括 hbase.rpc.timeout / hbase.client.operation.timeout / hbase.client.scanner.timeout.period 。然而这些参数官方并没有给出具体的介绍,导致开发人员并不真正理解这些参数的含义。接下来本文分别对这三个参数进行介绍,应用童鞋可以根据自己的实际情况对这三个参数进行设置。
hbase.rpc.timeout
从字面意思就可知道,该参数表示一次 RPC 请求的超时时间。如果某次 RPC 时间超过该值,客户端就会主动关闭 socket 。此时,服务器端就会捕获到如下的异常:
上述异常经常发生在大量高并发读写业务或者服务器端发生了比较严重的 Full GC 等场景下,导致某些请求无法得到及时处理,超过了时间间隔。该值默认大小为 60000ms ,即 1min 。
hbase.client.operation.timeout
该参数表示 HBase 客户端发起一次数据操作直至得到响应之间总的超时时间,数据操作类型包括 get 、 append 、 increment 、 delete 、 put 等。很显然, hbase.rpc.timeout 表示一次 RPC 的超时时间,而 hbase.client.operation.timeout 则表示一次操作的超时时间,有可能包含多个 RPC 请求。举个例子说明,比如一次 Put 请求,客户端首先会将请求封装为一个 caller 对象,该对象发送 RPC 请求到服务器,假如此时因为服务器端正好发生了严重的 Full GC ,导致这次 RPC 时间超时引起 SocketTimeoutException ,对应的就是 hbase.rpc.timeout 。那假如 caller 对象发送 RPC 请求之后刚好发生网络抖动,进而抛出网络异常, HBase 客户端就会进行重试,重试多次之后如果总操作时间超时引起 SocketTimeoutException ,对应的就是 hbase.client.operation.timeout 。
hbase.client.scanner.timeout.period
看到这里为止,很多细心的童鞋都会发现, hbase.client.operation.timeout 参数规定的超时基本涉及到了 HBase 所有的数据操作,唯独没有 scan 操作。然而 scan 操作却是最有可能发生超时的,也因此是用户最为关心的。 HBase 当然考虑到了这点,并提供了一个单独的超时参数进行设置: hbase.client.scanner.timeout.period 。这个参数理解起来稍微有点复杂,需要对 scan 操作本身有比较全面的理解,这可能也是很多业务用户并不了解的地方。
首先,我们来看一个最简单的 scan 操作示例:
很多人都会误认为一次 scan 操作就是一次 RPC 请求,实际上,一次请求大量数据的 scan 操作可能会导致多个很严重的后果:服务器端可能因为大量 io 操作导致 io 利用率很高,影响其他正常业务请求;大量数据传输会导致网络带宽等系统资源被大量占用;客户端也可能因为内存无法缓存这些数据导致 OOM 。基于此, HBase 会将一次大的 scan 操作根据设置条件拆分为多个 RPC 请求,每次只返回规定数量的结果。上述代码中 foreach(Result r : rs)语句实际上等价于 Result r = rs.next(),每执行一次 next()操作就会调用客户端发送一次 RPC 请求,参数 hbase.client.scanner.timeout.period 就用来表示这么一次 RPC 请求的超时时间,默认为 60000ms ,一旦请求超时,就会抛出 SocketTimeoutException 异常。
讲到这里,就借用宝地引申地讲讲另外两个相关的问题:
1. 上文提到一次大的 scan 操作会被拆分为多个 RPC 请求,那到底会拆分为多少个呢?
一次 scan 请求的 RPC 次数主要和两个因素相关,一个是本次 scan 的待检索条数,另一个是单次 RPC 请求的数据条数,很显然,两者的比值就是 RPC 请求次数。
一次 scan 的待检索条数由用户设置的条件决定,比如用户想一次获取某个用户最近一个月的所有操作信息,这些信息总和为 10w 条,那一次 scan 总扫瞄条数就是 10w 条。为了防止一次 scan 操作请求的数据量太大,额外提供了参数 maxResultSize 对总检索结果条数进行限制,该参数表示一次 scan 最多可以获取到的数据条数,默认为-1 ,表示无限制,如果用户设置了该参数,最后的返回结果条数就是该值与实际检索条数的更小者。
单次 RPC 请求的数据条数由参数 caching 设定,默认为 100 条。因为每次 RPC 请求获取到数据都会缓存到客户端,因此该值如果设置过大,可能会因为一次获取到的数据量太大导致客户端内存 oom ;而如果设置太小会导致一次大 scan 进行太多次 RPC ,网络成本高。
具体使用可以参考上文代码示例。
2. 经常有业务童鞋问道,在 scan 过程中 RegionServer 端偶尔抛出 leaseException ,是怎么回事?
看到 leaseException 就会想到租约机制,的确, HBase 内部在一次完整的 scan 操作中引入了租约机制。为什么需要租约机制?这和整个 scan 操作流程有莫大的关系,上文讲到,一次完整的 scan 通常会被拆分为多个 RPC 请求,实际实现中, RegionServer 接收到第一次 RPC 请求之后,会为该 scan 操作生成一个全局唯一的 id ,称为 scanId 。除此之外, RegionServer 还会进行大量的准备工作,构建整个 scan 体系,构造需要用到的所有对象,后续的 RPC 请求只需要携带相同的 scanId 作为标示就可以直接利用这些已经构建好的资源进行检索。也就是说,在整个 scan 过程中,客户端其实都占用着服务器端的资源,此时如果此客户端意外宕机,是否就意味着这些资源永远都不能得到释放呢?租约机制就是为了解决这个问题。 RegionServer 接收到第一次 RPC 之后,除了生成全局唯一的 scanId 之外还会生成一个携带有超时时间的 lease ,超时时间可以通过参数 hbase.regionserver.lease.period 配置,一旦在超时时间内后续 RPC 请求没有到来(比如客户端处理太慢), RegionServer 就认为客户端出现异常,此时会将该 lease 销毁并将整个 scan 所持有的资源全部释放,客户端在处理完成之后再发后续的 RPC 过来,检查到对应的 lease 已经不存在,就会抛出如下 leaseExcption :
写在最后
一旦发生超时异常,很多童鞋的第一反应是会将超时时间设长。可以负责任的说,这样的处理是盲目的,不仅不能从本质上解决问题,还会使得整个系统处于特别不敏感的状态,在某些异常情况下,客户端就会因为超时时间设置太长而一直阻塞,进而导致上层业务长时间卡顿。因此在大多数情况下都不建议将超时时间设大,推荐的方法是找到超时的原因,分析超时原因是否可以避免。
文章最后再说说如何设置超时,用户可以通过修改配置文件 hbase-site.xml 来设置这几个参数,也可以通过代码的方式进行设置,如下所示:
更多技术分享,请关注网易视频云官方网站( http://vcloud.163.com/) 或者网易视频云官方微信( vcloud163 )进行交流与咨询