1.设置的目的

由于作为在线服务,需要能够保证在快速失败、失败容错重试等特性。快速失败能保证系统的低延时,能防止因为等待某个资源,造成服务资源暂用,最后导致服务不可用。失败容错能够提供服务的稳定性,进行服务失败是重试。因此HBase客户端提供的重试机制,并通过配置合理的参数使得客户端在保证一定容错性的同时还能够保证系统的低延迟特性。

2.hbase客户端重要参数

  • 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调用的单个相应时间的最大值。

3.hbase客户端使用示例

/**
 * hbase client 单例连接
 * @author chun
 *
 */
public class HbaseClient {
    private static final Logger LOGGER = LoggerFactory.getLogger(HbaseClient.class);
    private Configuration conf = null;
    private Connection conn = null;
    private static HbaseClient instance = null;

    private HbaseClient(){
        init();
    }
    public void init(){
        try{
            conf =  HBaseConfiguration.create();  
            conf.set("hbase.zookeeper.quorum", "127.0.0.1");  
            conf.set("zookeeper.znode.parent", "/hbase");
            conf.set("hbase.zookeeper.property.clientPort", "2181"); 
            conf.set("hbase.client.pause", "50"); 
            conf.set("hbase.client.retries.number", "3"); 
            conf.set("hbase.rpc.timeout", "2000"); 
            conf.set("hbase.client.operation.timeout", "3000"); 
            conf.set("hbase.client.scanner.timeout.period", "10000"); 

            conn = ConnectionFactory.createConnection(conf);
        }catch(Exception e){
            LOGGER.error("初始化hbase连接失败"+e.getMessage(),e);
        }
    }

    public static HbaseClient getInstance(){
        if(instance == null){
            synchronized (HbaseClient.class) {
                if(instance == null){
                    instance = new HbaseClient();
                }
            }
        }
        return instance;
    }

    /**
     * 获取htable操作类
     * @param tableName
     * @return
     * @throws IOException
     */
    public Table getHtable(String tableName) throws IOException{
        return conn.getTable(TableName.valueOf(tableName));
    }

    /**
     * 
     * @param hTableInterface
     */
    public void relaseHtable(Table table){
        if(table == null){
            return;
        }
        try {
            table.close();
        } catch (IOException e) {
            LOGGER.error(e.getMessage(),e);
        }
    }

    /**
     * 关闭hbase连接
     */
    public void destory(){
        try {
            conn.close();
            instance = null;
        } catch (IOException e) {
            LOGGER.error(e.getMessage(),e);
        }
    }

}

参考文章为
HBase最佳实践 – 客户端重试机制
HBase最佳实践-客户端超时机制