HBase client 客户端重试机制

背景

在hbase集群故障时,hbase client无法连接region server的时候,因为重试参数配置问题,程序并不会直接抛出异常,而是会一直重试,导致异常报警没有触发。此篇文章讲述client的重试机制及参数配置。

代码解析

RpcRetryingCall.javacallWithRetries函数是Rpc请求重试机制的实现, 可以参考以下源码(hbase版本为1.2.1)

/**
* Retries if invocation fails.
* @param callTimeout Timeout for this call
* @param callable The {@link RetryingCallable} to run.
* @return an object of type T
* @throws IOException if a remote or network exception occurs
* @throws RuntimeException other unspecified error
*/
public T callWithRetries(RetryingCallable<T> callable, int callTimeout)
throws IOException, RuntimeException {
List<RetriesExhaustedException.ThrowableWithExtraContext> exceptions =
  new ArrayList<RetriesExhaustedException.ThrowableWithExtraContext>();
this.globalStartTime = EnvironmentEdgeManager.currentTime();
context.clear();
for (int tries = 0;; tries++) {
  long expectedSleep;
  try {
    callable.prepare(tries != 0); // if called with false, check table status on ZK
    interceptor.intercept(context.prepare(callable, tries));
    return callable.call(getRemainingTime(callTimeout));
  } catch (PreemptiveFastFailException e) {
    throw e;
  } catch (Throwable t) {
    ExceptionUtil.rethrowIfInterrupt(t);
    if (tries > startLogErrorsCnt) {
      LOG.info("Call exception, tries=" + tries + ", retries=" + retries + ", started=" +
          (EnvironmentEdgeManager.currentTime() - this.globalStartTime) + " ms ago, "
          + "cancelled=" + cancelled.get() + ", msg="
          + callable.getExceptionMessageAdditionalDetail());
    }

    // translateException throws exception when should not retry: i.e. when request is bad.
    interceptor.handleFailure(context, t);
    t = translateException(t);
    callable.throwable(t, retries != 1);
    RetriesExhaustedException.ThrowableWithExtraContext qt =
        new RetriesExhaustedException.ThrowableWithExtraContext(t,
            EnvironmentEdgeManager.currentTime(), toString());
    exceptions.add(qt);
    if (tries >= retries - 1) {
      throw new RetriesExhaustedException(tries, exceptions);
    }
    // If the server is dead, we need to wait a little before retrying, to give
    //  a chance to the regions to be
    // tries hasn't been bumped up yet so we use "tries + 1" to get right pause time
    expectedSleep = callable.sleep(pause, tries + 1);

    // If, after the planned sleep, there won't be enough time left, we stop now.
    long duration = singleCallDuration(expectedSleep);
    if (duration > callTimeout) {
      String msg = "callTimeout=" + callTimeout + ", callDuration=" + duration +
          ": " + callable.getExceptionMessageAdditionalDetail();
      throw (SocketTimeoutException)(new SocketTimeoutException(msg).initCause(t));
    }
  } finally {
    interceptor.updateFailureInfo(context);
  }
  try {
    if (expectedSleep > 0) {
      synchronized (cancelled) {
        if (cancelled.get()) return null;
        cancelled.wait(expectedSleep);
      }
    }
    if (cancelled.get()) return null;
  } catch (InterruptedException e) {
    throw new InterruptedIOException("Interrupted after " + tries + " tries  on " + retries);
  }
}
}

HBase客户端请求在那个时间段网络有异常导致rpc请求失败,会进入重试逻辑
根据HBase的重试机制(退避机制),每两次重试机制之间会休眠一段时间,即cancelled.wait(expectedSleep),这个休眠时间太长导致这个线程一直处于TIME_WAITING状态。
休眠时间由expectedSleep = callable.sleep(pause,tries + 1)决定,根据hbase算法,默认最大的expectedSleep为20s,整个重试时间会持续8min,这也就是说全局锁会被持有8min。

重要参数设置

hbase.client.pause

失败重试时等待时间,随着重试次数越多,重试等待时间越长,计算方式如下所示:

public static int RETRY_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);

所以如果重试10次,hbase.client.pause=50ms,则每次重试等待时间为{50,100,150,250,500,1000,2000,5000,5000,5000}。

属性默认值为100ms,可以设置为50ms,甚至更小。

hbase.client.retries.number

失败时重试次数,默认为31次。可以根据自己应用的需求将该值调整的比较小。比如整个提供应用的超时时间为3s,则根据上面重试时间计算方法,可以将重试次数调整为3次。

hbase.rpc.timeout

该参数表示一次RPC请求的超时时间。如果某次RPC时间超过该值,客户端就会主动关闭socket。

默认该值为1min,应用为在线服务时,可以根据应用的超时时间,设置该值.如果应用总共超时为3s,则该值也应该为3s或者更小.

hbase.client.operation.timeout

该参数表示HBase客户端发起一次数据操作直至得到响应之间总的超时时间,数据操作类型包括get、append、increment、delete、put等。该值与hbase.rpc.timeout的区别为,hbase.rpc.timeout为一次rpc调用的超时时间。而hbase.client.operation.timeout为一次操作总的时间(从开始调用到重试n次之后失败的总时间)。

举个例子说明,比如一次Put请求,客户端首先会将请求封装为一个caller对象,该对象发送RPC请求到服务器,假如此时因为服务器端正好发生了严重的Full GC,导致这次RPC时间超时引起SocketTimeoutException,对应的就是hbase.rpc.timeout。那假如caller对象发送RPC请求之后刚好发生网络抖动,进而抛出网络异常,HBase客户端就会进行重试,重试多次之后如果总操作时间超时引起SocketTimeoutException,对应的就是hbase.client.operation.timeout。

hbase.client.scanner.timeout.period

该参数是表示HBase客户端发起一次scan操作的rpc调用至得到响应之间总的超时时间。一次scan操作是指发起一次regionserver rpc调用的操作,hbase会根据scan查询条件的cacheing、batch设置将scan操作会分成多次rpc操作。比如满足scan条件的rowkey数量为10000个,scan查询的cacheing=200,则查询所有的结果需要执行的rpc调用次数为50个。而该值是指50个rpc调用的单个相应时间的最大值。

参数推荐

在网络出现抖动的异常情况下,默认最差情况下一个线程会存在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次,然后放弃连接到集群,进而会再将全局锁交给其他线程,执行其他请求。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: HBase作为一个分布式系统,需要ZooKeeper来进行集群的协调和管理。在HBase中,ZooKeeper Session是指客户端与ZooKeeper服务器之间的逻辑连接,如果客户端与ZooKeeper服务器的Session失效,客户端需要重新连接到ZooKeeper服务器。 HBase的ZooKeeper Session重连机制分为两种情况: 1. 客户端与ZooKeeper服务器的连接断开,但是ZooKeeper服务器仍然存在,这种情况下客户端会尝试重新连接到ZooKeeper服务器,并恢复之前的Session。 2. ZooKeeper服务器不可用,这种情况下客户端会不断地重试连接,直到ZooKeeper服务器可用。当ZooKeeper服务器重新启动并且客户端重新连接成功后,客户端会创建一个新的Session。 ### 回答2: HBase是一个分布式数据库,它使用ZooKeeper来协调和管理其集群中的各个节点。在HBase中,当与ZooKeeper建立连接时,会创建一个会话(session),该会话会定期向ZooKeeper发送心跳以保持连接。 然而,由于各种原因,会话可能会中断,例如网络故障、ZooKeeper集群重新启动或者部分节点宕机等。在这种情况下,HBase会采取重连机制来重新建立与ZooKeeper的连接。 具体而言,HBase的重连机制如下: 1. 首先,HBase会在会话断开之后尝试与ZooKeeper重新建立连接,它会使用预先配置的ZooKeeper集群地址来查找并连接可用的ZooKeeper节点。 2. HBase会等待一段时间,并定期尝试连接ZooKeeper。默认情况下,它会每隔10秒尝试一次,直到连接成功或超过最大尝试次数。 3. 一旦HBase重新建立了与ZooKeeper的连接,它将恢复之前断开的会话。这意味着HBase将能够继续向ZooKeeper发送心跳以保持连接,并且能够接收和处理由ZooKeeper发送的事件通知。 4. 如果HBase尝试连接的次数超过了最大尝试次数,并且仍然无法建立连接,则表示重连失败。这时HBase会进行相应的错误处理,例如记录错误日志、抛出异常或进行其他操作。 综上所述,HBase的重连机制通过周期性地尝试连接ZooKeeper来保证与ZooKeeper的连接稳定性。这确保了HBase能够持续地与ZooKeeper进行通信,从而有效地管理和协调整个HBase集群的操作。 ### 回答3: HBase使用Zookeeper来进行协调和管理分布式集群的配置信息和状态信息。Zookeeper作为一个可靠的分布式协调服务,可以保证数据的一致性和可用性。 在HBase中,当Zookeeper与HBase Master建立连接时会创建一个会话(session),用于维护两者之间的通信。会话通常具有超时时间,一旦超过这个时间,Zookeeper会认为会话已失效并将其关闭。 当HBase Zookeeper会话丢失或超时后,会触发HBase的ZooKeeperWatcher机制进行重连。ZooKeeperWatcher是HBase中一个用于监视Zookeeper状态变化的线程。重连过程包括以下几个步骤: 1. ZooKeeperWatcher会尝试重新建立与Zookeeper的连接。它会检查是否存在已建立的连接,如果存在则会关闭旧连接。 2. 如果与Zookeeper的连接建立成功,则重新初始化HBase集群的状态。这包括重新注册HBase Master和RegionServer节点以及恢复已分配的Region。 3. 如果与Zookeeper的连接建立失败,则会进行重试重试机制通常是指定一定的时间间隔后再次尝试连接,直到连接成功或超过最大重试次数。 需要注意的是,在HBase中,Zookeeper会话的重连过程是透明的,对HBase用户来说是无感知的。用户只需要确保在配置文件中正确指定Zookeeper集群地址,而不需要关心具体的重连机制。 总之,HBase的Zookeeper会话重连机制确保了与Zookeeper的连接的可靠性和一致性,使得HBase集群在网络异常或Zookeeper故障的情况下能够自动恢复正常的运行状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值