一、HBase简介
-
BigTable
- 分布式存储系统,起初用于解决典型的互联网搜索问题:
- 建立互联网索引:
- 爬虫持续不断地抓取页面,并把页面每页一行地存储到BigTable里;
- MapReduce计算作业运行在整张表上,生成索引,为网络搜索应用做准备;
- 搜索互联网
- 用户发起网络搜索请求;
- 网络搜索应用查询建立好的索引,从BigTable得到网页;
- 搜索结果提交给用户;
- 建立互联网索引:
- 利用谷歌提出的MapReduce分布式并行计算模型来处理海量数据;
- 使用谷歌分布式文件系统GFS作为底层数据存储;
- 采用Chubby提供协同服务管理;
- 可以扩展到PB级别的数据和上千台机器,具备广泛应用性、可扩展性、高性能和高可用性等特点;
- 分布式存储系统,起初用于解决典型的互联网搜索问题:
-
HBase是一个高可靠、高性能、面向列、可伸缩的分布式数据库,是谷歌BigTable的开源实现,主要用来存储非结构化和半结构化的松散数据,其的目标是处理非常庞大的表,可以通过水平扩展的方式,利用廉价计算机集群处理由超过10亿行数据和数百万列元素组成的数据表;
-
Hadoop生态系统中HBase与其它部分的关系
-
HBase与BigTable的低层技术对应关系
BigTable HBase 文件存储系统 GFS HDFS 海量数据处理 MapReduce Hadoop MapReduce 协同管理服务 Chubby Zookeeper -
Why we need HBase? (已有关系数据库,Hadoop的HDFS与MapReduce)
- 传统的通用关系型数据库无法应对在数据规模剧增时导致的系统扩展性和性能问题(分库分表也不能很好解决);
- 传统关系数据库在数据结构变化时一般需要停机维护;
- HDFS面向批量访问模式,不是随机访问模式;
-
HBase与传统关系数据库的对比
传统关系型数据库 HBase 数据类型 关系模型,具有丰富的数据类型与存储方式 数据存储为未经解释的字符串 数据操作 涉及多表连接 只有简单操作(插入、查询、删除、清空等) 存储模式 基于行模式存储 基于列模式存储(列族) 数据索引 通常可以针对不同列构建复杂的多个索引,以提高数据访问性能 行键(访问 and 扫描) 数据维护 旧值会被覆盖 保留旧版本(时间戳) 可伸缩性 横向扩展困难,纵向扩展(CPU、内存) 水平扩展灵活 -
HBase访问接口
二、HBase数据模型
-
概述
- HBase表是稀疏、多维度、排序的映射表;HBase保存的每个值都是未经解释的字符串,不存在数据类型;
- HBase每一行均有一个行键和任意多列;
- HBase表在水平方向由一个或者多个列族组成,一个列族中可以包含任意多个列,同一个列族里面的数据存储在一起;
- 列族支持动态扩展,无需预先定义列的数量及类型,所有列均以字符串形式存储;HBase执行更新操作不会删除旧的数据版本而是生成一个新的版本,数据版本由时间戳标识;
-
基本概念
- 表:HBase采用表来组织数据,表由行和列组成(列划分为若干个列族)
- 行:HBase表由若干行组成,并由行键标识列
- 族:HBase表被分组成列族(Column Family)的集合、列族是基本的访问控制单元
- 列限定符:列族的数据通过列限定符(or 列)定位
- 单元格:
- 行键、列族、列限定符 → \rightarrow → 单元格
- 单元格存储的数据无数据类型而被视为字节数组byte[]
- 时间戳:数据的多个版本由时间戳标识并存储在单元格;
-
概念视图:
-
物理视图:
-
面向列的存储
-
Ex
- SQL模式
- 行式存储
- 主要面向事务型应用与系统;
- 缺点:取某列数据分析(年龄分布),必须扫描每一行;
- 列式存储主要面向分析型应用与系统;
- 列式存储
- 主要面向分析型应用与系统;
三、HBase实现原理
-
功能组件
- 库函数:链接到每个客户端;
- Master主服务器(one):
- 管理和维护HBase表额分区信息;
- 维护Region服务器列表;
- 分配Region;
- 负载均衡;
- Region服务器(more than one):
- 存储和维护Master分配的Region;
- 处理客户端的读写请求;
客户端不依赖于Master,而是通过Zookeeper来获得Region位置信息,然后从Region服务器上读取数据
-
表、Region
- 开始仅一个Region,之后分裂;
- Region拆分操作非常快,接近瞬间,因为拆分之后的Region读取的仍然是原存储文件,直到“合并”过程把存储文件异步地写到独立的文件之后,才会读取新文件;
- Region大小:每个Region的最佳大小取决于单台服务器的有效处理能力;
-
Region定位
-
元数据表(.META.表)存储Region和Region服务器的映射关系(Region id, RS id);
-
根数据表(-ROOT-表)记录所有元数据的具体位置;只有唯一一个Region;
-
Zookeeper文件记录-Root-表位置;
-
⇒ \Rightarrow ⇒
- 为了加快访问速度,.META.表的全部Region都会被保存在内存;
- 为了加快访问速度,.META.表的全部Region都会被保存在内存;
-
-
客户端访问数据的“三级寻址”
- 为了加速寻址,客户端会缓存位置信息,同时,需要解决缓存失效问题(惰性机制);
- 寻址过程客户端只需要询问Zookeeper服务器,不需要连接Master服务器(记住:ZooKeeper记录-Root-表位置);
四、HBase运行机制
-
HBase系统架构
-
客户端
- 客户端包含访问HBase的接口,同时在缓存中维护着已经访问过的Region位置信息,用来加快后续数据访问过程;
-
Zookeeper服务器
一个集群管理工具,被大量用于分布式计算,提供配置维护、域名服务、分布式同步、组服务.
- 选举出一个Master作为集群的总管,并保证在任何时刻总有唯一一个Master在运行,避免Master的“单点失效”问题;
-
Master
- 主服务器Master主要负责表和Region的管理工作:
- 管理用户对表的增加、删除、修改、查询等操作;
- 实现不同Region服务器之间的负载均衡;
- 在Region分裂或合并后,负责重新调整Region的分布;
- 迁移发生故障失效的Region服务器上的Region;
- 主服务器Master主要负责表和Region的管理工作:
-
Region服务器
- HBase最核心的模块;
- 负责维护分配给自己的Region;
- 响应用户的读写请求;
-
-
Region服务器工作原理
- 用户数据读写过程
- 用户写入数据时,被分配到相应Region服务器去执行;
- 用户数据首先被写入到MemStore和Hlog;
- 只有当操作写入Hlog之后,commit()调用才会将其返回给客户端;
- 当用户读取数据时,Region服务器会首先访问MemStore缓存,如果找不到,再去磁盘上面的StoreFile中寻找;
- 缓存的刷新
-
系统会周期性地把MemStore缓存里的内容刷写到磁盘的StoreFile文件中,清空缓存,并在Hlog里面写入一个标记:
每次刷写都生成一个新的StoreFile文件,因此,每个Store包含多个StoreFile文件;
-
每个Region服务器都有一个自己的HLog 文件,每次启动都检查该文件,确认最近一次执行缓存刷新操作之后是否发生新的写入操作;如果发现更新,则先写入MemStore,再刷写到StoreFile,最后删除旧的Hlog文件,开始为用户提供服务;
-
- StoreFile的合并
- 每次刷写都生成一个新的StoreFile,如果数量太多,会影响查找速度;
- 调用Store.compact()把多个合并成一个;
- 合并操作比较耗费资源,只有数量达到一个阈值才启动合并;
- 用户数据读写过程
-
Store工作原理
- Store是Region服务器的核心
-
HLog工作原理
- 分布式环境必须要考虑系统出错;
- HBase采用HLog保证系统恢复;
- HBase系统为每个Region服务器配置了一个HLog文件,它是一种预写式日志(Write Ahead Log);
- 用户更新数据必须首先写入日志后,才能写入MemStore缓存,并且,直到MemStore缓存内容对应的日志已经写入磁盘,该缓存内容才能被刷写到磁盘***;
- Zookeeper会实时监测每个Region服务器的状态,当某个Region服务器发生故障时,Zookeeper会通知Master
- Master首先会处理该故障Region服务器上面遗留的HLog文件,这个遗留的HLog文件中包含了来自多个Region对象的日志记录
- 系统会根据每条日志记录所属的Region对象对HLog数据进行拆分,分别放到相应Region对象的目录下,然后,再将失效的Region重新分配到可用的Region服务器中,并把与该Region对象相关的HLog日志记录也发送给相应的Region服务器
- Region服务器领取到分配给自己的Region对象以及与之相关的HLog日志记录以后,会重新遍日志记录中的各种操作,把日志记录中的数据写入到MemStore缓存中,然后,刷新到磁盘的StoreFile文件中,完成数据恢复
共用日志优点:提高对表的写操作性能;缺点:恢复时需要分拆日志.
五、HBase应用方案
-
HBase实际应用的性能优化方法
- 行键
- 行键是按照字典序存储的,设计行键要充分利用这个特点;
- 把经常一起读取的数据存储到一块,把最近可能被访问的数据放在一块;
- Ex
- 如果最近写入HBase表的数据是最可能被访问的,可以考虑把时间戳作为行键的一部分,由于是字典序排序,故可以使用Long.MAX_VALUE-timestamp作为行键以保证新写入的数据在读取时可以被快速命中;
- InMemory
- 创建表时通过HColumnDescriptor.setInMemory(true)将表放到Region服务器的缓存中,保证在读取的时候被cache命中;
- Max Version
- 创建表时通过HColumnDescriptor.setMaxVersions(int maxVersions)设置表中数据的最大版本,如果只需要保存最新版本的数据,那么可以设置setMaxVersions(1);
- Time to Live
- 创建表时以通过HColumnDescriptor.setTimeToLive(int timeToLive)设置表中数据的存储生命期,过期数据将自动被删除,例如如果只需要存储最近两天的数据,那么可以设置setTimeToLive(2 * 24 * 60 * 60);
- 行键
-
HBase的性能监视(Pass)
-
Master-status(自带)
-
HBase Master默认基于Web的UI服务端口为16010
-
Master
-
RegionServer
-
-
OpenTSDB
- OpenTSDB可以从大规模的集群(包括集群中的网络设备、操作系统、应用程序)中获取相应的metrics并进行存储、索引以及服务,从而使得这些数据更容易让人理解,如web化,图形化等;
-
Ambari
- Ambari 的作用就是创建、管理、监视 Hadoop 的集群;
-
-
HBase上构建SQL引擎
NoSQL区别于关系型数据库的一点就是NoSQL不使用SQL作为查询语言,至于为何在NoSQL数据存储HBase上提供SQL接口,原因是:
- 易使用
- 减少编码
-
Hive整合HBase
Hive与HBase的整合功能从Hive0.6.0版本已经开始出现,利用两者对外的API接口互相通信,通信主要依靠hive_hbase-handler.jar工具包(Hive Storage Handlers). 由于HBase有一次比较大的版本变动,所以并不是每个 版本的Hive都能和现有的HBase版本进行整合,所以在使用过程中特别注意 的就是两者版本的一致性.
-
Phoenix
Phoenix由Salesforce.com开源,是构建在Apache HBase之上的一个SQL中间层,可以让开发者在HBase上执行SQL查询.
-
构建HBase二级索引
-
HBase只有一个针对行键的索引,访问HBase表的行,只有三种方式:
- 通过单个行键访问;
- 通过一个行键的区间来访问;
- 全表扫描;
-
采用HBase0.92版本之后引入的Coprocessor特性,可以使用其它产品为HBase提供索引功能:
Coprocessor
- Coprocessor提供了两个实现:endpoint and observer;
- endpoint相当于关系型数据库的存储过程,而observer则相当于触发器;
- observer允许在记录put前后作一些处理,故可以在插入数据时同步写入索引表;
- 优点:
- 非侵入性:引擎构建在HBase之上,既没有对HBase进行任何改动,也不需要上层应用做任何妥协;
- 缺点:
- 每插入一条数据需要向索引表插入数据,即耗时是双倍的,对HBase的集群的压力也是双倍的;
-
Hindex二级索引
- 华为开发的纯Java编写的HBase二级索引,兼容Apache HBase 0.94.8
- 特性:
- 多个表索引;
- 多个列索引;
- 基于部分列值的索引;
-
HBase+Redis
- Redis做客户端缓存;
- 将索引实时更新到Redis等KV系统(key-value),定时从KV更新索引到HBase的索引表;
-
HBase+solr
- solr基于Lucene的全文搜索服务器并对其进行了扩展,,提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展并对查询性能进行了优化,并且提供了一个完善的功能管理界面,是一款非常优秀的全文搜索引擎;
-
六、HBase的安装(CentOS 7)
附:zookeeper的安装(不选择hbase自带的zookeeper)
下载Zookper安装包:Apache Zookeeper:apache-zookeeper-3.6.2-bin.tar.gz
解压:sudo tar -zxvf ~/Downloads/apache-zookeeper-3.6.2-bin.tar.gz -C /usr/local
重名名:sudo mv apache-zookeeper-3.6.2-bin.tar.gz zookeeper
修改权限:sudo chown -R hadoop:hadoop zookeeper
配置环境变量:vim ~/.bashrc
export ZOOKEEPER_HOME=/usr/local/zookeeper
export PATH=$PATH:$ZOOKEEPER_HOME/bin
环境变量生效:source ~/.bashrc
修改zookeeper配置文件:
- cd /usr/local/zookeeper/conf
- cp zoo_sample.cfg zoo.cfg
- 设置其中的数据目录及日志存放目录并注册结点及端口号:vim zoo.cfg
dataDir=/usr/local/zookeeper/tmp/data
dataLogDir=/usr/local/zookeeper/tmp/logs
clientPort=2181 # 记住这个端口号,一般都有,不需要编写
server.1=localhost:2888:3888 # 保持跟hadoop配置文件一致即可
- 启动:cd /usr/local/zookeeper/bin、./zkServer.sh start
- 查看状态:./zkServer.sh status
- 关闭:./zkServer.sh stop
附:Hadoop与Hbase兼容性
-
下载HBase安装包:Apache Downloads Mirrors
- hbase-2.3.2-bin.tar.gz (注意与Hadoop版本的对应,本人使用的是3.2.1)(可以通过Xftp远程传输到虚拟机hadoop用户的主目录的Downloads文件下)
-
解压:sudo tar -zxvf ~/Downloads/hbase-2.3.2-bin.tar.gz -C /usr/local
-
重名名hbase安装目录(cd /usr/local):sudo mv hbase-2.3.2 hbase
-
修改hbase目录权限(cd /usr/local):sudo chown -R hadoop:hadoop hbase
-
配置环境变量
- vim ~/.bashrc
export HBASE_HOME=/usr/local/hbase
export PATH=$PATH:$HBASE_HOME/bin # 无需进入安装目录的bin文件夹即可使用相关命令- source ~/.bashrc # 生效
- hbase version # 查看版本
-
伪分布式配置(注意是否有JAVE_HOME环境变量、jdk、hadoop)
- cd到hbase安装目录的conf文件夹
- vim hbase-env.sh
export JAVA_HOME=/usr/lib/jvm/jdk1.8.0_271
export HBASE_CLASSPATH=/usr/local/hbase/conf
export HBASE_MANAGES_ZK=true # 默认用hbase自带的zookeeper- 配置hbase-site.xml
<configuration> <property> <name>hbase.rootdir</name> <value>hdfs:/localhost:9000/hbase</value> <!--主机名或主机ip,注意与hadoop对应--> </property> <property> <name>hbase.zookeeper.quorum</name> <value>localhost</value> <description>The directory shared by RegionServers.</description> </property> <property> <name>hbase.cluster.distributed</name> <value>true</value> </property> <property> <name>hbase.unsafe.stream.capability.enforce</name> <value>false</value> </property> </configuration>
- 启动(注意开启顺序):start-dfs.sh、zkServer.sh start(不使用hbase自带的zookeepr)、start-hbase.sh、jps
- 输入jps需要看到的进程:HMaster、HResionServer、QuorumPeerMain、NameNode、DataNode、SecondaryNameNode、jps
- 停止:stop-hbase.sh、zkServer.sh stop(不使用hbase自带的zookeepr,根status查看zookeeper状态)、stop-dfs.sh
七、编程实战-HDFS Java API
附:HBase部分shell命令
- create ‘tablename’,‘rowkey’
- list
- put ‘tablename’,‘rowkey’,‘rowFamily:rowName’,‘value’
- get ‘tablename’,‘rowkey’, {COLUMN=>‘rowFamily:rowName’}
- enable ‘tablename’
- disable ‘tablename’
- drop ‘tablename’(删除前需disable)
apache_hbase_reference_guide.pdf
-
目标:如何通过HBase Java API实现HBase表的创建、单元格数据的插入更新以及获取单元格数据
-
What we will do?
- 创建一个学生信息表,用来存储学生姓名(姓名作为行键,并且假设姓名不会重复)以及考试成绩,其中,考试成绩是一个列族,分别存储了各个科目的考试成绩。
-
Step
- 新建Maven项目,配置依赖(如果无hadoop-auth依赖,会出现异常:NoSuchMethodError: org.apache.hadoop.securityadoopKerberosName.setRuleMechanism)
<dependencies> <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-client --> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <version>3.2.1</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-auth</artifactId> <version>3.2.1</version> <!-- NoSuchMethodError: org.apache.hadoop.securityadoopKerberosName.setRuleMechanism --> </dependency> <dependency> <groupId>org.apache.hbase</groupId> <artifactId>hbase-client</artifactId> <version>2.3.2</version> </dependency> <dependency> <groupId>org.apache.hbase</groupId> <artifactId>hbase</artifactId> <version>2.3.2</version> <type>pom</type> </dependency>
-
新建类并设置属性
protected static Configuration configuration; protected static Connection connection; protected static Admin admin;
-
编写init()方法
private static void init(){ configuration = HBaseConfiguration.create(); configuration.set("hbase.rootdir","hdfs://localhost:9000/hbase"); try { connection = ConnectionFactory.createConnection(configuration); admin = connection.getAdmin(); } catch (IOException e) { e.printStackTrace(); } }
-
编写createTable()方法
public static void createTable(String myTableName, String[] colFamily) throws IOException { TableName tableName = TableName.valueOf(myTableName); if(admin.tableExists(tableName)){ System.out.print("table exists"); }else{ TableDescriptorBuilder tableDescriptor = TableDescriptorBuilder.newBuilder(tableName); for(String str:colFamily){ ColumnFamilyDescriptor family = ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(str)).build(); tableDescriptor.setColumnFamily(family); } admin.createTable(tableDescriptor.build()); } }
-
编写insertData()方法
public static void insertData(String tableName, String rowKey, String colFamily, String col, String val) throws IOException { Table table = connection.getTable(TableName.valueOf(tableName)); Put put = new Put(rowKey.getBytes()); put.addColumn(colFamily.getBytes(), col.getBytes(), val.getBytes()); table.put(put); table.close(); }
-
编写getData方法
public static void getData(String tableName, String rowKey, String colFamily, String col) throws IOException { Table table = connection.getTable(TableName.valueOf(tableName)); Get get = new Get(rowKey.getBytes()); get.addColumn(colFamily.getBytes(), col.getBytes()); Result result = table.get(get); System.out.println(new String(result.getValue(colFamily.getBytes(), col.getBytes()))); table.close(); }
-
编写close()方法
private static void close(){ try{ if(admin != null){ admin.close(); } }catch(IOException e){ e.printStackTrace(); } }
-
main方法:调用上述编写的方法即可
- 新建Maven项目,配置依赖(如果无hadoop-auth依赖,会出现异常:NoSuchMethodError: org.apache.hadoop.securityadoopKerberosName.setRuleMechanism)
-
异常:
- NoSuchMethodError: org.apache.hadoop.securityadoopKerberosName.setRuleMechanism
- 解决方法:添加依赖hadoop-auth
Source:Hadoop Course PPT of NEU