面向列的据库HBase
第一章 Hbase介绍
本阶段介绍HBase 是一个分布式的、面向列的开源数据库。是基于Google 开源的bigtable的实现,面向列的非关系型数据库。点击查看HBase官方网站介绍
Hadoop生态系统图
非关系型数据库知识面扩展
- cassandra (开源分布式NoSQL数据库系统)
HBase ( 分布式的、面向列的开源数据库 )
MongoDB ( 基于分布式文件存储的数据库) - Couchdb ( 文件存储数据库 )
- Neo4j ( 非关系型图数据库 )
HBase简介
- HBase (Hadoop Database): 是一个高可靠性、高性能、面向列、可伸缩、实时读写的分布式非关系型数据库
- 利用Hadoop HDFS作为其文件存储系统,利用Hadoop MapReduce来处理HBase中的海量数据,利用Zookeeper作为其分布式协同服务。
- 从技术上讲,HBase实际上更像是“数据存储”而不是“数据库”,因为它缺少RDBMS中的许多功能,例如字段型列,二级索引,触发器和高级查询语言等。
- 主要用来存储非结构化和半结构化的松散数据(列式存储的NoSQL 数据库),但是他同样能够存储结构化数据
HBase架构
1. Client
- 提供访问HBase的接口并维护cache(写缓存)来加快对HBase的访问
2. Zookeeper
前两点说明了ZK不仅有高可用功能 , 后两点还说明了ZK具有存储功能
- 保证任何时候,集群中只有一个master(采取主备节点 .mater: 主节点)
- 实时监控Region server的上线和下线信息。并实时通知Master( 类似心跳检测 ,健康检查 )
- 存贮所有Region的寻址入口 。
- 存储HBase的schema和table元数据
3. Master
主要是用于管理Region Server
- 为Region server分配region
- 负责Region server的负载均衡
- 发现失效的Region server并重新分配其上的region
- 管理用户对table的增删改操作
4. RegionServer
- Region server维护region,处理对这些region的IO请求
- Region server负责切分在运行过程中变得过大的region
5. Region
- HBase自动把表水平划分成多个区域(region),每个region会保存一个表里面某段连续的数据
- 每个表一开始只有一个region,随着数据不断插入表,region不断增大,当增大到一个阀值的时候,region就会等分会两个新的region(裂变)
- 当table中的行不断增多,就会有越来越多的region。这样一张完整的表被保存在多个Regionserver 上。( 防止数据倾斜, 压力过大)
6. Memstore 与 storefile
- 一个region由多个store组成,一个store对应一个CF(列族)
- store包括位于内存中的memstore和位于磁盘的storefile写操作先写入memstore, 当memstore中的数据达到某个阈值,hregionserver会启动 flashcache 进程写入storefile,每次写入形成单独的一个storefile (这里也可以通过
flush 表名
手动写入storefile ) - 当storefile文件的数量增长到一定阈值后,系统会进行合并(minor、major compaction) ,在合并过程中会进行版本合并和删除工作(majar),形成更大的storefile
minor compaction:自动合并 , 小范围合并 ,不会影响读写性能
major compaction:手动触发 , 所有storefile合成一个storefile, 影响读写性能 - 当一个region所有storefile的大小和数量超过一定阈值后,会把当前的region分割为两个,并由hmaster分配到相应的regionserver服务器,实现负载均衡
- 客户端检索数据,先在memstore找,找不到再找storefile
HRegion ( 即: Hbase架构图中的Region):
- HRegion是HBase中分布式存储和负载均衡的最小单元。最小单元就表示不同的HRegion可以分布在不同的 HRegion server上。
- HRegion由一个或者多个Store组成,每个store保存一个列族columns family。
- 每个Strore又由一个memStore和0至多个StoreFile组成。如图:StoreFile以HFile格式保存在HDFS上。
HBase 立体架构图
观看方式 : 从后往前看
如果面试问架构怎么办?
通过对上面架构图的理解, 最好能够手画架构图 , 如果在面试中由于紧张答不出来了可以自己画出来,如下图
在此类面试最好自备笔和纸
HBase数据模型
1. ROW KEY
- 唯一标识一行数据( 类似MySQL中的主键 )
- 按照字典顺序排序的。
- Row key只能存储64k的字节数据
2. Timestamp时间戳
- 在HBase每个cell存储单元对同一份数据有多个版本,根据唯一的时间戳来区分每个版本之间的差异,不同版本的数据按照时间倒序排序,最新的数据版本排在最前面。
- 时间戳的类型是 64位整型。
- 时间戳可以由HBase(在数据写入时自动)赋值,此时时间戳是精确到毫秒的当前系统时间。
- 时间戳也可以由客户显式赋值,如果应用程序要避免数据版本冲突,就必须自己生成具有唯一性的时间戳。
3. Column Family列族 & qualifier列
- HBase表中的每个列都归属于某个列族,列族必须作为表模式(schema)定义的一部分预先给出。如 create ‘test’, ‘course’;
- 列名以列族作为前缀,每个“列族”都可以有多个列成员(column);如course:math, course:english, 新的列族成员(列)可以随后按需、动态加入;
- 权限控制、存储以及调优都是在列族层面进行的;
- HBase把同一列族里面的数据存储在同一目录下,由几个文件保存。
- 定义表格时,可以不声明列, 但必须声明列族
4. Cell单元格
- 由行和列的坐标交叉决定;
- 单元格是有版本的;
- 单元格的内容是未解析的字节数组;
- 由{row key, column( = +), version} 唯一确定的单元。
- cell中的数据是没有类型的,全部是字节码形式存贮。
5. Hlog(WAL log)
- HLog文件就是一个普通的Hadoop Sequence File,Sequence File 的Key是HLogKey对象,
- HLogKey中记录了写入数据的归属信息,除了table和region名字外,同时还包括 sequence number和timestamp,
timestamp是” 写入时间”,sequence number的起始值为0,或者是最近一次存入文件系统中sequence number。(一旦数据被删除, 即可通过这里进行恢复 ) - HLog SequeceFile的Value是HBase的KeyValue对象,即对应HFile中的KeyValue
第二章 HBase安装
伪分布式搭建
在单机跑( 安装在node1主机上, 主要不要安装在zk中)
安装步骤
# 1.上传文件并解压(软件见底部分享)
tar -zxf hbase-0.98.12.1-hadoop2-bin.tar.gz
mv hbase-0.98.12.1-hadoop2 /opt/hbase
# 2,配置环境变量( 追加或修改如下内容 ),然后 source /etc/profile
export HBASE_HOME=/opt/hbase
export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_PREFIX/bin:$HADOOP_PREFIX/sbin:$ZOOKEEPER_HOME/bin:$HIVE_HOME/bin:$HBASE_HOME/bin
# 3.测试是否安装成功(图1)
hbase +tab+tab
# 4.修改配置文件 hbase-env.sh (复制自己java的java_home,添加到文件中)
export JAVA_HOME=/usr/local/jdk1.8.0_11
# 5.修改配置文件 hbase-site.sh ( 添加如下内容,指定了hbase数据存放目录 )
<property>
<name>hbase.rootdir</name>
<value>file:///home/testuser/hbase</value>
</property>
<property>
<name>hbase.zookeeper.property.dataDir</name>
<value>/home/testuser/zookeeper</value>
</property>
# 6.测试hbase服务能否启动
##注意:hbase内嵌了zookeeper,因此不能在有zk启动的节点安装,建议新建一个节点
[root@node1 opt]# start-hbase.sh
[root@node1 opt]# jps
7177 HMaster
##访问图形化界面
http://node1:60010/
## 进入hbase的命令行窗口
hbase shell
图1
hbase help中的显示的所有hbase命令
COMMAND GROUPS:
Group name: general
Commands: status, table_help, version, whoami
Group name: ddl
Commands: alter, alter_async, alter_status, create, describe, disable, disable_all, drop, drop_all, enable, enable_all, exists, get_table, is_disabled, is_enabled, list, show_filters
Group name: namespace
Commands: alter_namespace, create_namespace, describe_namespace, drop_namespace, list_namespace, list_namespace_tables
Group name: dml
Commands: append, count, delete, deleteall, get, get_counter, get_splits, incr, put, scan, truncate, truncate_preserve
Group name: tools
Commands: assign, balance_switch, balancer, catalogjanitor_enabled, catalogjanitor_run, catalogjanitor_switch, close_region, compact, compact_rs, flush, hlog_roll, major_compact, merge_region, move, split, trace, unassign, zk_dump
Group name: replication
Commands: add_peer, disable_peer, disable_table_replication, enable_peer, enable_table_replication, list_peers, list_replicated_tables, remove_peer, set_peer_tableCFs, show_peer_tableCFs
Group name: snapshots
Commands: clone_snapshot, delete_all_snapshot, delete_snapshot, list_snapshots, restore_snapshot, snapshot
Group name: security
Commands: grant, revoke, user_permission
Group name: visibility labels
Commands: add_labels, clear_auths, get_auths, list_labels, set_auths, set_visibility
基础语法
# ctr+BackSpace 删除命令单词
#help 查看 hbase 使用( 显示相关语法信息)
#list 列出所欲当前数据表
#describe 查看表描述
#scan 列出当前数据表中记录数
#create 创建表
#disable 将表设置成禁用
#drop 删除表
#put 增加记录
#delete 删除记录
# 举例
## 创建 emp表,列族分别是eno,ename
create 'emp','eno','empname'
## 描述表(图1)
describ 'emp'
## 删除表(图2)
## 添加数据到表,通过row key 获取对应列族信息,查看表的所有信息 (图3)
## 更改表( 通过row key进行数据的覆盖) ,flush 将 inmemstore 中数据写入 storefile(图4)
flush 表名
##根据row+列族名 ,使用delete 删除相关信息(图4)
图1
图2
图3
图4
图5
完全分布式搭建
原本搭建模式图
因为本人机器性能的原因, 改成如下架构
搭建步骤
前提: Hadoop集群必须准备好 Hadoop HDFS集群搭建步骤
1、环境准备
- hostname (主机名:node1,2,3,…)
- hosts (地址映射,将主机名与对应的虚拟机id配置映射)
- iptables (关闭防火墙,可使用永久关闭防火墙命令)
- 网络 (查看相互之间能否ping通)
2、时间同步 时间服务器
yum install ntp -y
ntpdate 202.120.2.101
3 免秘钥
简单免密钥配置
主-备 ,主-从,备-从(需要进行免密钥设置)
例如node1主,node5备(mater),node2,3,4从(region server)
node1需要配置免密钥到node2,3,4,5
mpde5需要配置免密钥到node1,2,3,4
# 免密钥配置方式如下
ssh-keygen #然后一直回车
ssh-copy-id -i .ssh/id_rsa.pub node_x # 然后根据提示输入node_x的密码,node_x为当前节点名称或ip
ssh node_x
exit
4、jdk环境变量
5、解压hbase,并配置hbase环境变量
6、修改配置文件
# 1. 修改配置文件 hbase-env.sh (添加如下内容)
export JAVA_HOME=/usr/local/jdk1.8.0_11
export HBASE_MANAGES_ZK=true
# 2. 修改配置文件 hbase.site.xml( hdfs://mycluster为hadoop集群名称 )
## hadoop集群名称可通过 cat /opt/hbase/conf/hdfs-site.xml 命令,找到name为dfs.nameservices的值就是集群名称
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<property>
<name>hbase.rootdir</name>
<value>hdfs://mycluster:8020/hbase</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>node2,node3,node4</value>
</property>
# 3, 修改配置文件regionservers
node2
node3
node4
# 4. 创建并修改文件 backup-masters ,内容是备用Master的位置
node4
# 5. 将hdfs 中的hdfs-site.xml文件拷贝到当前目录
cp /opt/chy/hadoop/etc/hadoop/hdfs-site.xml ./
# 6.将配置好的hbase分发到其他主机节点
scp -r hbase/ root@node2:/opt
scp -r hbase/ root@node3:/opt
scp -r hbase/ root@node4:/opt
# 7.启动Hbase集群
start-hbase.sh
## 计入hbase的命令行
hbase shell
## 关闭集群
stop-hbase.sh
## 利用jps查看master是否启动成功( 图1,图2)
## 访问图形化界面,查看主备配置是否完成(图3) 很重要!!!
node1:60010
图1
图2
图3
第三章 HBase-API
重点 : rowkey 设计
环境搭建
Demo案例
创建 hbase-demo 普通 java 项目,并导入 hadoop 和 hbase 相关依赖 jar 包,并发布到类路径上
-
创建 HBaseDemo
-
添加jar包
所需要的有hbase的相关jar, 可以通过hbase软件的lib包下找,也可以通过末尾分享的Demo案例的lib包下复制
还需要Hdfs的相关jar包 ,可以从hadoop的lib目录下找,也可以通过本人 Hadoop-Hdfs中分享的资料中找
找到后build path到jar项目中# hbase的相关jar hbase-annotations-0.98.12.1-hadoop2.jar hbase-checkstyle-0.98.12.1-hadoop2.jar hbase-client-0.98.12.1-hadoop2.jar hbase-common-0.98.12.1-hadoop2-tests.jar hbase-common-0.98.12.1-hadoop2.jar hbase-examples-0.98.12.1-hadoop2.jar hbase-hadoop-compat-0.98.12.1-hadoop2.jar hbase-hadoop2-compat-0.98.12.1-hadoop2.jar hbase-it-0.98.12.1-hadoop2-tests.jar hbase-it-0.98.12.1-hadoop2.jar hbase-prefix-tree-0.98.12.1-hadoop2.jar hbase-protocol-0.98.12.1-hadoop2.jar hbase-rest-0.98.12.1-hadoop2.jar hbase-server-0.98.12.1-hadoop2-tests.jar hbase-server-0.98.12.1-hadoop2.jar hbase-shell-0.98.12.1-hadoop2.jar hbase-testing-util-0.98.12.1-hadoop2.jar hbase-thrift-0.98.12.1-hadoop2.jar high-scale-lib-1.1.1.jar htrace-core-2.04.jar netty-3.6.6.Final.jar
-
从虚拟机中下载hbase的配置文件文件到Hadoop(下图)
-
编写Demo代码
public class HbaseDemo { HBaseAdmin admin;//hbase的admin角色 HTable htable; String TN = "phone";//设置表名 @Before public void init() throws Exception { Configuration conf = new Configuration(); //设置读取zookeeper配置 conf.set("hbase.zookeeper.quorum", "node2,node3,node4"); admin = new HBaseAdmin(conf); htable = new HTable(conf, TN.getBytes()); } /** * 1.创建表 * @throws Exception */ @Test public void creatTable() throws Exception { if (admin.tableExists(TN)) { admin.disableTable(TN); admin.deleteTable(TN); } // 表描述 HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(TN)); HColumnDescriptor cf = new HColumnDescriptor("cf".getBytes()); desc.addFamily(cf); admin.createTable(desc); } /** * 2.插入数据 * @throws Exception */ @Test public void insertDB() throws Exception { //设置row key String rowKey = "1231231312"; Put put = new Put(rowKey.getBytes()); //列族,列名,列下的值 put.add("cf".getBytes(), "name".getBytes(), "xiaohai".getBytes()); put.add("cf".getBytes(), "age".getBytes(), "19".getBytes()); put.add("cf".getBytes(), "sex".getBytes(), "man".getBytes()); htable.put(put); } /** * 3.获取指定单元格信息 * @throws Exception */ @Test public void getDB() throws Exception { String rowKey = "1231231312"; Get get = new Get(rowKey.getBytes());//根据row key取得一行记录数据 get.addColumn("cf".getBytes(), "name".getBytes()); get.addColumn("cf".getBytes(), "age".getBytes()); get.addColumn("cf".getBytes(), "sex".getBytes()); Result rs = htable.get(get); Cell cell = rs.getColumnLatestCell("cf".getBytes(), "name".getBytes());//根据列族+列,获取对应的单元格对象 Cell cell2 = rs.getColumnLatestCell("cf".getBytes(), "age".getBytes()); Cell cell3 = rs.getColumnLatestCell("cf".getBytes(), "sex".getBytes()); // System.out.println(new String(cell.getValue())); System.out.println(new String(CellUtil.cloneValue(cell)));//获取每个单元格的值 System.out.println(new String(CellUtil.cloneValue(cell2))); System.out.println(new String(CellUtil.cloneValue(cell3))); } @After public void close() throws Exception { if (admin != null) { admin.close(); } } }
注意: 如果有不会的方法例如删除操作, 可以通过官方的API手册来查看 ,文档在hbase然健压缩包的docs目录下(图3)
图1
图2
注意: 这里是一行数据 , row key相同的数据在表中都是一行数据!!!
图3
模拟通话数据的产生和处理
执行本步骤操作时,需将上一个Demo创建的表删除 (即先disable表,然后drop表,或者直接运行创建表的方法( 覆盖原表))
然后依次执行下面代码
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
import org.apache.hadoop.hbase.filter.FilterList;
import org.apache.hadoop.hbase.filter.PrefixFilter;
import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import ah.szxy.hbase.Phone.PhoneDetail;
/**
* @author chy
*
*/
public class HBaseDemo {
HBaseAdmin admin;//hbase的admin角色
HTable htable;
String TN = "phone";//设置表名
@Before
public void init() throws Exception {
Configuration conf = new Configuration();
//设置读取zookeeper配置
conf.set("hbase.zookeeper.quorum", "node2,node3,node4")