HBase基础命令
(和hive,cassandra不同,不能使用 use namespace 进入命名空间,建不建区别貌似不大)
创建命名空间:
create_namespace 'my_ns'
删除命名空间:
drop_namespace 'my_ns'
更改命名空间:
alter_namespace 'my_ns', {METHOD => 'set', 'PROPERTY_NAME' => 'PROPERTY_VALUE'}
创建表:
create 'table name','column family'
例子:
create 'my_ns:my_table', 'fam'
create 'emp', 'personal data', 'professional data'
描述表:
describe 'table name'
列出表:
list
list 'table_name_prefix.*'
更改表:
添加一个新的列族:
alter 'table_name', NAME => 'family_name'
修改单元最大数目:
alter 't1', NAME => 'f1', VERSIONS => 5
删除列族:
alter ‘ table name ’, ‘delete’ => ‘ column family ’
删除表:
删除一个表之前必须先将其禁用。
disable 'emp'
drop 'emp'
插入数据:
put 'table name','row1','colfamily:colname','value'
例子:
put 'emp','1','personal data:name','raju'
put 'emp','1','personal data:city','hyderabad'
更新数据:(实质是直接插入,相同行列直接覆盖)
put 'table name','row','Column family:column name','new value'
例子:
put 'emp','row1','personal:city','Delhi'
扫描数据(扫描所有行):
scan 'table name'
读取数据:
读取一行数据:
get ’table name’,’row1’
例子:
get 'emp', '1'
读取一列数据:
get 'table name', ‘rowid’, {COLUMN => ‘column family:column name ’}
例子:
get 'emp', 'row1', {COLUMN=>'personal:name'}
更多查询数据方式:https://blog.youkuaiyun.com/kehan_c/article/details/95453746
在一个表中删除特定列:
delete 'table name','row','column name','time stamp'
例子:
delete 'emp', '1', 'personal data:city',
删除一行数据(删除表的所有单元格):
deleteall 'table name','row'
例子:
deleteall 'emp','1'
hbase shell执行文本命令
sample_commands.txt 文本内容:
create ‘test’, ‘cf’
list ‘test’
put ‘test’, ‘row1’, ‘cf:a’, ‘value1’
put ‘test’, ‘row2’, ‘cf:b’, ‘value2’
put ‘test’, ‘row3’, ‘cf:c’, ‘value3’
put ‘test’, ‘row4’, ‘cf:d’, ‘value4’
scan ‘test’
get ‘test’, ‘row1’
disable ‘test’
enable ‘test’
可通过以下命令来执行命令脚本:
./hbase shell ./sample_commands.txt
shell的特殊技巧
put 'test', 'row1', 'cf:a', 'value1'
可以写成
test.put 'row1', 'cf:a', 'value1'
同样适用于其他命令,如
t.scan
t.describe
t.disable
t.drop
对于已创建的表,可以使用get_table方法将它分配给一个变量,如
tab = get_table 't'
然后就可以使用tab.scan,tab.put ‘r1’ ,‘f’, ‘v’ 等命令了
建表的注意事项(Table Schema Rules Of Thumb):
1、目标区域(region)大小在10到50 GB之间。
2、目标是细胞(cell)不大于10 MB,或50 MB,如果你使用mob。否则,请考虑将单元格数据存储在HDFS中,并在HBase中存储指向该数据的指针。
3、一个典型的模式每个表有1到3个列族。不应该设计HBase表来模拟RDBMS表。
4、对于包含1或2列族的表,大约50-100个区域(region)是一个不错的数字。请记住,区域是列族的连续段。
5、保持你的列名尽可能的简短。列名存储为每个值(忽略前缀编码)。它们不应该像典型的RDBMS那样是自记录和描述性的。
6、如果您正在存储基于时间的机器数据或日志信息,而行键基于设备ID或服务ID加上时间,那么您可能会得到这样一种模式:旧的数据区域永远不会在特定的年龄之外有额外的写操作。在这种情况下,您将得到少量活动区域和大量没有新写的旧区域。对于这些情况,您可以容忍更多的区域,因为您的资源消耗仅由活动区域驱动。
7、如果只有一个列族忙于写操作,那么只有该列族才能容纳内存。在分配资源时要注意写模式。
自己总结:
1、列族数量要尽可能的少,最好不要超过3个;
2、列族数量尽可能是一个,只有当你需要读取不同的列范围时,才引入第二个(例如,每次只查询一个列族数据,不经常同时查询两个列族的数据);
3、一个表中存在多个列族,注意列族的行数,如果一个列族只有10行,一个100万行,那扫描10行的这个列族的效率会很低;
4、版本version尽可能不要设置的太高。它代表着存储的历史数据的数量,多余的数据才会被清除。
行键设计
1、因为行键是按照字母自动排序的,相关的数据可能会在一个region里,如果大量的读写某个或部分节点的数据,可能会造成节点的堵塞。
a)Salting。就是加随机前缀,这样分布就散开了,这种方式有利于写数据,但在读数据时,要计算去掉随机前缀,不利于读数据。
b)Hashing。和上面差不多,区别是这个前缀有规律,读数据的时候好计算,可以考虑使用。
c)Reversing the Key。直接反转行键,把最容易变化的部分放到开头,这可以有效的随机分布行键,且不怎么影响读数据,但是牺牲了行键自带的排序功能。真遇到阻塞了,这个还是很推荐使用的。
2、单调递增的行键设置是不好的,某些情况下影响写速度。因此不要使用时间戳或者1、2、3作为行键,如果非要使用时间戳,在时间戳前面加上其他的例如类型等不会一直变的字段,如key1-timestamp。
3、行键和列族名尽可能的短一点,不然会降低效率。(原理是行键和列族名作为必须存储的数据,在每行数据都存在,为了随机访问其保存在HFile中的索引值会很大,会占用大块的内存。压缩的话也会占据很大的索引)
列族名尽可能的短小,但是行键要注意,在短小的同时不能影响正常的get和scan查询。
4、反转时间戳。[key][reverse_timestamp]
这种形式挺不错的,先按key排序,再按时间戳倒序。
reverse_timestamp = Long.MAX_VALUE – timestamp
5、行键是不可变的。除非删除后再插入新数据。所以导数据的时候搞清楚行键对不对。
6、如果某些列的访问频率比其他列高,则创建多个列族来将经常访问的列与很少访问的列分开。这提高了性能,因为HBase只读取查询中指定的列族。
7、对于结构化对象,不要使用JSON,它不是很紧凑。使用protobuf、Avro、msgpack或BSON等格式。
8、考虑在存储前使用快速LZ变体压缩数据,以减少延迟和I/O成本。
9、
行键设计实例:
与mysql、hive、cassandra不同,hbase的行键很重要,作为检索工具,它的设置与其它的数据库显著不同,它不能很好地支持join操作,因此对行键设计的要求极高。
行键的具体设计要根据实际的数据情况来设计。
日志数据和序列化数据:
a)时间引导
[bucket][timestamp][hostname][log-event]
其中,long bucket = timestamp % numBuckets;
b)主机引导
[hostname][log-event][timestamp]
c)可变长度行键和定长行键
hbase的行键如果设计成定长的会更好,如果想把变长的行键转换为定长的行键,可以使用MD5加密或者数字替换的方法。
[MD5 hash of hostname] = 16 bytes
[MD5 hash of event-type] = 16 bytes
[timestamp] = 8 bytes
数字替换是使用hbase的counter功能。
客户订单模型(Customer/Order):
订单(order)的行键可以设置为:
[customer number][order number]
在hbase中最好使用定长的行键,因此可以使用md5或者数字替换转换一下:
[MD5 of customer number] = 16 bytes
[MD5 of order number] = 16 bytes
或者
[substituted long for customer number] = 8 bytes
[MD5 of order number] = 16 bytes
关系型数据库一般会建立几张表来保存订单数据,例如order、ShippingLocation、LineItem 等,但hbase没有join能力,来回查找信息很麻烦,所以有时候会把所有的信息整合到一张表里,例如这个例子里,可以把行键设置为
[order-rowkey] [LINE record type] [line item number]
其中订单详情列(LineItem )应该包含很多东西,可以作为列族中的一列,也可以直接保存成一个不规范的数据,例如json形式的数据,但这样解析起来很麻烦,hbase不好直接读取内部信息。
高表和宽表:
高表就是行多,列少,宽表相反,每行数据都存储了很多数据,这两种消耗的存储空间基本没有差别,个人感觉宽表挺好,前提是不要扫描返回行的所有cell,每次只读取一部分数据。
Time To Live (TTL)
ColumnFamilies 可以设置 秒 级别的ttl,时间一到立刻清除数据,刚添加的也删除。
cell 可以设置 毫秒 级别的ttl,但是数据留存时间不会超过所属列族的ttl。
Bulk Loading(最有效的导数据方式)
最直接的导数据方式有 通过client调用API 或者 执行mapreduce作业使用TableOutputFormat 类,但最有效的还是直接将数据写成HFile文件,然后直接提交集群读取。这种方式就是 Bulk Load。
使用Bulk Load的两个步骤:
1、数据准备。通过mapreduce作业准备数据,HFileOutputFormat2自带了一个很有效的功能configureIncrementalLoad(),它可以根据当前表的region分区界限自动设置TotalOrderPartitioner。HFileOutputFormat2这种输出格式以HBase的内部存储格式写出数据(Hfile),可以非常有效地将数据加载到集群中。
2、数据加载。可以使用importtsv的importtsv.bulk.output选项,它可以将数据导入到正在运行的集群中。这个命令行工具遍历准备好的数据文件,每个文件都确定文件所属的区域region。然后,它与采用HFile的适当的RegionServer联系,将其移动到存储目录中,并使数据对客户机可用。如果在数据准备的时候(过程中)region边界发生了变化,该工具会自动调整数据的分片,保证数据的正确加载,但是该功能效率不高,所以在加载数据时,要注意降低数据准备(第一个步骤)的延迟,或者尽量避免多作业同时写数据。
或者通过mapreduce作业使用HFileOutputFormat达到相同的目标。
进阶
如果还不满足importtsv的效率,可以深入研究ImportTsv.java并检查javadoc来获取HFileOutputFormat(HFile的输出格式)。
导入步骤也可以以编程的形式实现,可以研究一下LoadIncrementalHFiles 类。
Hbase工具
Canary 测试工具:
canary-test -help 来查看帮助
如果不输入参数,默认以 region模式 来获取集群每个region的一行
ImportTsv 导入工具:
通过put导入
$ bin/hbase org.apache.hadoop.hbase.mapreduce.ImportTsv -Dimporttsv.columns=a,b,c <tablename> <hdfs-inputdir>
为批量加载(bulk-loading)生成存储文件(storeFile)
$ bin/hbase org.apache.hadoop.hbase.mapreduce.ImportTsv -Dimporttsv.columns=a,b,c -Dimporttsv.bulk.output=hdfs://storefile-outputdir <tablename> <hdfs-data-inputdir>
这些文件可以通过completebulkload加载到Hbase中。
警告:如果准备了大量的数据想通过bulk loading导入到Hbase中,需要确定目标Hbase已经进行了预分区。
CompleteBulkLoad 加载工具:
一般和ImportTsv 一起使用,用于将storeFile加载到表中。
RowCounter 计数工具:
RowCounter是一个用来计算表的行数的mapreduce程序
RowCounter每个单元格只计算一个版本version。
CellCounter 计数工具:
它统计了表的更细粒度的统计信息。如:
表中总行数。
所有行上的列族(cf)总数。
所有行的限定符(cf:qualifier)总数。
每个CF的总发生率。
每个限定符的总出现次数。
每个限定符的版本总数。