1. Hbase简介
Hadoop-Database根据'bigtable'论文实现的
分布式 可扩展的大数据存储技术
随机访问 实时读写海量数据
存储数 '十亿行 百万列'的数据
高可靠性、高性能、面向列、可伸缩的分布式存储系统
hbase的底层存储基于hdfs
利用Zookeeper作为协调工具
2. Hbase是什么?
分布式开源数据库,基于hadoop分布式文件系统(HDFS)
模仿提供了Google文件系统的BigTable数据库所有功能
处理非常庞大的表
数十亿行 百万列
利用mapreduce计算数据,利用zookeeper协调资源
HBase是一款NoSQL
3. 行存储和列存储
行存储:mysql oracle底层基于行存储数据的
查询数据需要全表扫描,效率较低
对数据压缩支持不太好
列存储:hbase底层基于列存储数据的
查询数据不需做全表扫描
支持较好的数据压缩
4. Hbase的特点
可以分布式存储海量的数据
具有容错能力强,数据高可靠的特点
HBase是一个列式NoSQL数据库
数据存储的结构是按照列进行存储
5. Hbase的安装部署
==安装hbase高可用集群之前首先要保证zookeeper和hadoop已经安装完成==
准备安装包
hbase-1.1.5-bin.tar.gz
集群的规划
uplooking01: master
uplooking02: master
uplooking03: regionserver
uplooking04: regionserver
uplooking05: regionserver
解压安装包
[root@uplooking01: /soft]:
tar -zxvf hbase-1.1.5-bin.tar.gz -C /opt/
重命名
[root@uplooking01: /opt]:
mv hbase-1.1.5/ hbase
配置环境变量
[root@uplooking01: /opt]:
#配置HBASE的环境变量
export HBASE_HOME=/opt/hbase
export PATH=$PATH:$HBASE_HOME/bin
配置vim hbase-env.sh
[root@uplooking01: /opt/hbase/conf]:
vim hbase-env.sh
export JAVA_HOME=/opt/jdk
export HBASE_MANAGES_ZK=false #不使用hbase自带的zookeeper
export HBASE_CLASSPATH=/opt/hadoop/etc/hadoop
配置hbase-site.xml
[root@uplooking01: /opt/hbase/conf]:
vim hbase-site.xml
hbase.rootdir
hdfs://ns1/hbase
hbase.tmp.dir
/opt/hbase/tmp
hbase.cluster.distributed
true
hbase.zookeeper.quorum
uplooking03:2181,uplooking04:2181,uplooking05:2181
配置 regionservers
[root@uplooking01: /opt/hbase/conf]:
vim regionservers
uplooking03
uplooking04
uplooking05
分发文件
[root@uplooking01: /opt]:
scp -r hbase uplooking02:/opt
scp -r hbase uplooking03:/opt
scp -r hbase uplooking04:/opt
scp -r hbase uplooking05:/opt
scp /etc/profile uplooking02:/etc/
scp /etc/profile uplooking03:/etc/
scp /etc/profile uplooking04:/etc/
scp /etc/profile uplooking05:/etc/
source /etc/profile(所有节点都做,要使环境变量生效)
启动hbase集群
start-hbase.sh
单独启动master
[root@uplooking02:/]
hbase-daemon.sh start master
注意事项
==启动hbase集群一定要保证整个集群的时间一致==
==附加(一般不会有这种情况)==
如果启动集群执行start-hbase.sh,master节点可以启动,但是regionserver节点不能启动,但是单独启动regionserver(hbase-daemon.sh start regionserver)是可以启动的,也没有问题,name就需要拷贝一个jar包,
将HADOOP_HOME/share/hadoop/common/lib下的htrace-core-3.0.4.jar 复制到$HBASE_HOME/lib下
6. Hbase的体系结构(模型)
6.1 逻辑结构(模型)
表(table)
划分数据集合的概念,和传统的db中的表的概念是一样的
行键(rowKey)
对应关系数据库中的主键,作用就是唯一标示一行记录
获取hbase中的一个记录(数据),要通过行键来获取
行键是字节数组, 任何字符串都可以作为行键
表中的行根据行键(row key)进行排序 ,数据按照Row key的字节序(byte order)排序存储
列簇(列族)columnFamily
简单的认为是一系列“列”的集合
列限定符(column Qualifier)
或者叫列
每个列簇都可以有多个列
时间戳(version)
在单元格中可以存放多个版本的数据
单元格(cell)
主要用来存储数据
单元格的定位要通过三级定位才能定位到具体的单元格
三级定位
行键+(列族:列)+时间戳
6.2 物理结构(模型)
Zookeeper
分布式协调
Master
HMaster没有单点问题,HBase中可以启动多个HMaster
负责Table和Region的管理工作
管理用户对Table的增、删、改、查操作
RegionServer的负载均衡
调整Region分布 ,在Region Split后,负责新Region的分配
在HRegionServer停机后,负责失效HRegionServer上的Regions迁移
RegionServer
RegionServer主要负责响应用户I/O请求
向HDFS文件系统中读写数据,是HBase中最核心的模块
HLog部分和多个Region部分
Hlog
HLog保存着用户操作hbase的日志
==实现了Write Ahead Log (WAL)预写日志==
Hlog会删除已存储到StoreFile中的数据
Region
区域
保存了row-key的固定区域范围的数据
一个Hregion对应一个Region
一个Hregion对应多个Hstore
Hstore
对应一个列簇(列族)
一个Hstore包含一个MemStore(内存储) 和多个StoreFile
MemStore
内存储
内存中的一块区域,一个Hstore对应一个MemStore
当MemStore中的内容存放不下了就会刷出到硬盘以一个个的StoreFile存储
StoreFile
其实就是数据的存储位置
对HFile的封装**
Hfile
Hadoop File
Hdfs的一个文件对象
7. Hbase读写数据的流程
zookeeper(寻找元数据信息)
get /hbase/meta-region-server
找到提供元数据信息访问的regionserver
找"hbase:meta"表,再去查找要请求哪个regionser来读写数据
8. Hbase的Shell操作
列出所有的命名空间(相当于mysql中的show databases)
list_namespace
列出指定命名空间下的所有表
list_namespace_tables 'ns1'
创建命名空间
create_namespace 'ns1'
创建表
create 'ns1:t1','f1'
禁用表,因为删除表之前首先需要禁用了
disable 'ns1:t1'
启用表
enable 'ns1:t1'
删除表
drop 'ns1:t1'
添加数据
put 'ns1:t1','row001','f1:name','xiaohua'
查询数据
get 'ns1:t1','row001',{COLUMN=>'f1:name'}
删除数据
delete 'ns1:t1','row001','f1:name'
删除一行数据
deleteall 'ns1:t1','row001'
统计表的行数
count 'ns1:t1'
9. Hbase中的版本数据
创建Hbase表时指定列族的显示版本数
create 'ns1:t1',{NAME=>'f1',VERSIONS=>3}
修改Hbase表中的列族的显示版本数
alter 'ns1:t1',{NAME=>'f1',VERSIONS=>5}
查询指定版本数的数据
get 'ns1:t1',{COLUMN=>'f1:name',VERSIONS=>3}
==版本号的作用==
根据显示的版本数,查询出来想要版本的时间戳,根据时间戳找出具体值
10. Hbase中API的基本操作
UTF-8
1.1.5
org.apache.hbase
hbase-client
${hbase-version}
org.apache.hbase
hbase-server
${hbase-version}
org.apache.hive
hive-hbase-handler
2.1.0
junit
junit
4.12
public class HbaseTest {
//添加数据
@Test
public void testPut() throws IOException {
Configuration conf = HBaseConfiguration.create();
//指定zk的地址
conf.set("hbase.zookeeper.quorum", "uplooking03:2181,uplooking04:2181,uplooking05:2181");
Connection conn = ConnectionFactory.createConnection(conf);
Table table = conn.getTable(TableName.valueOf("ns1:t1"));
Put put = new Put(Bytes.toBytes("row001"));
put.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("name"), Bytes.toBytes("admin02"));
table.put(put);
}
//删除数据
@Test
public void testDelete() throws IOException {
Configuration conf = HBaseConfiguration.create();
//指定zk的地址
conf.set("hbase.zookeeper.quorum", "uplooking03:2181,uplooking04:2181,uplooking05:2181");
Connection conn = ConnectionFactory.createConnection(conf);
Table table = conn.getTable(TableName.valueOf("ns1:t1"));
Delete delete = new Delete(Bytes.toBytes("row001"));
table.delete(delete);
}
//查询数据
@Test
public void testGet() throws IOException {
Configuration conf = HBaseConfiguration.create();
//指定zk的地址
conf.set("hbase.zookeeper.quorum", "uplooking03:2181,uplooking04:2181,uplooking05:2181");
Connection conn = ConnectionFactory.createConnection(conf);
Table table = conn.getTable(TableName.valueOf("ns1:t1"));
Get get = new Get(Bytes.toBytes("row001"));
Result result = table.get(get);
String s = Bytes.toString(result.getValue(Bytes.toBytes("f1"),Bytes.toBytes("name")));
System.out.println(s);
}
}
11. Hbase中的API的管理操作
public class HbaseAdminTest {
private Connection connection;
@Before
public void init() throws Exception {
Configuration conf = new Configuration();
conf.set("hbase.zookeeper.quorum", "uplooking03:2181,uplooking04:2181,uplooking05:2181");
connection = ConnectionFactory.createConnection(conf);
}
/**
* 创建表
*
* @throws Exception
*/
@Test
public void testCreateTable() throws Exception {
//获取管理对象
Admin admin = connection.getAdmin();
HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("t2"));
HColumnDescriptor hcd = new HColumnDescriptor(Bytes.toBytes("f1"));
htd.addFamily(hcd);
admin.createTable(htd);
}
/**
* 列出所有的表
* @throws Exception
*/
@Test
public void testListTableNames() throws Exception {
//获取管理对象
Admin admin = connection.getAdmin();
TableName[] tableNames = admin.listTableNames("ns1:.*");
for (TableName tableName : tableNames) {
System.out.println(tableName);
}
}
}
12. Hbase高级查询
//查询数据
@Test
public void testScan() throws IOException {
Configuration conf = HBaseConfiguration.create();
//指定zk的地址
conf.set("hbase.zookeeper.quorum", "uplooking03:2181,uplooking04:2181,uplooking05:2181");
Connection conn = ConnectionFactory.createConnection(conf);
Table table = conn.getTable(TableName.valueOf("ns1:t1"));
Scan scan = new Scan();
byte[] cf = Bytes.toBytes("f1");
byte[] column = Bytes.toBytes("name");
Filter filter = new SingleColumnValueFilter(cf, column, CompareFilter.CompareOp.EQUAL, Bytes.toBytes("admin123"));
scan.setFilter(filter);
//获取包含多行数据的对象
ResultScanner resultScanner = table.getScanner(scan);
for (Result result : resultScanner) {
System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("f1"), Bytes.toBytes("age"))));
}
}
13. 百万数据的插入
13.1 mysql百万数据写入
耗时约20分钟
自己测试10分钟
8800000ms,插入15851742tiao数据
13.2 hbase百万数据的写入
/**
* 百万数据的插入
*/
public class HbaseMiTest {
private Connection connection;
@Before
public void init() throws Exception {
Configuration conf = new Configuration();
conf.set("hbase.zookeeper.quorum", "uplooking03:2181,uplooking04:2181,uplooking05:2181");
connection = ConnectionFactory.createConnection(conf);
}
@Test
public void test01() throws IOException {
HTable table = (HTable) connection.getTable(TableName.valueOf("ns1:t1"));
//不使用每个put操作都刷出一次
table.setAutoFlush(false);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
Put put = new Put(Bytes.toBytes("row" + i));
//关闭预写日志,但是不建议使用,因为这样做不安全
put.setWriteToWAL(false);
put.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("name"), Bytes.toBytes("admin" + i));
table.put(put);
if (i % 100000 == 0) {
table.flushCommits();
}
}
table.flushCommits();
long endTime = System.currentTimeMillis();
System.out.println("总耗时:" + (endTime - startTime) + "ms");
}
}
大约耗时27s
自己测试,1分20秒 590/80=7.4倍
查询一行是9秒
97602ms,插入15851742tiao数据 8800/175=50倍
14. Hbase中的手动切分region
split 'ns1:t1','row040'
15. Hbase手动移动region
move 'f6e6164514db53d660c5414df1f3864e','uplooking05,1602
**0,1539222350164'**
16. Hbase中row-key的设计
行健的热点问题
是由于行健相似、连续且数据量过大操作成单region的数据量过大,进而影响读写效率
行健应该尽量的随机、不要出现连续行健。
常见的行健设计就是,比如手机号码倒置+时间戳,比如随机前缀+关系型数据库中的主键
因为hbase提供的查询内容非常非常low,但是所有关于hbase的查询只能通过rowkey,所以
在设计行健的时候,应该考虑将尽量多的查询条件放到rowkey中去,形成的行健就成为复合键
列族的设计:
cf1----->"columnFamily"
cf2----->"cf"
建议hbase表是高表,不建议宽表,因为宽表拥有的列族很多,操作并跨越的文件(HFile)就很多,效率会有相应影响,
反之建议使用高表,列族不宜过多(列族一般使用一个)。
在设计表的时候,各个列/列族名称不宜过长,因为hbase需要对这些数据在内存中做缓存,做索引,进而影响内存容量,所以建议不易过长,以便能够在内存中容纳更多的数据。至于阅读性,有项目文档搞定。
17. Hbase中客户端工具
HbaseExplorer