HBase 体系结构
HBase 的系统模型
简介
NoSQL
Hbase 是一种 NoSQL 数据库,其实它更是一个分布式数据库,从技术上讲,相较于数据库,HBase更像是一个数据存储。因为HBase缺少很多关系型数据库的特性,例如有类型的列,二级索引,触发器,高级的查询语句。
但是HBase提供了很多支持线性及模块化的扩展。HBase可以通过增加RegionServer来扩展集群。如果一个集群的RegionServer的个数从10增加到20,那么他的存储和处理能力都增加一倍。关系型数据库,虽然也可以扩展,但都是单节点的扩展。但是单点的数据库,如果要提高性能,还需要硬件和存储性能的提升。HBase的特性如下:
- 强一致性的读写:HBase 不是最终一致性的数据库,这个特性很适合用户高速的数据收集。
- 自动分片:HBase的表分布在集群的region上,随着数据的增多,region会自动split成两个region。
- 基于Zookeeper保证RegionServer的高可用。
- HBase基于HDFS的文件存储系统,本身就是一个分布式的文件系统,保证了文件的多备份,高可用,不丢失等问题。
- MapReduce:支持基于MapReduce的大量任务并行读取。
- Java Client API:提供了java API,可以很方便的使用java接入。
- Thrift/REST API:同时也支持 Thrift和Rest非java语言的接入。
- Block Cache and Bloom Filter:HBase在读取数据是支持Block Cache缓存及依据Bloom 过滤器实现的判断 rowkey 可能存在和一定不存在的机制,优化查询效率。
- 可操作性的控制界面:HBase提供了内置的web话的管理界面。
使用场景
- 1,数据量较大。如果需要处理数亿计的数据时,HBase是一个很好的备选方案,如果只有上千或者上万条数据,使用关系型数据库可能是更好的选择。因为数据量太少时,数据被分散到多个节点上反而降低了查询和存储效率。
- 2,确定在业务处理的过程中没有使用RDBMS 中的特殊特性(例如 有类型的列,二级索引,事务,高级的查询语言)。一个基于RDBMS的应用,需要确认使用没有使用关系型数据库的高阶特性才能移动到HBase上存储。
- 3,确保有足够的硬件支持,HDFS要求至少有5个DataNode和一个NameNode。至少需要6台机器。虽然HBase可以使用stand-alone模式,但是这个最好只在开发环境使用,生产环境最好部署为分布式的系统。
HBase 与 Hadoop/HDFS的区别
HDFS是一个分布式的文件系统,比较适合存储大文件,他的文档指出,他不是通用的文档系统,因为其无法提供快速文件或记录查找服务。HBase基于HDFS构建,可以提供大数据表中记录的快速查找。HBase内部将数据存储到可索引的StoreFiles文件中,这些文件存储在HDFS上。可以通过查看HBase的数据模型了解。
目录表
目录表hbase:meta作为一个table存在于HBase中,在在使用list
查询时,返回结果会将其排除在外。不做展示。
hbase:meta
hbase:meta表保存了集群的所有region信息,hbase:meta的位置信息在zookeeper的meta-region-server
中存储。hbase:meta的表结果如下:
Key
key的结构为(table,region start key,region id)三个部分组成。
Values
- info:regioninfo,存储这Region对应的HRegionInfo的序列化信息。
- info:server ,存储负责管理当前Region的RegionServer的server:port新信息。
- info:serverstartcode,存储这RegionServer开始负责这个region的时间。
当表的region发生split时,将会再创建两列info:splitA和info:splitB。这两列代表这个被分开的region。这些列信息也会反序列化为HRegionInfo 实例。在split完成之后,最终这一行数据会被删除。
空的key用来标注标的开始和结束,如果一个region以空key开始,那么这个region是表的第一个region,如果一个region以空key开始和结尾,那么这个表,只有当前一个region
客户端 Client
HBase 客户端通过请求hbase:meta 来获取集群的的RegionServer集合。在定位需要查询的region集合后,客户端直接连接管理Region的RegionServer,发送读写请求。这些信息缓缓在client端,后续的请求不需要在进行上面的处理。如果RegionServer挂了,client会重新请求catalog tables;
连接集群
具体的连接API可参考链接:https://hbase.apache.org/book.html#client_dependencies
1.0.0版本 API
用户从ConnectionFactory
获取连接对象Connection
,然后从连接对象中获取Table,Admin,RegionLocator等对象,在使用完成后,需要关闭连接,并确认释放Connection对象。 Connections
是一个很重的对象,但是线程安全,s顒我们在应用中创建一个连接即可。Table,Admin和RegionLocator这些对象是轻量的,在使用时创建,使用完成销毁即可。详细API;
1.0.0版本之前的API
创建HTable是在HBase1.0.0之前的连接方式,Table是非线程安全的,Table只能给一个线程使用,HBaseConfiguration 对象是比较推荐的使用方式,他维持着到zookeeper一级RegionServer的连接,示例如下:
HBaseConfiguration conf = HBaseConfiguration.create();
HTable table1 = new HTable(conf, "myTable");
HTable table2 = new HTable(conf, "myTable");
而不是每个表都创建一个HBaseConfiguration
HBaseConfiguration conf1 = HBaseConfiguration.create();
HTable table1 = new HTable(conf1, "myTable");
HBaseConfiguration conf2 = HBaseConfiguration.create();
HTable table2 = new HTable(conf2, "myTable");
更多的连接信息可以参照ConnectionFactory。
如果应用要求多线程访问HBase,可以提前创建一个Connection
// Create a connection to the cluster.
Configuration conf = HBaseConfiguration.create();
try (Connection connection = ConnectionFactory.createConnection(conf);
Table table = connection.getTable(TableName.valueOf(tablename))) {
// use table as needed, the table returned is lightweight
}
异步客户端
在HBase2.0引入了可以异步处理HBase的API,我们可以从ConnectionFactory
获取一个AsyncConnection
,然后获取一个异步的table实例访问HBase。异步table中,大部分的接口和Table的意思相同,唯一的区别是返回结果使用CompletableFuture
包裹。因为是异步的,所有table不需要显示的关闭,而且table也是线程安全的。但是在做扫描时还是有些不同的:
- getSanner方法返回
ResultScanner
,工作方式和老的ClientAsyncPrefetchScanner
类似。 - scanAll接口一次返回所有的结果,这个方法的初衷是一次返回所有需要的少量数据
- 观察者模式,scan方法需要传入一个
ScanResultConsumer
作为参数,当查询完成后,数据将数据发送给消费者进行消费。
AsyncTable中的接口是模板话的,模板参数确定了使用ScanResultConsumerBase
哪个实现类完成扫描结果的消费。目前有连个消费实现类ScanResultConsumer
和AdvancedScanResultConsumer
。
- ScanResultConsumer需要一个单独的线程池处理返回的
CompletableFuture
。使用的单独的线程池,释放了RPC线程,所以callback不需要做任何其他额外的操作,这种比较适合callback不太快的扫描。 - AdvancedScanResultConsumer执行callback的处理任务在框架的线程里,他不允许做比较耗时的操作,也不允许block,因为这可能影响矿建的性能。他主要为高阶用户提供的,用来自己编写更高性能的消费者。
Asynchronous Admin
我们可以从ConnectionFactory
获取一个AsyncConnection
,然后获取一个AsyncAdmin
。getAdmin有两个方法,其中一个方法需要传入一个线程池,用来执行callback。这个方法用来给普通用户使用的,另外一个没有线程池的方法使用框架的线程执行callback,他同样不允许在callback中执行耗时的操作,这个也是提供给高阶开发者的。
Master
HMaster是一个Master Server的实现,主要负责监控所有的RegionServer实例,提供元数据修改的接口。在一个分布式集群中,主节点已NameNode的角色运行。当集群中存在多个Masters时,所有的Master竞争成为cluster真正的Master,如果一个活跃的Master与zookeeper断链,剩下的Masters竞争成为j群的Master。
RegionServer
HRegionServer 为RegionServer的一个实现,他负责管理Region,在分布式集群中,他的角色相当于DataNode。
多线程处理任务
他的主要功能在后台启动多种线程,管理Region。其中的线程的分类如下:
- CompactSplitThread,检查Region的split,处理minor 镜像的合并;
- MajorCompactionChecker 检查major 合并;minor 合并,只合并部分的HFile,无法做到整体合并,这样就无法清理delete的数据,所以需要major合并。
- MemStoreFlusher,HBase基于LSM实现的,其分为内存部分和磁盘部分,MemStore达到阈值后,需要将数据刷新到StoreFiles中
- LogRoller 检查WAL(Hlog)是否过期,是否删除,HBase为了保证高可用,在写入内存时,会将数据写入WAL中,这样需要定期的检查WAL的数据是否已经存入磁盘,如果已经存入,则需要清理WAL。
Block Cache
为了加快数据的读取速度,HBase设计了Block Cache 其中Block的大小为64k,存储这磁盘上连续存储的KV数据。Block Cache存在两种实现方式:LruBlockCache和BucketCache。默认为LruBlockCache
- LruBlockCache,是JVM的堆上缓存,需要设置working set size。
- BucketCache,是一个非堆缓存,存在三种模式,分别为offheap,file和mmaped file。
Region
Region是分布式表的最基础元素。当数据表超过一定大小会水平切分,分裂成两个Region。Region是集群负载均衡的基本单位,Region由一个或者多个store组成,store的个数取决于列簇的个数。每个Store由一个MemStore和一个或多个HFile组成,数据会首先写入MemStore中,当MemStore写满后,系统会将数据异步flush到HFile中。随着数据的不断写入,HFile的数量会不断增多,这时候系统会执行Compact操作合并文件。