HBase相关概念
1.Row Key
基本原则是:(1).由于读取数据只能依靠RowKey,所以应把经常使用到的字段作为行键{如手机号+时间戳拼接的字符串} (2).RowKey长度越短越好,最好不要超过16个字节。
从表的形式看,主要有列少行多的高表和行多列少的宽表,一般情况高表更有优势,因为HBase只能按行拆分。
防止数据过热:当行健为时间戳时,写入数据集中在其中一个Region很容易产生单点过热。
解决办法:(1)添加hash前缀. (2)字段交换或提升权重:即在行键中添加另外一个字段或交换行建中多个字段的位置. (3)随机化,比如对整个行健取MD5,作为新的行健。
以上方法顺序度的性能由高到低,而写入的速度由低到高。
行健决定数据的读取维度或模式,数据行RowKey有序。但如果需要额外的读取顺序,则可以给表添加格外的列族,用于存储其他读取顺序的索引。比如:对于收件箱应用,行健为userID,data列族存消息数据(列名为messageID,值为消息内容),而idx列族存索引(列为标示+消息主题,值为附加信息)。这样就可以在读取索引列族时,得到按主题有序的数据。
2.Column Family
在一张表里不要定义太多的column family。目前Hbase并不能很好的处理超过2~3个column family的表。因为某个column family在flush的时候,它邻近的column family也会因关联效应被触发flush,最终导致系统产生更多的I/O。
3.In Memory
创建表的时候,可以通过HColumnDescriptor.setInMemory(true)将表放到RegionServer的缓存中,保证在读取的时候被cache命中。
4.Max Version
创建表的时候,可以通过HColumnDescriptor.setMaxVersions(intmaxVersions)设置表中数据的最大版本,如果只需要保存最新版本的数据,那么可以设置setMaxVersions(1)。
5.Time to Live(设置数据存储的生命周期)
创建表的时候,可以通过HColumnDescriptor.setTimeToLive(inttimeToLive)设置表中数据的存储生命期,过期数据将自动被删除,例如如果只需要存储最近两天的数据,那么可以设置setTimeToLive(2 * 24 * 60 * 60)。
6.Compact & Split
HBase的Compact分为两类:一类叫Minor Compact(部分文件合并), 一类叫Major Compact(全部文件合并).
两者区别在于:Minor Compact是在Store内StoreFile数量达到阈值(hbase.hstore.blockingStoreFiles, 默认是7)时触发,将Store内的多个小StoreFile合并成一个大的StoreFile.
Major Compact除了将给定Region中一个列族的所有StoreFile合并成一个大的StoreFile外,还会将其中的Delete标记项进行删除。Major Compact是HBase清理被删除记录的唯一机会,因为我们不能保证被删除的记录和墓碑标记记录在同一个Store内。----一个Region只保存一个Table的数据,一张Table的所有数据分布在多个Region上。一个Region包含多个Store。一个Store只保存一个Column Family的数据,一个Column Family的所有数据分布在多个Store内。
由于Major Compact非常消耗资源,实际应用中,可以考虑必要时手动进行。当Region内StoreFile的大小达到一定阈值后,等分Split为两个StoreFile。
7.Pre-Creating Regions
默认情况下,在创建HBase表的时候会自动创建一个Region分区,当导入数据的时候,所有的HBase客户端都向这一个Region写数据,直到这个Region足够大了才进行切分。一种可以加快批量写入速度的方法是通过预先创建一些空的Regions,这样当数据写入HBase时,会按照Region分区情况,在集群内做数据的负载均衡。 具体详见HBase优化相关
8.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不能直接支持,需要程序逻辑处理。