可以使用HBase Shell或者Java API的HBaseAdmin来创建和编辑HBase的Schema。
当修改列簇时,建议先将这张表下线(disable):
Configuration config = HBaseConfiguration.create();
HBaseAdmin admin = new HBaseAdmin(config);
String table = "Test";
admin.disableTable(table); // 将表下线
HColumnDescriptor f1 = ...;
admin.addColumn(table, f1); // 增加新的列簇
HColumnDescriptor f2 = ...;
admin.modifyColumn(table, f2); // 修改列簇
HColumnDescriptor f3 = ...;
admin.modifyColumn(table, f3); // 修改列簇
admin.enableTable(table);
更新
当表或者列簇改变时(包括:编码方式、压力格式、block大小等等),都将会在下次marjor compaction时或者StoreFile重写时生效。
表模式设计经验
region最大的阈值取值建议在8GB到50GB之间,不宜过小或过大。
单个cell不超过10MB,如果超过10MB,请使用mob,若再大可以直接存在HDFS中,在HBase内存储HDFS地址。
列簇数量不建议过多,一般1个即可,不建议超过3个。
列簇名应尽量简短,因为存储时每个value都包含列簇名(忽略前缀编码,prefix encoding)。
对于时序场景,建议rowkey设计为设备ID加上时间,如果采用时间+设备ID的方案会导致如下:
同一时间点的数据落入同一个region,导致热点。
较早数据随着时间推移、数据过期会留下大量的空region,带来不必要的开销。
列簇的数量
现在HBase并不能很好的处理两个或者三个以上的列簇,所以尽量让列簇数量少一些。
目前, flush和compaction操作是针对一个region。所以当一个列簇操作大量数据的时候会引发一个flush。那些邻近的列簇也有进行flush操作,尽管它们没有操作多少数据。
compaction操作现在是根据一个列簇下的全部文件的数量触发的,而不是根据文件大小触发的。
当很多的列簇在flush和compaction时,会造成很多没用的I/O负载(要想解决这个问题,需要将flush和compaction操作只针对一个列簇) 。
尽量在模式中只针对一个列簇操作。将使用率相近的列归为一列簇,这样每次访问时就只用访问一个列簇,提高效率。
列簇的基数
如果一个表存在多个列簇,要注意列簇之间基数(如行数)相差不要太大。 例如列簇A有100万行,列簇B有10亿行,按照行键切分后,列簇A可能被分散到很多region(及RegionServer),这导致扫描列簇A十分低效。
版本的数量
行的版本的数量是HColumnDescriptor设置的,每个列簇可以单独设置,默认是3。这个设置是很重要的,因为HBase不会覆盖一个值,只会在值的后面进行追加描述,用时间戳来区分。过早的版本会在执行major compaction时删除,这些在HBase数据模型有描述。这个版本的值可以根据具体的应用增加或减少。
不推荐将版本最大值设到一个很高的水平 (100或更多),除非历史数据很重要,因为这会导致存储文件变得极大。
最小版本数
和行的最大版本数一样,最小版本数也是通过HColumnDescriptor 在每个列簇中设置的。最小版本数缺省值是0,表示该特性禁用。 最小版本数参数和存活时间一起使用,允许配置如“保存最后T秒有价值数据,最多N个版本,但最少约M个版本”(M是最小版本数,M<N)。 该参数仅在存活时间对列簇启用,且必须小于行版本数。
支持数据类型
HBase通过Put和Result支持bytes-in/bytes-out接口,所以任何可被转为字节数组的东西可以作为值存入。输入可以是字符串、数字、复杂对象、甚至图像,它们能转为字节。
存在值的实际长度限制 (如:保存10-50MB对象到HBase对查询来说太长),搜索邮件列表获取本话题的对话。HBase的所有行都遵循HBase数据模型包括版本化。设计时需考虑到以上限制以及列簇的块大小。
存活时间
列簇可以设置TTL秒数,HBase在超时后将自动删除数据,HBase里面TTL时间时区是UTC。
存储文件仅包含有过期的行(expired rows),它们可通过minor compaction删除。将 hbase.store.delete.expired.storefile设置为false,可禁用此功能;将最小版本数设置成非0值也可达到同样的效果。
HBase的最新版本还支持将设定的时间存放在每个结构单元。TTL单元通过Mutation#setTTL作为更变请求(Appends, Increments, Puts, etc.)的一个属性提交,如果TTL的属性被设定了,它将会应用到由于该更变操作更新的所有单元上。cell TTL handling和ColumnFamily TTLs间有两个显著的差别:
Cell TTLs的数量级是毫秒而不是秒。
一个cell TTL不能超出ColumnFamily TTLs设置的有效时间。