1 HBase引言
1.1 HBase简介
HBase的原型是Google的BigTable论文,受到了该论文思想的启发,目前作为Hadoop的子项目来开发维护,用于支持结构化的数据存储。
官方网站:http://hbase.apache.org
民间中文文档:https://hbase.apachecn.org/#/
- 2006年开始开发HBase
- 2008年北京成功开奥运会,程序员默默地将HBase弄成了Hadoop的子项目
- 2010年HBase成为Apache顶级项目
- 现在很多公司基于HBase开发出了定制版,比如阿里云HBase
总结:HBase是构建在HDFS之上的分布式、面向列的存储系统,在需要实时读写、随机访问的超大规模数据集时,可以使用HBase。
1.2 HBase解决问题
一个表百亿行 百万列;(MySQL实战最大值500万行,30列)
1秒内查询得到结果。
1.3 HBase特点
# 1. 容量大
HBase单表百亿行,百万列。
# 2. 面向列
HBase存储是面向列,可以在数据存在以后动态增加新列和数据,并支持列数据的独立操作。
# 3. 多版本
HBase每个数据,可以同时保存多个版本,按照时间去标记。
# 4. 稀疏性
HBase每条数据的增删,并不是要操作所有的列,列可以动态增加,可以存在大量空白单元格,不会占用磁盘空间,这对于海量数据来讲,非常重要。
# 5. 扩展性
底层使用HDFS,存储能力可以横向扩展。
# 6. 高可靠性
底层使用HDFS,拥有replication的数据高可靠性。
# 7. 高性能
表数据达到一定规模,"自动分区",具备主键索引,缓存机制,使得HBase海量数据查询能达到毫秒级。
1.4 HBase与RDBMS
HBase | 关系型数据库 |
---|
数据库以region 的形式存在 | 数据库以Table的形式存在 | 使用行键 (row key) | 支持主键PK | 使用行表示一条数据 | 一条数据用row代表 | 使用列 column、列族 column family | column代表列数据的含义 | 使用HBase shell 命令操作数据 | 使用SQL操作数据 | 数据文件可以基于HDFS,是分布式文件系统, 可以任意扩展,数据总量取决于服务器数量 | 数据总量依赖于单体服务器的配置 | 不支持事务、不支持ACID | 支持事务和ACID | 不支持表连接 | 支持join表连接 |
1.5 HBase表逻辑结构

1.6 数据相关概念
# namespace 命名空间(数据库)
hbase管理表的结构,在HDFS中对应一个文件夹。
# table 表
hbase管理数据的结构,在HDFS中对应一个文件。
# column family 列族
表中数据的列,要属于某个列族,所有的列的访问格式(列族:列名)
注意:一张表中列族不宜过多,1-2即可
1.1 创建表时不需要指定表包含的列,需要指定列族
1.2 添加数据时,可以指定列族下的列
# rowkey 主键
用来标记和检索数据的主键key。
# cell 单元格
由 row key+column family+column+version 唯一确定的一条数据
# timestamp 时间戳
时间戳,每个单元格可以保存多个值,每个值有对应的时间戳,每个cell中,不同版本的数据倒叙排序,排在最前面的是最新数据。
2 HBase伪分布式
2.1 下载
地址:http://archive.apache.org/dist/hbase/
2.2 准备
-
安装并配置hadoop [root@hadoop10 installs]
3440 Jps
3329 SecondaryNameNode
3030 NameNode
3134 DataNode
-
安装并配置zookeeper 单机版Zookeeper安装
1.解压、配置环境变量
2.在/opt/installs/zookeeper3.4.6/下创建data目录
3.修改/opt/installs/zookeeper3.4.6/conf/zoo_sample.cfg文件名为zoo.cfg
4.修改zoo.cfg , dataDir=/opt/installs/zookeeper3.4.6/data/
5.启动zk zkServer.sh start
[root@hadoop10 installs]
3329 SecondaryNameNode
3509 QuorumPeerMain
3030 NameNode
3595 Jps
3134 DataNode
[root@hadoop10 installs]
ZooKeeper JMX enabled by default
Using config: /opt/installs/zookeeper3.4.14/bin/../conf/zoo.cfg
Mode: standalone
-
设置日期同步
[root@hadoop10 installs]
[root@hadoop10 installs]
[root@hadoop10 installs]
2020年 04月 12日 星期日 22:51:31 CST
2.3 启动顺序
在HBase启动之前,一定要确保HDFS、Zookeeper正常启动
2.4 安装
# 1. 安装hbase
1. 解压HBase
[root@hadoop10 modules]
2. 配置环境变量
export JAVA_HOME=/opt/installs/jdk1.8
export PATH=$PATH:$JAVA_HOME/bin
export HADOOP_HOME=/opt/installs/hadoop2.9.2/
export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
export PATH=$PATH:/opt/installs/zookeeper3.4.14/bin/
export HBASE_HOME=/opt/installs/hbase1.2.4/
export PATH=$PATH:$HBASE_HOME/bin
3. 加载profile配置
source /etc/profile
# 2. 初始化配置文件
export JAVA_HOME=/opt/installs/jdk1.8
export HBASE_MANAGES_ZK=false
# 2. -------------------hbase-site.xml-------------------------
<configuration>
<property>
<name>hbase.rootdir</name>
<value>hdfs://hadoop10:9000/hbase</value>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>hadoop10</value>
</property>
</configuration>
hadoop10
# 3. 启动hbase
启动顺序:
1. 启动zookpeer
2. 启动hdfs
3. 启动hbase
1. 启动hbase
start-hbase.sh
2. 关闭hbase
stop-hbase.sh
1. 启动HMaster
[root@hadoop10 installs]
[root@hadoop10 installs]
2. 启动HRegionServer
[root@hadoop10 installs]
[root@hadoop10 installs]
# 4. 验证访问
1. java进程查看
[root@hadoop10 installs]# jps
4688 NameNode
5618 HMaster
5730 HRegionServer
4819 DataNode
3509 QuorumPeerMain
6150 Jps
4984 SecondaryNameNode
2. HMaster WebUI查看
http://ip:16010
3. 进入客户端
hbase shell
hbase(main):001:0>

3 HBase命令
3.1 客户端命令
hbase shell
quit
help
3.2 namespace操作
默认存在一个default的namespace
list_namespace
create_namespace "命名空间名字"`
drop_namespace "命令空间名字"
3.3 表操作
hbase(main):024:0> list
TABLE
abcns:t_person
t_user
2 row(s) in 0.1140 seconds
hbase(main):027:0> list_namespace_tables "abcns"
TABLE
t_person
1 row(s) in 0.3970 seconds
语法:create "namespace:表名","列族1","列族2"
hbase(main):023:0> create "abcns:t_person","info","edu"
0 row(s) in 9.9000 seconds
hbase(main):030:0> desc "abcns:t_person"
Table abcns:t_person is ENABLED
abcns:t_person
COLUMN FAMILIES DESCRIPTION
{NAME => 'edu', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE',
DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE =>
'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}
{NAME => 'info', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE'
, DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE =
> 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}
2 row(s) in 1.6400 seconds
hbase(main):002:0> disable "namespace:表"
0 row(s) in 4.4790 seconds
hbase(main):002:0> drop "namespace:表"
0 row(s) in 4.4790 seconds
3.4 数据增删改查
put "namespace:表","rowkey","列族1:列名1","值"
hbase(main):007:0> put 'abcns:t_person','1001','info:name','zhangsan'
0 row(s) in 1.7250 seconds
hbase(main):008:0> put 'abcns:t_person','1001','info:age',20
0 row(s) in 0.0210 seconds
hbase(main):009:0> put 'abcns:t_person','1002','info:name','lisi'
0 row(s) in 0.0190 seconds
hbase(main):010:0> put 'abcns:t_person','1002','info:age',21
0 row(s) in 0.0620 seconds
get "namespace:表名","rowkey"
hbase(main):015:0> get 'abcns:t_person','1001'
COLUMN CELL
info:age timestamp=1598752891747, value=20
info:name timestamp=1598752881461, value=zhangsan
2 row(s) in 0.1550 seconds
get "namespace:表名","rowkey","列族:列"
hbase(main):019:0> scan "abcns:t_person"
hbase(main):024:0> scan 'abcns:t_person'
ROW COLUMN+CELL
1001 column=info:age, timestamp=1598753486814, value=20
1001 column=info:name, timestamp=1598753478658, value=zhangsan
1002 column=info:age, timestamp=1598753520306, value=21
1002 column=info:name, timestamp=1598753509800, value=lisi
2 row(s) in 0.0410 seconds
hbase(main):022:0> scan "abcns:t_person",{LIMIT=>2}
hbase(main):029:0> scan "abcns:t_person",{STARTROW=>"1001",STOPROW=>"1003"}
hbase(main):032:0> scan 'abcns:t_person',{STARTROW=>'1001',STOPROW=>'1003'}
ROW COLUMN+CELL
1001 column=info:age, timestamp=1598753486814, value=20
1001 column=info:name, timestamp=1598753478658, value=zhangsan
1002 column=info:age, timestamp=1598753520306, value=21
1002 column=info:name, timestamp=1598753509800, value=lisi
问题:HBase中的数据是按照Rowkey的ASCII字典顺序进行全局排序的
假如有5个Rowkey:"012", "0", "123", "234", "3",按ASCII字典排序后的结果为:"0", "012", "123", "234", "3"。
Rowkey排序时会先比对两个Rowkey的第一个字节,如果相同,然后会比对第二个字节,依次类推... 对比到第X个字节时,已经超出了其中一个Rowkey的长度,短的Rowkey排在前面。
hbase(main):032:0> scan "abcns:t_person",{STARTROW=>"1002",LIMIT=>2}
hbase(main):033:0> scan 'abcns:t_person',{STARTROW=>'1002',LIMIT=>2}
ROW COLUMN+CELL
1002 column=info:age, timestamp=1598753520306, value=21
1002 column=info:name, timestamp=1598753509800, value=lisi
1003 column=info:name, timestamp=1598753628840, value=wangwu
put "namespace:表","rowkey","列族:列名","值"
delete "namespace:表","rowkey","列族:列名"
deleteall "namespace:表","rowkey"
count "namespace:表"
truncate "namespace:表"
3.5 多版本问题
hbase(main):013:0> create "abcns:user","info"
hbase(main):016:0> alter "abcns:user",{NAME=>'info',VERSIONS=>2}
hbase(main):014:0> put "abc:user","10001","info:name","aaa"
0 row(s) in 0.2620 seconds
hbase(main):015:0> put "abc:user","10001","info:name","bb"
0 row(s) in 0.0290 seconds
hbase(main):017:0> get "abc:user","10001",{COLUMN=>'info:name',VERSIONS=>3}
COLUMN CELL
info:name timestamp=1586795010367, value=bb
info:name timestamp=1586795004085, value=aaa
说明:
1. 可以查看VERSIONS指定的版本数量的值。
2. cell中多个版本的值,按照时间戳降序排序。
3. 在get或者scan查询数据,并不指定VERSIONS,默认读取的cell中最新的1个的版本的值。
4 HBase API
4.1 环境准备
-
依赖 <dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>1.2.4</version>
</dependency>
-
初始化配置 将hbase中的conf中的 hbase-site.xml放到resource配置文件目录中。 conf.addResource("/hbase-site.xml") -
windows配置IP映射
4.2 API介绍
API | 含义 | 创建 |
---|
Configuration | 配置文件 | HBaseConfiguration.create(); | Connection | 连接,用来操作数据 | ConnectionFactory.createConnection(conf); | Admin | 客户端,用来操作元数据 (namespace和table结构) | conn.getAdmin(); | NamespaceDescriptor | 命名空间相当于database | NamespaceDescriptor.create(“abcns”).build(); | TableName | 表名 | TableName.valueOf(“abc:user”); | HTableDescriptor | 表 | new HTableDescriptor(tablename); | HColumnDescriptor | 列族 | new HColumnDescriptor(“info”); | Put | 添加数据 | new Put(Bytes.toBytes(“10001”)); | Delete | rowkey的删除条件 | new Delete(Bytes.toBytes(“10001”)); | Get | scan多行查询器 | new Get(Bytes.toBytes(“10019”)); | Scan | scan多行查询器 | new Scan(); | Result | 查询结果集(单条结果) | table.get(get); | ResultScanner | 查询结果集(N条结果) | table.getScanner(scan); | Bytes | 类型转化工具类,HBase中数据类型为字节, 所有类型存入后都变成字节,需要相互转化。 | |
4.3 HBase客户端
注意:配置windows向linux的ip映射
Configuration conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum","hadoop10");
BasicConfigurator.configure();
Connection conn = ConnectionFactory.createConnection(conf);
admin = conn.getAdmin();
admin.close();
4.4 常用API
4.4.1 创建namespace
NamespaceDescriptor abcns = NamespaceDescriptor.create("abcns").build();
admin.createNamespace(abcns);
4.4.2 表操作
操作表,使用admin
-
判断表是否存在
TableName tableName = TableName.valueOf("abcns:person");
boolean b = admin.tableExists(tableName);
System.out.println(b?"存在":"不存在");
-
创建表
TableName person = TableName.valueOf("abcns:person");
HColumnDescriptor info = new HColumnDescriptor("info");
HColumnDescriptor addr = new HColumnDescriptor("addr");
HTableDescriptor hTableDescriptor = new HTableDescriptor(person);
hTableDescriptor.addFamily(info);
hTableDescriptor.addFamily(addr);
admin.createTable(hTableDescriptor);
4.4.3 添加
操作数据使用conn
Table table = conn.getTable(TableName.valueOf("abcns:t_person"));
Put put = new Put(Bytes.toBytes("1001"));
put.addColumn(Bytes.toBytes("info"),Bytes.toBytes("name"),Bytes.toBytes("张三") );
put.addColumn(Bytes.toBytes("info"),Bytes.toBytes("age"), Bytes.toBytes(18));
put.addColumn(Bytes.toBytes("addr"), Bytes.toBytes("zipCode"), Bytes.toBytes("45000"));
table.put(put);
table.close();
4.4.4 修改
Table table = conn.getTable(TableName.valueOf("abcns:person"));
Put put = new Put(Bytes.toBytes("1001"));
put.addColumn(Bytes.toBytes("addr"), Bytes.toBytes("zipCode"), Bytes.toBytes("45001"));
table.put(put);
table.close();
4.4.5 删除
Table table = conn.getTable(TableName.valueOf("abcns:person"));
Delete delete = new Delete(Bytes.toBytes("1001"));
table.delete(delete);
4.4.6 查询
-
根据rowkey单条查询
Table table = conn.getTable(TableName.valueOf("abcns:person"));
Get get = new Get(Bytes.toBytes("10019"));
Result result = table.get(get);
byte[] namebyte = result.getValue(Bytes.toBytes("info"), Bytes.toBytes("name"));
byte[] agebyte = result.getValue(Bytes.toBytes("info"), Bytes.toBytes("age"));
byte[] zipbyte = result.getValue(Bytes.toBytes("addr"), Bytes.toBytes("zipCode"));
byte[] rowbytes = result.getRow();
System.out.println(Bytes.toString(namebyte));
System.out.println(Bytes.toInt(agebyte));
System.out.println(Bytes.toString(zipbyte));
-
多条查询
Table table = conn.getTable(TableName.valueOf("abcns:person"));
Scan scan = new Scan();
scan.addFamily(Bytes.toBytes("info"));
scan.addFamily(Bytes.toBytes("addr"));
scan.setStartRow(Bytes.toBytes("1001"));
scan.setFilter(new PageFilter(3));
ResultScanner result = table.getScanner(scan);
for (Result res:result){
byte[] namebyte = res.getValue(Bytes.toBytes("info"), Bytes.toBytes("name"));
byte[] agebyte = res.getValue(Bytes.toBytes("info"), Bytes.toBytes("age"));
byte[] zipCodebyte = res.getValue(Bytes.toBytes("addr"), Bytes.toBytes("zipCode"));
String name = Bytes.toString(namebyte);
int age = Bytes.toInt(agebyte);
String zipcode = Bytes.toString(zipCodebyte);
System.out.println(name+":"+age+":"+zipcode);
}
table.close();
-
范围查询
Table table = conn.getTable(TableName.valueOf("abcns:person"));
Scan scan = new Scan();
scan.addFamily(Bytes.toBytes("info"));
scan.addFamily(Bytes.toBytes("addr"));
scan.setStartRow(Bytes.toBytes("1001"));
scan.setStopRow(Bytes.toBytes("1003"));
ResultScanner result = table.getScanner(scan);
for (Result res:result){
byte[] namebyte = res.getValue(Bytes.toBytes("info"), Bytes.toBytes("name"));
byte[] agebyte = res.getValue(Bytes.toBytes("info"), Bytes.toBytes("age"));
byte[] zipCodebyte = res.getValue(Bytes.toBytes("addr"), Bytes.toBytes("zipCode"));
String name = Bytes.toString(namebyte);
int age = Bytes.toInt(agebyte);
String zipcode = Bytes.toString(zipCodebyte);
System.out.println(name+":"+age+":"+zipcode);
}
table.close();
-
前缀查询 Scan scan = new Scan();
Filter filter = new RowFilter(CompareFilter.CompareOp.EQUAL,new RegexStringComparator("a-"));
scan.setFilter(filter);
ResultScanner results = table.getScanner(scan);
for (Result result : results) {
byte[] nameByte = result.getValue(Bytes.toBytes("cf1"),Bytes.toBytes("name"));
byte[] ageByte = result.getValue(Bytes.toBytes("cf1"),Bytes.toBytes("age"));
System.out.println(Bytes.toString(nameByte) + "\t" + Bytes.toString(ageByte));
}
table.close();
-
多版本查询 Get get = new Get(Bytes.toBytes("1001"));
get.addColumn(Bytes.toBytes("cf1"),Bytes.toBytes("name"));
get.setMaxVersions(5);
Result result = table.get(get);
Cell[] cells = result.rawCells();
for (Cell cell : cells) {
System.out.println(Bytes.toString(CellUtil.cloneValue(cell)));
}
List<Cell> cells = result.listCells();
for (Cell cell : cells) {
System.out.println(Bytes.toString(CellUtil.cloneValue(cell)));
}
5 HBase架构体系
5.0 HBase基础架构

5.1 HRegionServer
HBase 是集群结构,会把这些块儿分散存储到多个服务器中,每个服务器名为HRegionServer 
HRegionServer(和DataNode同一节点)
1. 存储表数据部分
2. put delete get scan等针对数据的操作
3. 定时向Master报告自身节点的状态
4. 管理表的数据的Table的数据
5.2 HMaster
服务器多,需要一个管理者HMaster,负责 HRegion 的分配、HRegionServer 负载均衡的处理 
HMaster
1. Region Server状态的管理
2. 表的管理:create drop alter
3. 实现HRegionServer的数据负载均衡,平衡HRegion的分布
5.3 Zookeeper
Zookeeper
1. 解决HMaster的单点故障问题
2. 存放HMaster管理的HRegionServer的状态信息,并通知HMaster
3. 存放HMaster管理的表的元数据信息
表名、列名、key区间等。
5.4 HRegion
当某个 HRegion 的大小达到阈值后,便会被分割开来,新的 HRegion 也会由 HMaster 进行分配,放置到合适的 HRegionServer 中,HRegion 是 HBase 中分布式存储的最小单元,但并不是存储的最小单元,HRegion 内部会按照列族进行切分,分为多个 Store,每个 Store 保存一个列族,所以 HRegion 由一个或者多个 Store 组成 
HRegion
1. 表的横向切片的物理表现,大表的子表,有(startkey endkey),多行数据。
2. 为了减小单表操作的大小,提高读写效率。
5.5 Store
每个 Strore 又由一个 MemStore 和 N个 StoreFile 组成 , MemStore 是内存存储单元,当内存中数据达到阈值后,写入 StoreFile,StoreFile 以 HFile 格式保存 
Store
1. 表的纵向切分的物理表现,按照列族作为切分。
2. 按照列族查询,仅需要检索一定范围内的数据,减少全表扫描。

6 HBase读写原理
meta表:快速定位一条数据,在哪个regionserver的region中
6.1 读数据
获取读数据的region所在的RegionServer,先去BlockCache读取,若BlockCache没有,则到Memstore读取,若Memstore中没有,则到HFile中去读。

6.2 写数据
获取写数据的region所在的RegionServer,然后先将数据写到WAL(Write-Ahead Logging,预写日志系统)中,然后再将数据写到Memstore等待刷新,回复客户端写完成,然后再写入到storefile

7 HBase底层原理
7.1 Region Split分区
-
分区原因:提高Region的负载和读写效率  -
分区说明:Region一拆为二,并分布在不同的RegionServer上 -
默认分区机制: Region中数据超过128M、512M、1152M… *Region数量2hbase.hregion.memstore.flush.size … 10G、10G hbase.hregion.memstore.flush.size=128M
hbase.hregion.max.filesize=10G

-
分区问题
默认分区容易导致数据倾斜,硬件资源无法利用。(数据热点问题,大量的客户端访问,落在部分节点上,导致忙的忙死,闲的闲死。)
7.2 Region 预分区
-
预分区原因 ①增加读写效率。(多个region分布在不同的RegionServer中,可以提高并发效率) ②尽量保证每个Region中的数据量相当,防止数据倾斜。(合理利用计算资源) -
分区效果 每个Region维护一对StartKey和EndKey,限定维护输入rowkey范围。 添加数据时,将rowkey放入匹配的region中 region的切分问题:
-
切分的过程影响集群的运行效率 -
region切分之后,可能会导致单个region的热点问题 -
命令预分区 命令:create "namespace:表","列族",SPLITS=>["100000","200000","300000","400000"] 效果:(http://ip:16030)访问RegionServers -
Java预分区 
7.3 MemStore Flush刷写
-
刷写说明
简言:持久化,保护数据不丢失。
将RegionServer中内存中的数据Memstore,写入到硬盘中。
 
7.4 StoreFile Compaction
-
目的
storefile小文件过多,查询时,需要遍历所有文件,效率低。
storefile中遍布过期数据,占用空间,且查询效率低。
-
说明
简言:为提高检索效率,合并store。 
-
分类和时机
特点:
- 全局的所有store file文件的合并。
- 去除删除被覆盖的文件。
- 特别消耗RegionServer的性能资源。(重点)
服务器执行全局合并至,对外暂时不提供服务
时机:每7天执行一次:参数:hbase.hregion.majorcompaction
一般手动触发。 手动触发命令:major_compact "namespace:表名"
7.5 rowkey设计原则
HBase四点RowKey设计原则:长度原则、唯一原则、排序原则,散列原则
-
长度原则:RowKey本质上是一个二进制码的流,可以是任意字符串,最大长度为64kb,实际应用中一般为10-100byte,以byte[]数组形式保存,一般设计成定长。官方建议越短越好,不要超过16个字节。 -
唯一原则:由于RowKey用来唯一标识一行记录,所以必须在设计上保证RowKey的唯一性。 -
排序原则:HBase会把RowKey按照ASCII进行自然有序排序,所以反过来在设计RowKey的时候可以根据这个特点来设计完美的RowKey,利用好这个特性就是排序原则。 -
散列原则:设计出的RowKey需要能够均匀的分布到各个RegionServer上。比如设计RowKey的时候,当Rowkey 是按时间戳的方式递增,就不要将时间放在二进制码的前面,可以将 Rowkey 的高位作为散列字段,由程序循环生成,可以在低位放时间字段,这样就可以提高数据均衡分布在每个Regionserver实现负载均衡的几率。 
7.6 热点现象及解决
当大量请求访问HBase集群的一个或少数几个节点,造成少数RegionServer的读写请求过多,负载过大,而其他RegionServer负载却很小,这样就造成热点现象
通过RowKey优化,避免热点现象
-
反转(Reversing):顾名思义就是把固定长度或者数字格式的rowkey进行反转,反转分为一般数据反转和时间戳反转,其中以时间戳反转较常见。 适用场景:初步设计出的RowKey在数据分布上不均匀,但RowKey尾部的数据却呈现出了良好的随机性(注意:随机性强代表经常改变,没意义,但分布较好),可以考虑将RowKey的信息翻转,或者直接将尾部的bytes提前到RowKey的开头。反转可以有效的使RowKey随机分布,但是反转后有序性就得不到保障,因此它牺牲了RowKey的有序性。 -
加盐(Salting):不同于密码学里的加盐方法,RowKey的加盐原理是在原RowKey的前面添加固定长度的随机数,也就是给RowKey分配一个随机前缀使它和之前的RowKey的开头不同。 适用场景:设计的RowKey虽有意义,但是数据类似,随机性比较低,反转也没法保证随机性,这样就没法根据RowKey分配到不同的Region里,这时候就可以使用加盐的方式。 需要注意随机数要能保障数据在所有Regions间的负载均衡,也就是说**分配的随机前缀的种类数量应该和想把数据分散到的那些region的数量一致 **。只有这样,加盐之后的rowkey才会根据随机生成的前缀分散到各个region中,避免热点现象。 -
哈希(Hashing):基于RowKey的完整或部分数据进行Hash,而后将哈希后的值完整替换或部分替换原RowKey的前缀部分。这里说的hash常用的有MD5、sha1、sha256 或 sha512 等算法。 适用场景:哈希和加盐的适用场景类似,但是由于加盐方法的前缀是随机数,用原rowkey查询时不方便,因此出现了哈希方法,由于哈希是使用各种常见的算法来计算出的前缀,因此哈希既可以使负载分散到整个集群,又可以轻松读取数据。
7.7 BlockCache(高速读写)
# 1 Memstore
Region内存中
特点:
(内存)
(数据最新的)
(有序)
# 2 BlockCache(LRU)
HBase缓存中。
缓存策略:LRU(数据淘汰机制),最近最少使用原则,保留最近最新使用多的数据。
写:数据写入MemStore(内存),然后再刷写到storefile (硬盘)
MemStore提供写的效率,底层写入数据到MemStore就认为写功能
读:从BlockCache(内存缓存)中读取,读取不到再去MemStore(内存)中读,读取不到再去StoreFile(硬盘)中读取,读取到数据之后存储到BlockCache(内存缓存)中
BlockCache底层采用的LRU算法,会将最近最少使用的数据淘汰掉,保证内存中多存储一些热点数据
8 HBase完全分布式
注意
- 编辑regionservers,使用vi编辑
- 安装hbase之前,同步系统时间
8.1 官方架构图

8.2 完全分布式
集群规划
192.168.199.11: HMaster
192.168.199.12: HRegionServer
192.168.199.13: HRegionServer
# 0 确保HDFS HA已经搭建完毕
[root@hadoop11 ~]# jps
1259 JournalNode
1965 NameNode
1758 DFSZKFailoverController
2110 Jps
1215 QuorumPeerMain
# 1. 安装HBase
1. 解压HBase
[root@hadoop11 modules]
2. 配置环境变量
export JAVA_HOME=/opt/installs/jdk1.8
export PATH=$PATH:$JAVA_HOME/bin
export HADOOP_HOME=/opt/installs/hadoop2.9.2/
export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
export PATH=$PATH:/opt/installs/zookeeper3.4.14/bin/
export HBASE_HOME=/opt/installs/hbase-1.2.4
export PATH=$PATH:$HBASE_HOME/bin
3. 加载profile配置
source /etc/profile
# 2. 初始化HBase 配置文件
export JAVA_HOME=/opt/installs/jdk1.8
export HBASE_MANAGES_ZK=false
# 2. -------------------hbase-site.xml-------------------------
<configuration>
<property>
<name>hbase.rootdir</name>
<value>hdfs://hdfs-cluster/hbase</value>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>hadoop11,hadoop12,hadoop13</value>
</property>
</configuration>
hadoop12
hadoop13
[root@hadoop11 installs]
[root@hadoop11 installs]
# 3. 远程拷贝
1. 拷贝profile文件
[root@hadoop11 installs]# scp /etc/profile root@hadoop12:/etc/
[root@hadoop11 installs]# scp /etc/profile root@hadoop13:/etc/
2. 拷贝hbase安装软件和配置文件
[root@hadoop11 installs]# scp -r hbase-1.2.4/ root@hadoop12:/opt/installs/
[root@hadoop11 installs]# scp -r hbase-1.2.4/ root@hadoop13:/opt/installs/
3. 重新加载profile
[root@hadoop11 ~]# source /etc/profile
[root@hadoop12 ~]# source /etc/profile
[root@hadoop13 ~]# source /etc/profile
# 3. 启动HBase
1. 启动hbase
start-hbase.sh
2. 关闭hbase
stop-hbase.sh
|