1、建表属性
1.1、建表基本语句
create "table","cf1":"column","value"
create "table",{NAME => "cf1", VERSION => 3}.{NAME => "CF2",TTL=1212212}
(1)表名:没有太多要求,见名知意
(2)列簇定义
-
列簇名称长度:最好就一个字母;
-
列簇的个数:最好就是一个,不超过三个;
-
列属性定义:列簇名称、最大版本、生命周期、布隆过滤器、读缓存
1.2、列簇属性之BLOOMFILTER(布隆过滤器)
- 含义:是否使用布隆过滤及使用何种方式,布隆过滤可以每列族单独启用
使用方法:create 'table',{NAME => 'baseinfo' BLOOMFILTER => 'ROW'}
-
HColumnDescriptor.setBloomFilterType拥有三种策略:
- ①NONE:不使用布隆过滤器
- ②ROW:行键的哈希在每次插入行时将被添加到布隆,主要用于经常查询行键时
- ③ROWCOL:行键 + 列族 + 列族修饰的哈希将在每次插入行时添加到布隆,主要用于行和列簇中的列的联合查询
-
作用:用布隆过滤可以节省读磁盘过程,可以有助于降低读取延迟
1.3、列簇属性之VERSION(版本号)
- 含义:是数据保留多个版本
create 'table',{ NAME => 'baseinfo' VERSIONS=>'2'}
- 相关策略
- MIN_VERSIONS => ‘0’:在compact操作执行之后,至少要保留的版本
- 前提:只有在设置了TTL时候生效
- MIN_VERSIONS => ‘0’:在compact操作执行之后,至少要保留的版本
1.4、列簇属性之COMPRESSION(压缩)
- 含义:是该列族是否采用压缩,采用什么压缩算法
create 'table',{NAME=>'info',COMPRESSION=>'SNAPPY'}
- 相关压缩算法:推荐使用Snappy算法,标准 - 压缩率、压缩速率
- 注意事项:如果建表之初没有压缩,后来想要加入压缩算法,可以通过alter修改schema
1.5、列簇属性之TTL(Time To Live)
-
含义:列族数据的存活时间,单位是s
-
删除时间:下次 major compact的时候再彻底删除数据
-
默认时间:默认是2147483647,即:Integer.MAX_VALUE 值大概是68年
2、Hbase建表优化之预分区
2.1、预分区概述
在创建HBase表的时候会自动创建一个region分区,当导入数据的时候,所有的HBase客 户端都向这一个region写数据,直到这个region足够大了才进行切分。
Hbase预分区:通过预先创建一些空的regions,这样当数据写入HBase时,会按照region分区情况,在集群内做 数据的负载均衡,从而加快批量写入速度。
2.2、命令行创建预分区
# 1、创建表直接将表切分为5段
hbase>create 'table1','f1',SPLITS => ['\x10\x00', '\x20\x00', '\x30\x00','\x40\x00']
# 2、创建表时指定该表有8个Region,分界值算法为UniformSplit
hbase>create 'table2','f1', { NUMREGIONS => 8 , SPLITALGO => 'UniformSplit' }
# 3、创建表时指定该表有10个Region,分界值算法为HexStringSplit
hbase>create 'table3','f1', { NUMREGIONS => 10, SPLITALGO => 'HexStringSplit' }
2.3、API方式创建预分区
hbase org.apache.hadoop.hbase.util.RegionSplitter test_table HexStringSplit -c
10 -f info
hbase org.apache.hadoop.hbase.util.RegionSplitter splitTable HexStringSplit -c
10 -f info
- 参数详述:
test_table:表名
HexStringSplit:split 方式
-c:指定初始region数量
-f:指定family信息
3、Hbase建表优化之BulkLoad
3.1、BulkLoad原理概述
- 含义:批量插入
正常数据进行插入的时候,都要进行先写操作日志,再写内存,等待时间/数据量会触发flush和compact和split。
BulkLoad模式通过mapreduce程序直接生成 HFile, 直接导入到hbase表中的。
- BulkLoad原理示意图:
(1)从数据源中提取数据,通常是文本文件或者其他数据库,然后将数据文件上传到HDFS中
(2)将数据转换为HFile,这个步骤需要MapReduce,将rowkey作为OutputKey,将一个Put或者Delete作为OutputValue,在这个阶段,将会在输出文件夹中,一个Region就创建一个HFile。注意输入的数据将会几乎被重写,所以所需的磁盘空间至少比原始的数据集的大小多一倍,在进程结束后,可以删除转储文件。
(3)通过告知RegionServers在哪里找到这些文件,并且将文件加载到HBase中,这一步需要使用LoadIncrementalHFiles。
- 缺点:因为没有写入Hlog日志,所以如果数据丢失,就没有找回的可能
3.2、命令行实现BulkLoad
- 将生成好的HFile文件迁移到目标集群(即HBase集群所在的HDFS上),然后在使用HBase命令进行导入。
# 先使用distcp迁移hfile
hadoop distcp -Dmapreduce.job.queuename=queue_1024_01 -update -skipcrccheck -m 10
/tmp/pres hdfs://nns:9000/tmp/pres
# 使用bulkload方式导入数据
hbase org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles /tmp/pres person
4、RowKey设计原则
HBase中表会被划分为1…n个Region,被托管在 RegionServer 中。Region 二个重要的属性: StartKey 与 EndKey 表示这个 Region 维护的 rowKey 范围,当我们要读/写数据时,如果 rowKey 落在 某个start-end key范围内,那么就会定位到目标region并且读/写到相关的数据。
4.1、长度原则
- 定义:不能太长,最好一个,建议不要超过16个字节
(1)Rowkey就要占用100*1000万=10亿个字节,将近1G数据,这会极大影响HFile的存储效率;
(2)MemStore将缓存部分数据到内存,如果Rowkey字段过长内存的有效利用率会降低,系统将无法缓存更多 的数据,这会降低检索效率。因此Rowkey的字节长度越短越好。
4.2、唯一原则
- 定义:同一张表的所有rowkey肯定是唯一的
必须在设计上保证其唯一性。rowkey是按照字典顺序排序存储的,因此,设计rowkey的时候,要充分利用这 个排序的特点,将经常读取的数据存储到一块,将最近可能会被访问的数据放到一块。
4.3、散列原则
- 定义:将数据(Region)分散均匀,保证负载均衡。
如果Rowkey是按时间戳的方式递增,不要将时间放在二进制码的前面,建议将Rowkey的高位作为散列字段, 由程序循环生成,低位放时间字段,这样将提高数据均衡分布在每个Regionserver实现负载均衡的几率。如 果没有散列字段,首字段直接是时间信息将产生所有新数据都在一个 RegionServer上堆积的热点现象,这 样在做数据检索的时候负载将会集中在个别RegionServer,降低查询效率。
5、列簇设计原则
- 追求原则:在合理范围内能尽量少的减少列簇就尽量减少列簇。
- 最优设计:将所有相关性很强的key-value都放在同一个列簇下,这样既能做到查询效率最高,也能保持尽可能少的访问不同的磁盘文件
CASE:以用户信息为例,可以将必须的基本信息存放在一个列族,而一些附加的额外信息可以放在另一列族 hbase的列簇越少越好!尽量就是1个。
6、数据热点
6.1、数据热点原因
(1)hbase的中的数据是按照字典序排序的,当大量连续的rowkey集中写在个别的region,各个region之间数据分布不均衡;
(2)创建表时没有提前预分区,创建的表默认只有一个region,大量的数据写入当前region;
(3)创建表已经提前预分区,但是设计的rowkey没有规律可循,设计的rowkey应该由regionNo+messageId组成。
6.2、数据热点解决方案
- 核心:设计出可以让数据分布均匀的RowKey,让每个Region的负载是相同的
(1)加盐
在rowkey的前面增加随机数,具体就是给**rowkey分配一个 随机前缀以使得它和之前的rowkey的开头不同。**分配的前缀种类数量应该和你想使用数据分散到不同 的region的数量一致。加盐之后的rowkey就会根据随机生成的前缀分散到各个region上,以避免热点。
(2)哈希
哈希会使同一行永远用一个前缀加盐,哈希也可以使负载分散到整个集群,但是读却是可以预测的。使用确定的哈希可以让客户端重构完整的rowkey,可以使用get操作准确获取某一个行数据。
- 注意事项:既可以分散,也可以让相同特征的值存储在一起
(3)反转
反转固定长度或者数字格式的rowkey,这样可以使得rowkey中经常改变的部分(最没有意义的部分)放在前面。这样可以有效的随机rowkey,但是牺牲了rowkey的有序性。
CASE:以手机号为rowkey,可以将手机号反转后的字符串作为rowkey,这样的就避免了以 手机号那样比较固定开头导致热点问题
(4)时间戳反转
一个常见的数据处理问题是快速获取数据的最近版本,使用反转的时间戳作为rowkey的一部分对这个 问题十分有用,可以用 Long.Max_Value - timestamp 追加到key的末尾,例如 [key] [reverse_timestamp] , [key] 的最新值可以通过scan [key]获得[key]的第一条记录,因为HBase中 rowkey是有序的,第一条记录是最后录入的数据。
CASE:比如需要保存一个用户的操作记录,按照操作时间 倒序排序,在设计rowkey的时候,可以这样设计 [userId反转] [Long.Max_Value - timestamp],在查询用户的所有操作记录数据的时候,直接指定反转 后的userId,startRow是[userId反转] [000000000000],stopRow是[userId反转] [Long.Max_Value - timestamp]
7、Hbase的数据访问方式
(1)单个rowkey:非常频繁的一些 rokwey尽量分散;
(2)范围查询
- 如果要查询的数据量很大,但是数据很分散,那么就需要从很多regoinserver去查询;
- 如果要查询的数据量很大,但是又都集中在一个节点,那么这个节点的压力就比较大。
(3)全表扫描