人工智能作为当前最热门的技术,其根本上离不开大数据的支持。如果把人工智能比喻成一个神经网络,那么数据则是在这个神经网络中用来传递信息的化学物质,没有信息传递的神经网络显然不名一文,因此大数据扮演着人工智能基石的角色。
Hadoop生态系统的HDFS和MapReduce分别为大数据提供了存储和分析处理能力,但是对在线实时的数据存取则无能为力,而HBase作为Apache顶级项目,弥补了Hadoop的这一缺陷,满足了在线实时系统低延时的需求。目前HBase在各大互联网公司几乎都有应用,前景广阔。
HBase的数据模型与传统数据库相比更加灵活,使用之前无须预先定义一个所谓的表模式(Schema),同一个表中不同行数据可以包含不同的列,而且HBase对列的数量并没有限制。
当然如果一行包括太多的列,就会对性能产生负面影响。HBase很适合存储不确定列、不确定大小的半结构化数据。
逻辑模型
HBase是一个键值(key-value)型数据库。HBase数据行可以类比成一个多重映射(map),通过多重的键(key)一层层递进可以定位一个值(value)。因为HBase数据行列值可以是空白的(这些空白列是不占用存储空间的),所以HBase存储的数据是稀疏的。
下面解释一下与HBase逻辑模型相关的名词。
(1)表(table):类似于关系型数据库中的表,即数据行的集合。表名用字符串表示,一个表可以包含一个或者多个分区(region)。
(2)行键(row key):用来标识表中唯一的一行数据,以字节数组形式存储,类似于关系型数据库中表的主键(不同的是从底层存储来说,行键其实并不能唯一标识一行数据,因为HBase数据行可以有多个版本。
但是,一般在不指定版本或者数据时间戳的情况下,用行键可以获取到当前最新生效的这行数据,因此从用户视图来说,默认情况下行键能够标识唯一一行数据),同时行键也是HBase表中最直接最高效的索引,表中数据按行键的字典序排序。
(3)列族(column family):HBase是一个列式存储数据库,所谓列式就是根据列族存储,每个列族一个存储仓库(Store),每个Store有多个存储文件(StoreFile)用来存储实际数据。
(4)列限定符(column qualifier):每个列族可以有任意个列限定符用来标识不同的列,这个列也类似于关系型数据库表的一列,与关系型数据库不同的是列无须在表创建时指定,可以在需要使用时动态加入。
(5)单元格(cell):单元格由行键、列族、列限定符、时间戳、类型(Put、Delete等用来标识数据是有效还是删除状态)唯一决定,是HBase数据的存储单元,以字节码的形式存储。
(6)版本(version):HBase数据写入后是不会被修改的,数据的Put等操作在写入预写入日志(Write-Ahead-Log,WAL)(类似于Oracle Redo Log)后,会先写入内存仓库(MemStore),同时在内存中按行键排序,等到合适的时候会将MemStore中的数据刷新到磁盘的StoreFile文件。
因为数据已经排序,所以只需顺序写入磁盘,这样的顺序写入对磁盘来说效率很高。由于数据不会被修改,因此带来的问题就是数据会有多个版本,这些数据都会有一个时间戳用来标识数据的写入时间。
(7)分区(region):当传统数据库表的数据量过大时,我们通常会考虑对表做分库分表。例如,淘宝的订单系统可以按买家ID与按卖家ID分别分库分表。同样HBase中分区也是一个类似的概念,分区是集群中高可用、动态扩展、负载均衡的最小单元,一个表可以分为任意个分区并且均衡分布在集群中的每台机器上,分区按行键分片,可以在创建表的时候预先分片,也可以在之后需要的时候调用HBase shell命令行或者API动态分片。
接下来以用户行为管理系统为例,假设现在需要用HBase来存储电商系统的用户行为数据,表s_behavior用来存储这些行为数据,两个列族pc和ph分别存储电脑端与手机端的行为数据,列v用来存储用户浏览记录,列o用来存储用户的下单记录,图1-1描述了这个表的HBase逻辑视图。
图1-1 HBase逻辑视图
HBase按行键的字典序存储数据行,其数据存储层级可以用如下的一个Java中的Map结构类比:
Map<RowKey,Map<Column Family,Map<Column Qualifier,Map<Timestamp,Value>>>>
如下代码可以用来定位到某个键值对(或者说单元格):
map.get("12345_1516592489001_1").get("pc").get("v").get("1516592489001");
代码清单3-1的JSON字符串同样近似地描述了这个多维的Map。
代码清单3-1 HBase逻辑视图类比JSON
{
"12345_1516592489001_1": {
"pc": {
"pc:v": {
"1516592489000": "1001",
"1516592489001": "1002"
},
"pc:o": {
"1516592489000": "1001"
}
},
"ph": {
"ph:v": {
"1516592489001": "1002"
}
}
},
"12345_1516592490000_2": {
"ph": {
"ph:v": {
"1516592490000": "1004"
}
}
}
}
物理模型
HBase是一个列式存储数据库,数据按列族聚簇存储在存储文件(StoreFile)中,空白的列单元格不会被存储,图1-2描述了HBase表的物理存储模型。
(1)HBase中表按照行键的范围被划分为不同的分区(Region),各个分区由分区服务器负责管理并提供数据读写服务,HBase主节点进程(HMaster)负责分区的分配以及在集群中的迁移。
(2)一个分区同时有且仅由一个分区服务器提供服务。当分区增长到配置的大小后,如果开启了自动拆分(也可以手动拆分或者建表时预先拆分),则分区服务器会负责将这个分区拆分成两个。
每个分区都有一个唯一的分区名,格式是“<表名,startRowKey,创建时间>”。一个分区下的每个列族都会有一个存储仓库(Store),因此一个表有几个列族,那么每个分区就会有几个存储仓库。
(3)每个Store(存储仓库)有且仅有一个MemStore(内存仓库),但是可以有多个存储文件。当分区服务器处理写入请求时,数据的变更操作在写入WAL后,会先写入MemStore,同时在内存中按行键排序。
当MemStore到达配置的大小或者集群中所有MemStore使用的总内存达到配置的阈值百分比时,MemStore会刷新为一个StoreFile(存储文件)到磁盘,存储文件只会顺序写入,不支持修改。
(4)数据块(block)是HBase中数据读取的最小单元,StoreFile由数据块组成,可以在建表时按列族指定表数据的数据块大小。如果开启了HBase的数据压缩功能,数据在写入StoreFile之前会按数据块进行压缩,读取时同样对数据块解压后再放入缓存。理想情况下,每次读取数据的大小都是指定的数据块大小的倍数,这样可以避免一些无效的IO,效率最高。
图1-2 HBase物理视图
图1-3描述了上面提到的表和分区等各模块分别由HBase的哪些进程负责管理。
图1-3 HBase模块交互图
(1)HMaster:负责监控集群中所有的分区服务器进程,负责所有元数据的更新(如分区由哪个分区服务器提供服务)。
(2)HMaster同时负责分区在分区服务器中的负载均衡,在一个分布式集群中,HMaster进程通常与Hadoop的NameNode运行在同一个节点,每个集群会部署至少两个HMaster节点,一个作为活跃节点提供服务,另一个作为备用节点提供快速的灾备切换,保证集群的高可用。
(3)HRegionServer:管理其负责的分区,处理分区的读写请求、分区增大的拆分(split)以及分区的压缩(compact)。HBase客户端根据元数据(客户端从HMaster获取到元数据后会缓存在本地,当分区操作抛出特定异常后会从HMaster刷新缓存)定位到操作数据对应的分区所在分区服务器之后,HBase客户端对数据的读写就直接与分区服务器交互,因此对分区的读写不会对HMaster造成压力。
HRegionServer进程通常与Hadoop的DataNode运行在同一个节点,这样对数据的读取可以尽量做到本地读取,减少网络请求。
(4)WAL:默认情况下一个分区服务器仅有一个WAL。HBase客户端数据请求操作会先写入WAL文件再写入内存仓库MemStore,这样当分区服务器宕机重启的时候,可以用WAL来恢复分区服务器的状态(如MemStore中更新的数据没有刷新到StoreFile持久化,则分区服务器启动时需要通过WAL重做(replay)数据更新来恢复)。
如果数据操作写入WAL失败,则这个更新数据的请求也会失败。由于一个分区服务器只有一个WAL,对WAL的写入必须是顺序写入,这里可能导致性能瓶颈,HBase1.0引入了mutiWAL的支持,mutiWAL允许分区服务器并发地写入多个WAL,这个并发来自于对WAL更新按分区分组,也就是说不同分区可以支持并发写多个WAL,因此mutiWAL无法提升对单个分区的高并发更新的性能。
(5)Store:每个分区的每个列族对应一个存储仓库,一个存储仓库包含一个MemStore和多个存储文件。当MemStore的大小达到了配置的阈值后,MemStore会刷新为一个存储文件,存储文件顺序写入,不支持修改,以HFile的形式存储在Hadoop的DataNode中。
(6)MemStore:MemStore位于分区服务器的堆内存,数据在写入MemStore的时候即会按行键排序,这样刷新到存储文件的时候可以直接顺序写入,提高写性能。同时,MemStore作为一个内存级缓存,能够提供对新写入数据的快速访问(新插入数据总是比老数据使用频繁)。
彭旭 著
本书以精练的语言介绍HBase的基础知识,让初学者能够快速上手使用HBase,对HBase的核心思想(如数据读取、数据备份等)和HBase架构(如LSM树、WAL)有深入的分析,让有经验的HBase开发人员也能够循序渐进地深入理解HBase源码,以便更好地去调试和解决线上遇到的各种问题。本书更加专注HBase在线实时系统的调优,让HBase集群响应延迟更低,能够更好地为在线实时系统服务。
邀请10名好友关注异步图书10天,即可免费获得异步新书。
长按二维码,可以关注我们哟
每天与你分享IT好文。
点击阅读原文,购买《HBase入门与实践》
阅读原文
网友评论