一、HBase的RowKey设计原则


  1.我们知道HBase是三维有序存储的,通过RowKey(行键),ColumnKey(Column family和qualifier)和TimeStamp(时间戳),这三个维度,对HBase中的数据进行快速的定位,Hbase中的RowKey可以唯一的标识一行记录,在HBase查询的时候,有以下的几种方式:

  1)通过get的方式,指定rowkey获取唯一一条记录。

  2)通过scan的方式,设置startRow和stopRow参数的方式进行范围的匹配

  3)全表扫描,直接扫描整张中的数据。

  2.热点问题

  hbase中的行是按照rowkey的字典顺序进行排序的,这种设计优化了scan操作,可以将相关的行以及会被一起读取的行存在临近位置,便于scan。而糟糕的设计是热点的源头,热点发生在大量的client直接访问节点上一个或者极少数个节点上(访问可能是读、写或者是其他的操作),即是大量的数据都流向了集群的一个或者几个节点的上面,大量的访问会使得单个的机器超出自身的承受能力,引起性能的下降甚至性能的不可用,这也会影响同一个regionServer上的其他region ,由于主机无法服务其他主机的请求,没有达到数据的均衡分散。设计良好的数据访问模式,以使集群被充分,均衡的调用。

  3.避免热点的方法有以下几种:

    1)加盐。具体的操作就是在rowKey前面添加随机数,具体就是给rowKey分配一个随机前缀,以使得其和之前的rowkey的开头不相同,分配的前缀的种类数量和你想使用数据分散到不同region的数量一致,加盐之后的rowKey就会根据随机生成的前缀分散到各个region上,以避免热点。

    2)hash。哈希会使得同一行永远使用一个前缀加盐,哈希也可以使得负载分散到整个的集群,但是读却是可以预测的。使用确定的hash可以让客户端重构完整的rowKey,可以使用get操作准确的获取某一行数据

    3)反转。第三种放置热点的方法是反转固定长度或者数字格式的rowKey,这样可以使得rowKey中经常改变的部分放到前面,这样可以有效的随机rowKey,但是牺牲了rowKey的有序性。反转rowKey的例子以手机号为RowKey,可以将手机号反转后的字符串作为rowKey,这样可以避免以手机号那样的比较固定的开头导致热点问题。    

    4)时间戳反转。一个常见的数据处理问题是快速的获取数据最近的版本,使用反转的时间戳为rowkey的一部分对这个问题十分有用,可以用 Long.Max_Value - timestamp 追加到 key 的末尾,例如 [key][reverse_timestamp] , [key] 的最新值可以通过 scan[key]获得[key]的第一条记录,因为 HBase 中 rowkey 是有序的,第一条记录是最后录入的数据。列族尽可能越短越好,最好是一个字符, 冗长的属性名虽然可读性好,但是更短的属性名存储在 HBase 中会更好 。

  4.RowKey的设计原则

    1.rowkey的长度设计原则:rowkey是一个二进制码流,可以是任意字符串,最大长度是64kb,在实际应用中一般为10到100bytes,以字节数组byte[]的形式保留,一般设计成定长,建议越短越好,一般不超过16个字节。

    2.rowkey的散列原则,如果rowkey按照时间戳的方式递增,不要将时间放在二进制吗的前面,建议将rowKey的高位采用散列字段来进行处理,由程序随机生成,低位放时间字段,这样讲提高数据均衡分布在每个RegionServer中,以实现负载均衡的可能性。如果不进行散列字段处理,首字段直接使用时间信息,所有的数据都会集中分布在一个regionServer上,这样在进行检索的时候,负载会集中在个别的RegionServer上,造成热点问题,降低查询效率。

    3.rowkey的唯一性原则。必须在设计上保证其唯一性,rowkey是按照字典顺序排序存储的,因此在设计rowKey的时候要充分利用排序这个特点,将经常读取的数据存储在一块,将最近可能访问的数据存储到一块。

    4.盐析。在rowkey的前面增加随机数,具体就是给rowkey分配一个随机前缀,以使他和之前的rowkey的前缀不同,分配的前缀的种类数量应该和你想使用的数据分散到不同region的数量是一致的,加盐之后的rowkey会根据随机生成的前缀分散到各个region上。以避免热点。

  4.电信公司实例。

  电信公司rowKey设计实例:

    0.区域划分:划分100个区域,从00到99

      CallerId +  201703 :hashcode % 100  = 00 -99

    1.rowKey设计:rno  +  callerid  +  calltime[201702011212]  +  calleeid  +  duration ,这个地方注意:rno 等于callerid + calltime 的一部分

    2.通话记录:

      1)创建表:$hbase>create 'ns1:calllogs','f1'

      2)创建单元测试。向表中添加数据。

package com.it18zhang.hbaseDemo;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Test; import java.io.IOException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date; /**
* 通话日志
* rowKey的设计
* 区号:主叫或被叫,时间,方向0-主叫,1-被叫
*xx,callerid ,time,direction ,calleid,duration
*
*/
public class TestCalllogs {
@Test
public void put() throws Exception {
Configuration conf = HBaseConfiguration.create();
Connection conn = ConnectionFactory.createConnection(conf);
TableName tname = TableName.valueOf("ns1:calllogs");
Table table = conn.getTable(tname);
String callerId ="";
String calleeId ="";
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.applyPattern("yyyymmddhhmmss");
String callTime = sdf.format(new Date());
int duration = ;
DecimalFormat df= new DecimalFormat("");
String dura = df.format(duration);
//区域00-99
int hash =(callerId+ callTime.substring(,)).hashCode() %;
hash = (hash & Integer.MAX_VALUE)%;
//hash区域号
DecimalFormat dff = new DecimalFormat();
dff.applyPattern("");
String regNo = dff.format(hash);
//拼接rowkey
String rowKey = regNo+","+","+callerId+","+callTime+","+""+calleeId+","+dura;
byte[] rowid = Bytes.toBytes("row3");
Put put = new Put(rowid);
put.addColumn(Bytes.toBytes("f1"),Bytes.toBytes("callerPos"),Bytes.toBytes("河北"));
put.addColumn(Bytes.toBytes("f1"),Bytes.toBytes("callerPos"),Bytes.toBytes("河南"));
table.put(put);
}
}

    3)创建协处理器。

  

public class CalleeLogRegionObserver extends BaseRegionObserver{

            public void postPut(ObserverContext<RegionCoprocessorEnvironment> e, Put put, WALEdit edit, Durability durability) throws IOException {
super.postPut(e, put, edit, durability);
//
TableName callLogs = TableName.valueOf("calllogs");
//得到当前的TableName对象
TableName tableName = e.getEnvironment().getRegion().getRegionInfo().getTable();
if(!callLogs.equals(tableName)){
return ;
} //得到主叫的rowkey
//xx , callerid , time , direction, calleid ,duration
//被叫:calleid,time, String rowkey = Bytes.toString(put.getRow());
String[] arr = rowkey.split(","); String hash = Util.getRegNo(arr[],arr[]);
//hash String newRowKey = hash + "," + arr[] + "," + arr[] + ",1," + arr[] + "," + arr[] ;
Put newPut = new Put(Bytes.toBytes(newRowKey)); Table t = e.getEnvironment().getTable(tableName); t.put(newPut);
}
}
  4.配置hbase-site.xml并分发

    <property>
      <name>hbase.coprocessor.region.classes</name>
      <value>it18zhang.hbaseDemo.coprocessor1.CalleeLogRegionObserver</value>

    </property>

      

HBASE学习笔记(五)的更多相关文章

  1. C#可扩展编程之MEF学习笔记(五):MEF高级进阶

    好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用 ...

  2. (转)Qt Model/View 学习笔记 (五)——View 类

    Qt Model/View 学习笔记 (五) View 类 概念 在model/view架构中,view从model中获得数据项然后显示给用户.数据显示的方式不必与model提供的表示方式相同,可以与 ...

  3. java之jvm学习笔记五(实践写自己的类装载器)

    java之jvm学习笔记五(实践写自己的类装载器) 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和第四节我们一直在强调一句话,类 ...

  4. Learning ROS for Robotics Programming Second Edition学习笔记(五) indigo computer vision

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

  5. Typescript 学习笔记五:类

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

  6. ES6学习笔记<五> Module的操作——import、export、as

    import export 这两个家伙对应的就是es6自己的 module功能. 我们之前写的Javascript一直都没有模块化的体系,无法将一个庞大的js工程拆分成一个个功能相对独立但相互依赖的小 ...

  7. muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor

    目录 muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor Connector 系统函数connect 处理非阻塞connect的步骤: Connetor时序图 Accep ...

  8. python3.4学习笔记(五) IDLE显示行号问题,插件安装和其他开发工具介绍

    python3.4学习笔记(五) IDLE显示行号问题,插件安装和其他开发工具介绍 IDLE默认不能显示行号,使用ALT+G 跳到对应行号,在右下角有显示光标所在行.列.pycharm免费社区版.Su ...

  9. Go语言学习笔记五: 条件语句

    Go语言学习笔记五: 条件语句 if语句 if 布尔表达式 { /* 在布尔表达式为 true 时执行 */ } 竟然没有括号,和python很像.但是有大括号,与python又不一样. 例子: pa ...

随机推荐

  1. 【JDBC】使用Spring提供的JDBCTemplate通过Statement向MySql数据库插入千万条数据,耗时4m55s,使用insert语句批量插入方式二

    这回依然是使用 insert批量插入这种方式 insert into emp(name,age,cdate) values ('A' , 20, '2019-10-13 00:00:00'), ('B ...

  2. Android ROM适配

    Android是开源的,不同的手机厂商都有自己定制的系统,所以这就给开发者带来了ROM适配难题.在一些群里面经常看到有人因为手机适配问题,说这个手机坑,那个手机坑,其实那是没有对ROM定制系统的一些变 ...

  3. C# WinForm设置窗口大小不可调,取消最大、最小化按键

    this.FormBorderStyle = FormBorderStyle.FixedDialog;//设置边框为不可调节 this.MaximizeBox = false;//取消最大化按键 th ...

  4. 几句java代码搞定十万个为什么数据

    最近想做一个app,为小朋友推荐十万个为什么的故事,但是找了很久数据,发现挺难的找的,又去写爬虫,发现没有一个好的网站可以爬,最后一个偶然的机会在csdn上发现一个可用的接口,很快就把问题解决了,下面 ...

  5. set_multicycle_path语法说明【转载】

    (转载) (其实多看手册就知道原因了) Q:多周期路径中的检查保持时间时刻,为什么默认是在建立时间检查的前一个cycle?请大家谈谈自己的理解. 如:Set_multicycle_path -setu ...

  6. k8s集群部署(3)

    一.利用ansible部署kubernetes集群环境准备 基于二进制方式部署和利用ansible-playbook实现自动化:既提供一键安装脚本,也可以分步执行安装各个组件,同时讲解每一步主要参数配 ...

  7. TCP/IP 和 和 DoD 模型

    TCP/IP 模型也被称作 DoD 模型(Department of Defense Model).TCP/IP 字面上代表了两个协议:TCP(传输控制协议)和 IP(网络之间互联协议).TCP/IP ...

  8. Python-sympy科学计算与数据处理(求极限及其它功能)

    极限 其它功能

  9. 深入解读TCP/IP

    虽然大家现在对互联网很熟悉,但是计算机网络的出现比互联网要早很多. 计算机为了联网,就必须规定通信协议,早期的计算机网络,都是由各厂商自己规定一套协议,IBM.Apple和Microsoft都有各自的 ...

  10. RAID冗余磁盘阵列的创建

    RAID 0 :条带化,数据被拆分到多个驱动中,写速度最快,但并没有数据镜像或校验信息. RAID 1 :镜像化,完全磁盘镜像,在独立磁盘上创建数据的两份拷贝,这个级别提供最好的数据安全,但写速度慢. ...