分享

Hbase初步入门-- 表该如何构造和设计

pig2 2014-5-23 21:34:41 发表于 入门帮助 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 10 78091

问题导读:
1.hbase入门,我们该如何构造和设计
2.hbase创建表会自动创建几个region分区?
3.Column Family该如何设计?
4.该如何设置数据的有几个版本?
5.hbase在什么请款不过下进行Compact与Split操作?
6.HBase中row key用来检索表中的记录,有几种方式?





1.1 Pre-Creating Regions

默认情况下,在创建HBase表的时候会自动创建一个region分区,当导入数据的时候,所有的HBase客户端都向这一个region写数据,直到这个region足够大了才进行切分。一种可以加快批量写入速度的方法是通过预先创建一些空的regions,这样当数据写入HBase时,会按照region分区情况,在集群内做数据的负载均衡。

有关预分区,详情参见:Table Creation: Pre-Creating Regions ,下面是一个例子:

  1. public static boolean createTable(HBaseAdmin admin, HTableDescriptor table, byte[][] splits) throws IOException { try {
  2.     admin.createTable(table, splits); return true;
  3.   } catch (TableExistsException e) {
  4.     logger.info("table " + table.getNameAsString() + " already exists"); // the table already exists...  return false;  
  5.   }
  6. } public static byte[][] getHexSplits(String startKey, String endKey, int numRegions) { byte[][] splits = new byte[numRegions-1][];
  7.   BigInteger lowestKey = new BigInteger(startKey, 16);
  8.   BigInteger highestKey = new BigInteger(endKey, 16);
  9.   BigInteger range = highestKey.subtract(lowestKey);
  10.   BigInteger regionIncrement = range.divide(BigInteger.valueOf(numRegions));
  11.   lowestKey = lowestKey.add(regionIncrement); for(int i=0; i < numRegions-1;i++) {
  12.     BigInteger key = lowestKey.add(regionIncrement.multiply(BigInteger.valueOf(i))); byte[] b = String.format("%016x", key).getBytes();
  13.     splits[i] = b;
  14.   } return splits;
  15. }
复制代码
1.2 Row Key
HBase中row key用来检索表中的记录,支持以下三种方式:
  • 通过单个row key访问:即按照某个row key键值进行get操作;
  • 通过row key的range进行scan:即通过设置startRowKey和endRowKey,在这个范围内进行扫描;
  • 全表扫描:即直接扫描整张表中所有行记录。
在HBase中,row key可以是任意字符串,最大长度64KB,实际应用中一般为10~100bytes,存为byte[]字节数组,一般设计成定长的。
row key是按照字典序存储,因此,设计row key时,要充分利用这个排序特点,将经常一起读取的数据存储到一块,将最近可能会被访问的数据放在一块。
举个例子:如果最近写入HBase表中的数据是最可能被访问的,可以考虑将时间戳作为row key的一部分,由于是字典序排序,所以可以使用Long.MAX_VALUE - timestamp作为row key,这样能保证新写入的数据在读取时可以被快速命中。
1.3 Column Family
不要在一张表里定义太多的column family。目前Hbase并不能很好的处理超过2~3个column family的表。因为某个column family在flush的时候,它邻近的column family也会因关联效应被触发flush,最终导致系统产生更多的I/O。感兴趣的同学可以对自己的HBase集群进行实际测试,从得到的测试结果数据验证一下。
1.4 In Memory
创建表的时候,可以通过HColumnDescriptor.setInMemory(true)将表放到RegionServer的缓存中,保证在读取的时候被cache命中。
1.5 Max Version
创建表的时候,可以通过HColumnDescriptor.setMaxVersions(int maxVersions)设置表中数据的最大版本,如果只需要保存最新版本的数据,那么可以设置setMaxVersions(1)。
1.6 Time To Live
创建表的时候,可以通过HColumnDescriptor.setTimeToLive(int timeToLive)设置表中数据的存储生命期,过期数据将自动被删除,例如如果只需要存储最近两天的数据,那么可以设置setTimeToLive(2 * 24 * 60 * 60)。
1.7 Compact & Split
在HBase中,数据在更新时首先写入WAL 日志(HLog)和内存(MemStore)中,MemStore中的数据是排序的,当MemStore累计到一定阈值时,就会创建一个新的MemStore,并且将老的MemStore添加到flush队列,由单独的线程flush到磁盘上,成为一个StoreFile。于此同时, 系统会在zookeeper中记录一个redo point,表示这个时刻之前的变更已经持久化了(minor compact)。
StoreFile是只读的,一旦创建后就不可以再修改。因此Hbase的更新其实是不断追加的操作。当一个Store中的StoreFile达到一定的阈值后,就会进行一次合并(major compact),将对同一个key的修改合并到一起,形成一个大的StoreFile,当StoreFile的大小达到一定阈值后,又会对 StoreFile进行分割(split),等分为两个StoreFile。
由于对表的更新是不断追加的,处理读请求时,需要访问Store中全部的StoreFile和MemStore,将它们按照row key进行合并,由于StoreFile和MemStore都是经过排序的,并且StoreFile带有内存中索引,通常合并过程还是比较快的。
实际应用中,可以考虑必要时手动进行major compact,将同一个row key的修改进行合并形成一个大的StoreFile。同时,可以将StoreFile设置大些,减少split的发生。










已有(10)人评论

跳转到指定楼层
hadoop小象 发表于 2014-5-28 11:00:23
rowkey如果是有序的话,会将数据存储到一个server中,那么其他server就会闲下来,那这不是hadoop很忌讳的吗
回复

使用道具 举报

sstutu 发表于 2014-5-29 11:02:17
hadoop小象 发表于 2014-5-28 11:00
rowkey如果是有序的话,会将数据存储到一个server中,那么其他server就会闲下来,那这不是hadoop很忌讳的吗

数据可以是有序的,但是你可以打乱他们的排布。
回复

使用道具 举报

hadoop小象 发表于 2014-5-29 13:18:32
sstutu 发表于 2014-5-29 11:02
数据可以是有序的,但是你可以打乱他们的排布。

哦,如何打乱他们的排布
回复

使用道具 举报

wpf0909 发表于 2014-5-29 13:48:47
学习新的东东,很不容易哦
回复

使用道具 举报

sstutu 发表于 2014-5-29 23:22:22
hadoop小象 发表于 2014-5-29 13:18
哦,如何打乱他们的排布
你说的rowkey,跟我说的不太一样。打乱的方式有很多中。

对时间序的key,导致集中单调的ke,都操作一个region的问题:
1.可以增加prefixkey,如rowkey前加上(time%<number of Server>)时间对机子数取模的值,0myrowkey,1myrowkey。
2.将时间生成随机数MD5(time)


回复

使用道具 举报

sstutu 发表于 2014-5-29 23:23:34
下面的内容,你可以参考:


HBase模式设计之ID顺序增长(rowkey顺序增长)

   在设计RowKey的时候,常常有应用的RowKey必须包含ID部分,这样才可以支持查询访问。但ID自增长,会导致写入数据的时候压力集中在某一个或少数几个Region上,这是HBase设计的大忌。

   经过多个应用的实践,我创造了ID的二进制反转的方式来避免。

   简单说明: 比如ID是Byte型(一般为int或者long,此处为方便解释),RowKey=ID+timestamp,1,2,3,4……这样增长,对应二进制为0000 0001,0000 0010,0000 0011,0000 0100……,因为前面的bit是不会变化的,所以以ID为RowKey(或者ID打头)的数据写入的时候会集中在一个region上,然后又集中在下一个region上。为此将变化的部分放到RowKey的前面,来分散写入的压力。前面的增长在RowKey的ID上就变成1000 0000, 0100 0000, 1100 0000,0010 0000……我们预分区,假如需要16-1个分区,就可以分为[,0x01),[0x01,0x02),[0x02,0x03)……[0xFE,0xFF), [0xFF,),注意算一下,这样,1,2,3,4……就会写到不同的区间上,从而分散到不同的region了。(提醒:为什么只拿ID说事,不考虑timestamp呢,因为HBase的RowKey时字节码比较的,先从高位开始,高位分出胜负,后面就不care了~)

优点:转顺序为分散,均衡集群压力;可以做到预分区;不用hash,不用考虑ID的hash碰撞,从而节约存储空间;
限制:scan只能在同一ID打头的rowkey内进行,连续ID的scan不能直接支持,需要程序逻辑处理。

回复

使用道具 举报

小小布衣 发表于 2014-7-18 18:42:39
sstutu 发表于 2014-5-29 23:23
下面的内容,你可以参考:

我发现这里讲的太好了,对于没有实践的我来说,学的是思想
回复

使用道具 举报

tang 发表于 2015-6-10 21:17:25
回复

使用道具 举报

孤独的战神 发表于 2015-11-18 15:31:06
新手努力学习中
回复

使用道具 举报

12下一页
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条