在运维HBase的这段时间里,发现业务用户一方面比较关注HBase本身服务的读写性能:吞吐量以及读写延迟,另一方面也会比较关注HBase客户端使用上的问题,主要集中在两个方面:是否提供了重试机制来保证系统操作的容错性?是否有必要的超时机制保证系统能够fastfail,保证系统的低延迟特性?

这个系列我们集中介绍HBase客户端使用上的这两大问题,本文通过分析之前一个真实的案例来介绍HBase客户端提供的重试机制,并通过配置合理的参数使得客户端在保证一定容错性的同时还能够保证系统的低延迟特性。

案发现场

最近某业务在使用HBase客户端读取数据时出现了大量线程block的情况,业务方保留了当时的线程堆栈信息,如下图所示:

看到这样的问题,首先从日志和监控排查了业务表和region server,确认了在很长时间内确实没有请求进来,除此之外并没有其他有用的信息,同时也没有接到该集群上其他用户的异常反馈,从现象看,这次异常是在特定环境下才会触发的。

案件分析过程

1.根据上图图1所示,所有的请求都block在<0x0000000782a936f0>这把全局锁上,这里需要关注两个问题:

  • 哪个线程持有了这把全局锁<0x0000000782a936f0>?
  • 这是一把什么样的全局锁(对于问题本身并不重要,有兴趣可以参考步骤3)?

2.哪个线程持有了这把锁?

2.1 很容易在jstack日志中通过搜索找到全局锁<0x0000000782a936f0>被如下线程持有:

定睛一看,该线程持有了这把全局锁,而且处于TIMED_WAITING状态,因此这把锁可能长时间不释放,导致所有需要这把全局锁的线程都阻塞等待。好了,那问题就转化成了:为什么这个线程会处于TIME_WAITING状态?

2.2 根据上图提示,查看源码中RpcRetryingCall.java的115行代码,可以确定该线程处于TIME_WAITING状态是因为自己休眠导致,如下图所示:

RpcRetryingCall函数是Rpc请求重试机制的实现,所以可以有两点推断:

  • HBase客户端请求在那个时间段网络有异常导致rpc请求失败,进入重试逻辑
  • 根据HBase的重试机制(退避机制),每两次重试机制之间会休眠一段时间,即上图115行代码,这个休眠时间太长导致这个线程一直处于TIME_WAITING状态。

休眠时间由上图中expectedSleep = callable.sleep(pause,tries+ 1)决定,根据hbase算法(见第三部分),默认最大的expectedSleep为20s,整个重试时间会持续8min,这也就是说全局锁会被持有8min,可这并不能解释持续将近几个小时的阻塞无请求。除非有两种情况:

  • 配置有问题:需要客户端检查hbase.client.pause和hbase.client.retries.number两个参数配置出现异常,比如hbase.client.pause参数如果手抖配成了10000,就有可能出现几个小时阻塞的情况
  • 网络持续有问题:如果线程1持有全局锁重试失败之后退出,线程2竞争到这把锁,此时网络依然有问题,线程2会再次进入重试,重试8min之后失败退出,循环下去,也有可能出现几个小时阻塞的情况

和业务方确认配置,所有参数基本属于默认配置,因此猜测一不成立,那最有可能的情况就是猜测二。经过确认,在事发当时(凌晨0点~早上6点)确实存在很多服务因为云网络升级异常发生抖动的情况出现。然而因为没有具体的日志信息,所以并不能完全确认猜测是否正确。但是,通过问题的分析可以进一步明白HBase重试机制以及部分客户端参数优化策略,这也是写这篇文章的初衷之一。

3. 再来看看这把全局锁到底是什么锁,查看源码可知这把锁是下图中红框中的regionLockObject对象:

参考源码注释可知,这把锁是为了防止同时多线程并发加载meta分区。全局锁代码块首先会从缓存中查找meta分区,如果不存在会执行prefetchRegionCache方法远程查找并写入缓存,因此如果第一个线程成功加载meta分区数据并写入缓存,后来线程可以直接使用。

正常情况下,prefetchRegionCache方法只有在缓存不存在的情况下会执行,如果此时网络不存在问题,远程查找meta分区信息会很快完成,持锁时间也会很短。一旦网络出现长时间抖动,就有可能出现这把锁一直被持有,阻塞其他线程。

HBase Rpc重试机制

通过上文分析可知,HBase的重试机制是这次异常发生的关键点,有必要对其进行一次解析。HBase执行rpc失败之后会执行重试操作,

重试的最大次数可以通过配置文件配置,对应的参数为hbase.client.retries.number,0.98版本中该参数的默认值为31。

同时每两次重试之间会sleep一段时间,即上文提到的expectedSleep变量,该变量实现具体算法如下:

public static intRETRY_BACKOFF[] = { 1, 2, 3, 5, 10, 20, 40, 100, 100, 100, 100, 200, 200 };

long normalPause =pause * HConstants.RETRY_BACKOFF[ntries];

long jitter =  (long)(normalPause * RANDOM.nextFloat() *0.01f); // 1% possible jitter

return normalPause +jitter;

其中RETRY_BACKOFF是一个重试系数表,由小到大递增表示重试时间会随着重试次数逐渐递增。pause变量可以通过配置文件配置,对应的参数为hbase.client.pause,0.98版本中该参数的默认值为100。

暂时忽略jitter这个小随机变量,默认情况下最大的重试间隔休眠时间 expectedSleep = 100 * 200 = 20s。默认重试次数为31,则每次连接集群重试之间的暂停时间将依次为:

[100,200,300,500,1000,2000,4000,10000,10000,10000,10000,20000,20000,…,20000]

这意味着客户端将在448s内重试30次,然后放弃连接到集群.

客户端参数优化实践

很显然,根据上面第二部分和第三部分的介绍,一旦在网络出现抖动的异常情况下,默认最差情况下一个线程会存在8min左右的重试时间,从而会导致其他线程都阻塞在regionLockObject这把全局锁上。为了构建一个更稳定、低延迟的HBase系统,除过需要对服务器端参数做各种调整外,客户端参数也需要做相应的调整:

1.hbase.client.pause:默认为100,可以减少为50

2.hbase.client.retries.number:默认为31,可以减少为21

修改后,通过上面算法可以计算出每次连接集群重试之间的暂停时间将依次为:

[50,100,150,250,500,1000,2000,5000,5000,5000,5000,10000,10000,…,10000]

客户端将会在2min内重试20次,然后放弃连接到集群,进而会再将全局锁交给其他线程,执行其他请求。

HBase之重试机制相关推荐

  1. loadingcache 有重试机制吗_重试机制的实现

    服务在请求资源,如果遇到网络异常等情况,导致请求失败,这时需要有个重试机制来继续请求. 常见的做法是重试3次,并随机 sleep 几秒. 业务开发的脚手架,HTTP Client 基本会封装好 ret ...

  2. springboot 整合retry(重试机制)

    当我们调用一个接口可能由于网络等原因造成第一次失败,再去尝试就成功了,这就是重试机制,spring支持重试机制,并且在Spring Cloud中可以与Hystaix结合使用,可以避免访问到已经不正常的 ...

  3. Spring Cloud Gateway重试机制

    前言 重试,我相信大家并不陌生.在我们调用Http接口的时候,总会因为某种原因调用失败,这个时候我们可以通过重试的方式,来重新请求接口. 生活中这样的事例很多,比如打电话,对方正在通话中啊,信号不好啊 ...

  4. 一文读懂熔断器和重试机制

    导语:随着微服务的流行,熔断作为其中一项很重要的技术也广为人知.当微服务的运行质量低于某个临界值时,启动熔断机制,暂停微服务调用一段时间,以保障后端的微服务不会因为持续过负荷而宕机.本文作者介绍了熔断 ...

  5. invalid signature 错误原因验签失败_Nginx 失败重试机制

    可直接点击上方蓝字 (网易游戏运维平台) 关注我们,获一手游戏运维方案 src 网易游戏 SRE,喜欢钻研与分享. 背景 Nginx 作为目前应用较广的反向代理服务,原生提供了一套失败重试机制,来保证 ...

  6. HttpClientFactory 结合 Polly 轻松实现重试机制

    HttpClientFactory 结合 Polly 轻松实现重试机制 Intro 我们的服务里有一个 API 会去调用第三方的接口,设置了超时时间,最近偶尔会发生超时的情况,微软在提供 HttpCl ...

  7. android网络重试机制,okhttp源码解析(四):重试机制

    前言 这一篇我们分析okhttp的重试机制,一般如果网络请求失败,我们会考虑连续请求多次,增大网络请求成功的概率,那么okhttp是怎么实现这个功能的呢? 正文 首先还是回到之前的Intercepto ...

  8. Spring Retry 重试机制实现及原理

    概要 Spring实现了一套重试机制,功能简单实用.Spring Retry是从Spring Batch独立出来的一个功能,已经广泛应用于Spring Batch,Spring Integration ...

  9. Spring Cloud Zuul重试机制探秘

    简介 本文章对应spring cloud的版本为(Dalston.SR4),具体内容如下: 开启Zuul功能 通过源码了解Zuul的一次转发 怎么开启zuul的重试机制 Edgware.RC1版本的优 ...

最新文章

  1. 触摸屏与计算机通讯视频在线,MCGS触摸屏与电脑调试软件modbus通讯
  2. Backbone集合
  3. SpringCloud-Eureka-服务注册是如何发起的
  4. linux svn 命令
  5. mysql avg 报错_MySQL报错汇总
  6. 基于公开数据的特殊人群在线活动特征挖掘
  7. 微软遭遇XP SP3疯狂重启尴尬境地
  8. hexdump命令常用选项-C -v
  9. 适用于游戏开发领域的语言
  10. 用python在大麦网抢票攻略_大麦网抢票有什么攻略?
  11. 微信授权登录功能实现
  12. 解决浏览器被劫持的一些方法
  13. 【vue】Element Calendar 组件显示农历及节日
  14. 小米Note4、小米8、一加6刷机(三方rec+rom+root)
  15. <学习笔记>从零开始自学Python-之-常用库篇(十一)正则表达式re库
  16. fiddler 升级后抓取https流量各种失败后一定不要忘记这一招
  17. VisionMobile:M2M生态系统的秘方(5):四、创建M2M平台
  18. 【面试】—常见面试问题,面试技巧和注意事项
  19. 南京林业大学与华为正式签署战略合作协议
  20. 阿里巴巴分拆中国万网赴美上市

热门文章

  1. qcustomplot删除一条曲线_被“谭卓”旗袍造型给惊艳,波波头搭配一条酒红色旗袍,华丽高贵...
  2. 对于早期Servlet内核你清楚吗,这些基础的东西,不能忘哦
  3. 华为全面屏鸿蒙,华为5G概念新机:真全面屏+鸿蒙OS 这才是旗舰手机
  4. html1怎样插入视频,HTML视频教程,第1章 HTML初识
  5. asp.net如何解决传递中文参数乱码问题
  6. 作用 react_react-styleguidist核心知识点详解
  7. Java 并发编程之同步工具类 Exchanger
  8. Python写入文件的工具类
  9. Python Pandas导出Hbase数据到dataframe
  10. 华为大数据战略_任正非:华为应抓住“大数据”机遇 抢占战略制高点