HBase RowKey 设计的那些事

本文涉及的产品
云原生网关 MSE Higress,422元/月
任务调度 XXL-JOB 版免费试用,400 元额度,开发版规格
注册配置 MSE Nacos/ZooKeeper,118元/月
简介:
   在说rowkey设计之前,先回答一下大家配置HBase时可能有的疑问,关于HBase是否需要单独的ZooKeeper托管?嗯,如果只是部署HBase,我建议不要用单独的ZooKeeper进行托管,用HBase自带的ZooKeeper就可以,假如要部署其他应用,比如Spark等可以单独部署一个ZooKeeper集群。好,废话不多说了,下面说说RowKey设计的事。

先谈HBase底层架构

对于新手来说,RowKey的设计是比较陌生的一件事,看上去很简单的东西,其实非常复杂,RowKey的设计基本上可以划分成两大影响,分别是分析维度、查询性能。为什么要这样分呢?我们再回头看看HBase系统架构图:


d69f445222b73c40a1e5e2d71338c0ad60481613

这种设计看上去并没有什么问题,但是这种设计隐藏了非常多陷阱,假如CompanyCode字段非常固定,而TimeStamp变化比较大的话,会造成单个Region连续地存储这些数据,数据量非常大的时候,这个Region会集中了这些数据,当有应用需要访问这些数据时,造成了RPC timeout,甚至应用程序直接报错,无法执行。

合理的RowKey设计方法

     基于上面的原因,我们需要考虑单点集中以及数据查询两方面的因素,因此,在RowKey上我们要针对这两个问题进行方案设计。

     首先是单点集中问题,我们出现这样单点集中的原因大概有以下几种:

l RowKey前面的字符过于固定

l 集群结点数量过少

集群结点数量是由我们自身硬件资源限制的,这个我们不考虑在内,我们主要考虑RowKey设计。既然是因为前面字符过于集中,那么我们可以通过在RowKey前面添加随机的一个字符串,下面是引自《HBase Essential》里面的一个随机字符计算方法:

int saltNumber = new Long(new Long(timestamp).hashCode()) %<number of region servers>

用这种方法,我们在插入数据的时候可以人为地随机把一断时间内的数据打散,分布到各个RegionServer下的Region中,充分利用分布式的优势,这样做不紧可以加快数据的读写访问,也解决了数据集中的问题。

改良后的RowKey设计方案

     通过上面的技术研讨,可以制定出以下的RowKey设计方案了:

随机字符(2位) + 时间位(14位)+ CompanyCode(4位)

     我在实际测试过程中,前后两种方案对比,前者的MR程序跑了1个小时,后者只花了5分钟。

合理地编写查询代码

     我们完成数据存储之后,假如要取出某部分数值,需要设置Scan查询,以下是我在实战中用到的部分代码,仅供参考:
public class HBaseTableDriver extends Configured implements Tool {

 

    public int run(String[] arg0) throws Exception {

       if(arg0.length < 4 || arg0.length > 5)

           throw new IllegalArgumentException("The input argument need:start && stop && farmid && turbineNum && calid");

       if(arg0[0].length() != 8 || arg0[1].length() != 8)

           throw new IllegalArgumentException("The date format should be yyyyMMdd");

      

       Configuration conf = HBaseConfiguration.create();

       conf.set("hbase.zookeeper.quorum", ConstantValues.QUOREM);

       conf.set("hbase.zookeeper.property.clientPort", ConstantValues.CLIENT_PORT);

      

       //extract table && tagid && start time && end time

       conf.set("start", arg0[0]);

       conf.set("stop", arg0[1]);

        conf.set("farmid", arg0[2]);

       conf.set("turbineNum", arg0[3]);

       conf.set("calid", arg0[4]);

       String startRow = "0" + arg0[0] + " 000000" + arg0[2] + "001";

       String stopRow = "2" + arg0[1] + " 235959" + arg0[2] + RowKeyGenerator.addZero(Integer.parseInt(arg0[3]));

      

       String targetKpiTableName = "kpi2";

      

       Job job = Job.getInstance(conf, "KPIExtractor");

        job.setJarByClass(KPIExtractor.class);

        job.setNumReduceTasks(6);

        Scan scan = new Scan();

        scan.addColumn("f".getBytes(), "v".getBytes());

        String regEx = "^\\d{1}(?:" + arg0[0].substring(0, 4) + "|" + arg0[1].substring(0, 4) + ")\\d{17}";

        switch(arg0[4]){

        case "1":

               regEx = regEx + "(?:823|834)$";

               startRow = startRow + "823";

               stopRow = stopRow + "834";

            break;

        case "2":

            regEx = regEx + "211$";

            startRow = startRow + "211";

           stopRow = stopRow + "211";

            break;

        case "3":

            regEx = regEx + "544$";

            startRow = startRow + "544";

           stopRow = stopRow + "544";

            break;

        case "4":

            regEx = regEx + "208$";

            startRow = startRow + "208";

           stopRow = stopRow + "208";

            break;

        case "5":

            regEx = regEx + "(?:739|823)$";

            startRow = startRow + "739";

           stopRow = stopRow + "823";

            break;

        case "6":

            regEx = regEx + "(?:211|823)$";

            startRow = startRow + "211";

           stopRow = stopRow + "823";

            break;

        case "7":

            regEx = regEx + "708$";

            startRow = startRow + "708";

           stopRow = stopRow + "708";

            break;

        case "8":

            regEx = regEx + "822$";

            startRow = startRow + "822";

           stopRow = stopRow + "822";

            break;

        case "9":

            regEx = regEx + "211$";

            startRow = startRow + "211";

           stopRow = stopRow + "211";

            break;

        default:

            throw new IllegalArgumentException("UnKnown Argument calid:"+arg0[4]+",it should be between 1~9");

        }

        scan.setStartRow(startRow.getBytes());

        scan.setStopRow(stopRow.getBytes());

        scan.setFilter(new RowFilter(CompareOp.EQUAL, new RegexStringComparator(regEx)));

        TableMapReduceUtil.initTableMapperJob("hellowrold", scan , KPIMapper.class, ImmutableBytesWritable.class, ImmutableBytesWritable.class, job);

        TableMapReduceUtil.initTableReducerJob(targetKpiTableName, KPIReducer.class, job);

        job.waitForCompletion(true);

       return 0;

    }

   

}

文章转载自 开源中国社区 [http://www.oschina.net]

相关实践学习
云数据库HBase版使用教程
&nbsp; 相关的阿里云产品:云数据库 HBase 版 面向大数据领域的一站式NoSQL服务,100%兼容开源HBase并深度扩展,支持海量数据下的实时存储、高并发吞吐、轻SQL分析、全文检索、时序时空查询等能力,是风控、推荐、广告、物联网、车联网、Feeds流、数据大屏等场景首选数据库,是为淘宝、支付宝、菜鸟等众多阿里核心业务提供关键支撑的数据库。 了解产品详情:&nbsp;https://cn.aliyun.com/product/hbase &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
SQL 分布式数据库 Apache
Hbase的二级索引和RowKey的设计
Hbase的二级索引和RowKey的设计
352 1
|
分布式数据库 索引 Hbase
《HBase应用与发展之HBase RowKey与索引设计》电子版地址
HBase应用与发展之HBase RowKey与索引设计
138 0
《HBase应用与发展之HBase RowKey与索引设计》电子版地址
|
分布式数据库 Hbase
|
分布式数据库 Hbase
|
存储 缓存 负载均衡
Hbase的Rowkey设计以及如何进行预分区
今天有人问我Hbase的rowkey设计和预分区的问题,这篇文字就简单介绍一下.,关于Hbase的表的一些基本概念这里就不说了,直接说重点,尽可能说的简单一点,废话就不写了. 1.什么是Rowkey? 我们知道Hbase是一个分布式的、面向列的数据库,它和一般关系型数据库的最大区别是:HBase很适合于存储非结构化的数据,还有就是它基于列的而不是基于行的模式.
Hbase的Rowkey设计以及如何进行预分区
|
存储 缓存 负载均衡
大白话彻底搞懂 HBase Rowkey 设计和实现方式
大白话彻底搞懂 HBase Rowkey 设计和实现方式
884 0
大白话彻底搞懂 HBase Rowkey 设计和实现方式
|
存储 分布式数据库 开发者
HBase表设计_8 | 学习笔记
快速学习 HBase表设计_8
168 0
|
存储 分布式数据库 开发者
HBase 表设计_7 | 学习笔记
快速学习 HBase 表设计_7
140 0
|
分布式数据库 开发者 Hbase
HBase 表设计_6 | 学习笔记
快速学习 HBase 表设计_6
136 0
|
存储 大数据 Java
HBase 表设计_5 | 学习笔记
快速学习 HBase 表设计_5
146 0