Hbase基础
- NoSQL非关系型数据库
- NoSQL的特点
- NoSQL数据库类型简介
- Hbase概述
- HBase列式数据模型简介
- 数据模型概述
- 数据模型的基本概念
- 概念视图
- 物理视图
- Hbase安装
- Hbase的主要组件
- Hbase的架构组成
- HRegionServer详解
- Hbase的读写流程
- 1.客户端寻找HRegionServer,以及缓存位置信息
- 2.写数据流程
- 3 读数据流程
NoSQL非关系型数据库
虽然关系型数据库系统很优秀,但是在大数据时代,面对着快速增长的数据规模和一件复杂的数据模型,关系型数据库已经无法对象很多数据库处理任务.NoSQL凭借着易扩展,大数据量,高性能以及灵活的数据模型得到了广泛的应用
1.NoSQL的起因
NoSQL泛指非关系型数据库,随着Web2.0网站的星期,传统的关系型数据库(Mysql,Oracle)已经无法适应Web2.0网站,NoSQL的产生就是喂了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据领域.
1. 无法满足对海量数据的高效率存储和访问的需求
2. 无法满足对数据库的高可扩展性和高可用性的需求
3. 关系数据库无法存储和处理半结构化/非结构化数据
4. 关系数据库的事务特性对 Web 2.0 是不必要的
5. Web 2.0 无须进行复杂的 SQL 查询,特别是多表关联查询
NoSQL的特点
关系型数据库中的表都是存储一些格式化的数据结构,每个元组字段的组成都一样,即使不是每个元组都与要所有的字段,但是,数据库还是回为每个元组分配所有的字段,这样,便于表和表之间进行链接等操作.
NoSQL是一种不同于关系型数据库的数据库管理系统设计方式,是对非关系型数据库的统称
它采用的数据库模型不是非关系型数据库的关系模型,而是类似键值,列族,文档等的数据模型.
打破了长久以来关系型数据库的ACID 原子性 一致性 隔离性 持久性 的局面
它数据存储不需要固定的表结构 ,每个元组都可有不一样的字段,每个元组可以根据需要增加一些自己的键值对,这样的话可以不会局限于固定的结构 ,减少了一些时间和空间的开销
NoSQL再面对海量数据的存取上具备关系型数据库无法比拟的性能优势
- 灵活的可扩展性
多年以来,数据库的负载需要增加时,只能依赖与纵向扩展,也就是买更强的服务器,而不是依赖于横向扩展,将数据库分布在多台主机上.
NoSQL 在数据设计上就是要能够透明地利用新结点进行扩展。
NoSQL 数据库种类繁多,但是一个共同的特点是都去掉了关系型数据库的关系型裝性。
数据之间无关系,非常容易扩展,从而也在架构层面上带来了可横向扩展的能力。 - 大数据量和高性能
在大数据时代被存储的数据的规模极大的增加了,虽然关系型数据库的能力也随着数据规模的增加而增长,但是实际上的性能已经午发满足一些企业的需求
而NoSQL数据库具有非常高的读写性能,尤其在大数据量下,能同样保持高性能,得益于NoSQL数据库的无关系性. - 灵活的数据模型,可以处理半结构化/非结构化的大数据
对于大型的生产性的关系型数据库来就讲,变更数据模型是一件很困难的事情.即使是对一个数据模型做很小的改动,也许就需要停机或者降低服务水平,
NoSQL数据库在数据模型约束方面更加宽松,不用实现为储存的数据建立字段,随时可以储存自定义的数据格式.
NoSQL数据库可以让应用程序在一个数据元素里储存任何结构的数据,包括半结构化和非结构化数据.
NoSQL数据库类型简介
总的来说NoSQL数据库可以划分为四种类型:键值数据库,列式数据库,文档数据库和图形数据库
1.键值数据库
键值数据库你可以把它理解为一个分布式的Hashmap,支持SET/GET元操作,它使用一个哈希表,表中的Key用来定位Value,就是储存和检索具体的Value
数据库不能对Balue进行索引和查询.Value可以用来存储任意类型的数据,包括基本数据类型和对象等,
键值存储的值也可以是比较复杂的结构,比如一个新的键值对封装成的一个对象.
一个完整的分布式键值数据库会将Key按照策略尽量均匀的散列在不同的节点上,其中,一致性哈希函数是比较优雅的散列策略,它可以保证当某个节点挂掉的时候,只有改节点的数据需要重新散列.
在存在大量写操作的情况下,键值数据库可以比关系型数据库具有更明显的性能优势,这是因为关系型数据库需要建立索引来加速查询,当存在大量写操作时,索引会频繁的发生更新,从而维护索引需要付出的代价是很大的.键值数据库具有良好的伸缩性,理论上可以进行无限扩容,
键值数据库可以进一步划分为内存键值数据库和持久化键值数据库.
①.内存键值数据库把数据保存咋内存中,比如说如 Memcached 和 Redis
②.持久化键值数据库把数据保存在磁盘中,如 BerkeleyDB、Voldmort 和 Riak。
键值数据库也有自己的局限性,主要是条件查询
如果只对部分值进行查询或者更新,效率会比较低下,在使用键值数据库的时候,应该尽量避免夺标关联查询,还有一点,键值数据库发生故障不支持事务回滚操作,所以无法支持事务.
大多数键值数据库通常不会关心存入的Value是什么,在它看来,只是一堆字节,所以开发者也无法通过Value的某些属性来获取整个Value2.列式数据库
列式数据库起源于 Google 的 BigTable,其数据模型可以看作是一个每行列数可变的数据表, 它可以细分为 4 种实现模式,如图
其中,Super Column Family 模式可以理解为 maps of maps,例如,可以把一个作者和他的专辑结构化地存成 Super Column Family 模式,如图所示。
在行式数据库查询时,无论需要哪一列,都需要将每一行都扫描完,
PID | Pname | AGE |
1 | 张三 | 18 |
2 | 李四 | 56 |
3 | 王五 | 20 |
如果想对表格中的age=18的人员的信息,数据库会从上到下,从左到右扫描表,最终返回age=18的人员信息.
在查询的过程中如果给某些特定字段建立索引,将会显著的提高查询速度,但是索引会带来额外的开销,而且数据库仍然在扫描所有的列
而列式数据库可以分别储存每个列,从而在列数较少的情况下更快的进行扫描
列式存储的话每一列都有一个索引,索引将行号映射到数据,列式数据库将数据映射到行号,采用这种方式计数变得更快,很容易就可以查询到某个项目的爱好人数, 并且每个表都只有一种数据类型,所以单独善储列也利于优化压缩。
列式数据库能够在其他列不受影响的情况下,轻松添加一列,但是如果要添加一条记录时就需要访问所有表,所以行式数据库要比列式数据库更适合联机事务处理过程(OLTP),因为 OLTP 要频繁地进行记录的添加或修改。
列式数据库更适合执行分析操作,如进行汇总或计数。实际交易的事务,如销售类,通常会选择行式数据库。列式数据库采用高级查询执行技术,以简化的方法处理列块(称为“批处理”),从而减少了 CPU 使用率。
- 文档数据库
文档数据库是通过键来定位一个文档的,所以是键值数据库的一种衍生品。在文档数据库中,文档是数据库的最小单位。文档数据库可以使用模式来指定某个文档结构。
文档数据库是 NoSQL 数据库类型中出现得最自然的类型,因为它们是按照日常文档的存储来设计的,并且允许对这些数据进行复杂的查询和计算。
尽管每一种文档数据库的部署各有不同,但是大都假定文档以某种标准化格式进行封装,并对数据进行加密。
文档格式包括 XML、YAML、JSON 和 BSON 等,也可以使用二进制格式,如 PDF、Microsoft Office 文档等。一个文档可以包含复杂的数据结构,并且不需要采用特定的数据模式,每个文档可以具有完全不同的结构。
文档数据库既可以根据键来构建索引,也可以基于文档内容来构建索引。基于文档内容的索引和查询能力是文档数据库不同于键值数据库的主要方面,因为在键值数据库中,值对数据库是透明不可见的,不能基于值构建索引。
文档数据库主要用于存储和检索文档数据,非常适合那些把输入数据表示成文档的应用。从关系型数据库存储方式的角度来看,每一个事物都应该存储一次,并且通过外键进行连接,而文件存储不关心规范化,只要数据存储在一个有意义的结构中就可以。. - 图形数据库
图形数据库以图论为基础,用图来表示一个对象集合,包括顶点及连接顶点的边。图形数据库使用图作为数据模型来存储数据,可以高效地存储不同顶点之间的关系。
图形数据库是 NoSQL 数据库类型中最复杂的一个,旨在以高效的方式存储实体之间的关系。
图形数据库适用于高度相互关联的数据,可以高效地处理实体间的关系,尤其适合于社交网络、依赖分析、模式识别、推荐系统、路径寻找、科学论文引用,以及资本资产集群等场景。
图形数据库在处理实体间的关系时具有很好的性能,但是在其他应用领域,其性能不如其他 NoSQL 数据库。
典型的图形数据库有 Neo4J、OrientDB、InfoGrid、Infinite Graph 和 GraphDB 等。有些图形数据库,如 Neo4J,完全兼容 ACID 特性。
Hbase概述
1.Hbase是基于Apache Hadoop的面向列(列族)的NoSQL数据库,是Google的BigTable的开源实现
2.Hbase是一个针对半结构化数据的开源的,多版本的,可伸缩的,高可靠的,高性能的,分布式的和面向列的动态模式数据库
3.Hbase和传统的关系型数据库不同,他是采用了BigTable的数据模型增强的系数排序映射表(Key/Value),其中键由行关键字,列关键字,和时间戳构成的.
4.Hbase提供了对大规模数据的随机,实时读写访问.—>内存
5.Hbase的目标是储存并处理大型的数据,也就是仅仅使用普通的硬件配置,就能够处理上千亿的行和几百万的列所组成的超大型数据库。
6.Hadoop是一个高容错,高延时的分布式文件系统和高并发的批处理系统,不适用提供实时计算,而Hbase是可以提供实时计算(占用大量内存)的分布式数据库,数据被保存在HDFS上,由HDFS保证他的高容错性.
7.Hbase上的数据是以二进制流(byte[])的形式存储在HDFS的数据块中的,但是Hbase存储的数据对于HDFS来说是透明的
8.Hbase可以直接使用本地文件系统,也可以使用Hadoop的HDFS
9.Hbase中保存的数据可以使用MapReduce来处理,将数据存储和并行计算有机的结合在一起.
10.Hbase是按照列族进行数据存储的.每个列族会包括许多的列,并且这些列是经常需要同时处理的属性,也就是说Hbase把经常需要一起处理的列构成列族一起存放,从而避免了需要对这些列进行重构的操作,
11.Hbase在充分利用列式存储优势的同时,通过列族减少列连接的需求
HBase列式数据模型简介
数据模型概述
Hbase是一个稀疏,多维度,有序的映射表
这张表的每个单元是通过行键,列族,列限定符和时间戳组成的索引来标识的.
每个单元的值是一个未经过解释的二进制数据(byte[]),没有数据类型,当用户在表中存储数据时,每一行都有一个唯一的行键和任意多的列
表的每一行由多一个或者多个列族组成,一个列族可以有任意多个列
在同一个表模式下,每行中包含的列族是相同的,也就是列族的名称和个数时相同的,但是每行中每个列族中包含的列的个数可以不同
Hbase中的同一个列族中的数据储存在一起,列族支持动态扩展,可以随时添加新的列,不需要提前定义列的数量,
所以,尽管在表里的每一行拥有相同的列族,但是可能有不同的列,正是因为如此,对于整个映射表的每行数据而言,有些列的值就是空的,所以Hbase的表是稀疏的.
Hbase执行更新操作的时候,不会删除旧版本的数据,而是生成一个新的版本,原有的版本仍然保留.
用户可以对Hbase保留的版本数量进行设置,在查询数据库的时候,用户可以选在获取距离某个时间点最近的版本,或者一次性的获取所有的版本.
如果查询的时候不提供时间戳,那么系统就会返回离当前时间最近的那个版本的数据.
Hbase提供了两种数据版本的回收方式:一种是保存数据的最后三个版本;另一种是保存最近一段时间的版本,比如说最近一个月
数据模型的基本概念
Hbase中的数据被存储在表中,具有行和列,是一个多维的映射结构.
1.表(table)—>以前的数据库
Hbase采用表来组织数据,表由许多行和列组成,列划分为多个列族.
2.行(row)
在表里面,每一行代表着一个数据对象.每一行都是由一个行键(Row Key)和一个或者多个列组成的.
行键是行的唯一标识,行键并没有什么特定的数据类型,以二进制的字节来存储,按照字典(ASC码表)排序.
因为表的行是按照行键顺序来进行存储的,所以行键的设计相当重要
设计行键的一个重要原则就是相关的行键要出存在接近的位置,例如,设计记录网站的表时,行键需要将域名反转(例如,org.apache.www、org.apache.mail、org.apache.jira),这样的设计能使与apache相关的域名在表中存储的位置非常接近,
访问表中的行只有三种方式:通过单个行键获取单行数据;通过一个行键的取键来访问给定区间的多行数据;全表扫描
3.列族(Column Family)–>数据库表
在定义Hbase表的时候需要提前设置好列族,表中所有的列都需要组织在列族中
列族一旦确定后,就不能轻易修改,因为会影响到Hbase的真实的物理存储结构,但是列族中的列限定符及其对应的值可以进行动态增删,
表中的每一行都有相同的列族,但是不需要每一行的列族里都有一致的列限定符,所以说是一种稀疏的表结构,这样可以在一定程度上避免数据的荣冗余.
Hbase中的列族是一些列的集合,一个列族的所有成员都有着相同的前缀,例如,courses:history 和 courses:math 都是列族 courses 的成员。“:”是列族的分隔符,用来区分前缀和列名。
列族必须在表建立的时候声明,列可以随时新建,
每个column faily储存在HDFS的一个单独文件中,空值不会被保存
4.列限定符(Column Qyalifier)
列族中的数据通过列限定符来进行映射,列限定符不需要事先定义,也不需要在不同行之间保持一致,列限定符没有特定的数据类型,以二进制字节来存储.
5.列(Column)
列是由列族和列限定符联合标识的,由“ : ”进行间隔,如 family:qualifiero
6.单元(Cell)
由行键,列族和列限定符一起标识的是一个单元,储存在单元里的数据称之为单元数据,没有特定的数据类型,以二进制字节来存储
Hbase提供基于单元的版本管理功能,版本号默认通过timestamp来标识,并且排序呈倒序.
7.时间戳(Timestamp)
默认情况下,每一个单元中的数据插入时都会用时间戳来进行版本的标识.
读取单元数据时,如果时间戳没有被指定,则默认返回最新的数据;写入新的单元数据时,如果没有设置时间戳,则默认使用当前时间,每一个列族的单元数据的版本数量都被Hbase单独维护,默认情况下,Hbase保留三个版本数据.
总结来看
Hbase的一个表map key–>rowkey val–>由多个列族组成
rowkey:时byte array 时表中每条记录的主键,方便快速查找,Rowkey设计非常重要
Column Family:列族,拥有一个名称(string),包含一个或者多个相关列 --> map
Column:属于某一个columnfamily,familyName:columnName,每条记录可动态添加
Version Number:类型为Long,默认值是系统时间戳,可由用户自定义
Value(Cell):Byte array
概念视图
在Hbase的概念视图中,一张表可以视为一个多维的,稀疏的映射关系,通过"行键+列族:列限定符+时间戳"的格式就可以定位特定单元格的数据.因为Hbase的表是稀疏的,因此某些字段可以是空白的.
如图,是Hbase的概念视图,是一个存储网页信息的表的片段,行键是一个反向的URL,如 www.cnn.com 反向成 com.cnn.www。反向 URL 的好处就是,可以让来自同一个网站的数据内容都保存在相邻的位置,从而可以提高用户读取该网站的数据的速度。
contents 列族存储了网页的内容;anchor 列族存储了引用这个网页的链接;mime 列族存储了该网页的媒体类型。
图中给出的 com.cnn.www 网站的概念视图中仅有一行数据,行的唯一标识为“com.cnn.www”,对这行数据的每一次逻辑修改都有一个时间戳关联对应。
表中共有四列:contents:html、anchor:cnnsi.com、anchor:my.look.ca 和 mime:type,每一列以前缀的方式给出其所属的列族。
物理视图
虽然从概念视图层面看来,Hbase的每个表是由很多行组成的,但是在物理的存储层面看来,他是采用了基于列的存储方式,而不像关系型数据库那样用基于行的储存方式.这正是Hbase与关系型数据库的重要区别之一.上图的概念试图在进行物理存储的时候,会存为如下图的三个片段,也就是说,这个Hbase表会按照contents,anchor,mime三个列族分别存放.属于同一个列族的数据保存在一起,同时,和每个列族放在一起的还有行键和时间戳,在上图的概念视图中,可以看到许多列是空的,也就是说,这些列上面不存在值
在物理视图中,这些空的列不会储存为null,而是根本不会被存储,从而可以节省大量的存储空间.当请求这些空白的单元的时候,会返回null值.
在图中可以看出,网页的内容一共由三个版本,对应的时间戳分别为t3,t5,t6
网页一共被两个页面引用 分别是"my.look.ca"和"cnnsi.com" 时间戳分别为t8,t9
网页的媒体类型,从t6开始为"text/html"
从图中可以看出,在 HBase 表的概念视图中,每个行都包含相同的列族,尽管并不是每行都需要在每个列族里都存储数据。
例如,在图中的前两行数据中,列族 contents 和列族 mime 的内容为空。后 3 行数据中,列族 anchor 的内容为空。后两行数据中,列族 mime 的内容为空。
总结来看:
每个Column family存储在hdfs上的一个单独文件夹中,空值不会被保存
Key 和 Version number在每个 column family中均有一份
HBase 为每个值维护了多级索引,即:<namespace,key, column family, column name, timestamp>
在物理层面上,表格的的数据是通过StoreFile来存储的,每个storeFile相当于一个可序列化的Map,Map的Key和Value都是可二进制数据
Column Family
是一组Column的组合,在HBase中,Schema的定义主要为Column Family的定义,同大多数nosql数据库一样,HBase也是支持自由定义Schema,但是前提要先定义出具体的Column Family,而在随后的column定义则没有任何约束
其次,HBase的访问权限控制,磁盘及内存统计等功能都是基于Column Family层面完成的
Timestamp
HBase提供基于Cell的版本管理功能,版本号默认通过timestamp来标识,并且呈倒序排列
Hbase安装
链接: link.
Hbase的主要组件
Hbase的架构组成
Hbase采用Master/Slave架构搭建集群 也就是主从结构,隶属于Hadoop生态系统,由以下类型节点组成:
HMaster节点,HRegionServer节点,ZooKeeper集群,而在底层,他将数据存储到HDFS中,因而涉及到HDFS的namenode和Datanode等,总体结构如下:
各个组件说明
Client:
1) 使用Hbase RPC机制与HMaster和HRegionServer进行通信;
2) Client与Hmaster进行通信进行管理类操作;
3) Client与HRegionServer进行数据读写类操作
HMaster NAMENODE RESOURCEMANAGER:
HMaster没有单点问题,Hbase中可以启动多个HMaster,通过Zookeeper保证总有一个HMaster在运行
HMaster主要负责Table和Region的管理工作:
1) 管理用户对表的增删改查操作;
2)管理HRegionServer的负载均衡,调整Region的分布
3)Region Split后,负责新的Region的分布
4)在HRegionServer停机后,负责失效的HRegionServer上Region的迁移
HRegionServer:DATANODE NODEMANAGER:
Hbase中的最核心的模块;
1)维护Region,处理这些region的IO的请求
2)Regionserver负责切分在运行过程中变得过大的Region;
Region的概念
Region是Hbase数据管理的基本单位.数据的move,数据的balance,数据的split,都是按照region来进行操作的. region中储存着用户的真实数据,而为了管理这些数据,HBase使用了RegionServer来管理region
一个表中可以包含一个或者多个region ,每个region只能被一个RS(RegionServer)提供服务,RS同时服务多个region,来自不同RS上的region组合成表格的整体逻辑结视图.
RegionServer其实是hbase的服务,部署在一台物理服务器上,region有一点像关系型数据库的分区,数据存放在region中,当然,region下面还有很多结构,确切的来说 :数据存放在memstore和hfile中.我们访问hbase的时候,先去hbase系统表查找定位这条记录属于那个region,然后定位到这个region属于那个服务器,然后就到那个服务器里查找对应region中的数据
region 是部分数据,所以是所有数据的一个自己,但region包括完整的行,所以region 是行为单位 表的一个子集.
每个region 有三个主要要素:
它所属于哪张表
它所包含的的第一行(第一个region 没有首行)
他所包含的最后一行(末一个region 没有末行)
HRegionServer基于HDFS部署,所以可以左到数据本地化操作
一个表可以对应多个region,但是一个region只能被一个HS服务,并且一个HS上也不一定保存一个表所有的region
HRegion使用RowKey将表水平切割成多个HRegion,从HMaster的角度,每个HRegion都记录了它的StartKey和EndKey(第一个HRegion的StartKey为空,最后一个HRegion的EndKey为空),由于RowKey是排序的,因而Client可以通过HMaster快速的定位每个RowKey在哪个HRegion中。
Zookeeper:
1)ZooKeeper为HBase集群提供协调服务,它管理着HMaster和HRegionServer的状态(available/alive等),并且保证集群中只有一个HMaster,会在它们宕机时通知给HMaster,从而HMaster可以实现HMaster之间的故障转移;
2)实时监控HRegionServer的上线和下线信息,并实时通知给HMaster;
3)存储HBase的Meta Table(hbase:meta)的位置,Meta Table表存储了集群中所有用户HRegion的位置信息,且不能split;
4)Zookeeper的引入使得Master不再是单点故障 HMaster虽然可以开启多个 但是不是越多越好 两个 --> 只开一个 nn2 贡献出来保存region nn2 没有 block --> 尴尬
HRegionServer详解
HRegionServer和DataNode一般在同一台机器上运行,实现数据的本地行
1)HRegionServer内部管理了一系列的HRegion现象,每个HRegion对应了Tabke中的一个Region(这张表的N行数据)
2)一个Table可以有一个或多个Region,他们可以在一个相同的HRegionServer上,也可以分布在不同的HRegionServer上,一个HRegionServer可以有多个HRegion,他们分别属于不同的Table。
3)HRegion由多个Store(HStore)构成,每个HStore对应了Table在这个HRegion中的一个Column Family,即内阁Column Family就是一个集中的存储单元,因而最好将具有相近IO特性的Column存储在一个Column Family,以实现高效读取。
4)每个HRegionServer中都会有一个HLog对象。
HLog是一个实现 Write Ahead Log 的类,每次用户操作写入Memstore的同时,也会写一份数据到HLog文件,HLog文件定期会滚动出新,并删除旧的文件(已持久化到StoreFile中的数据)。
引入HLog原因:灾难恢复。在分布式系统环境中,无法避免系统出错或者宕机,一旦HRegionServer意外退出,MemStore中的内存数据就会丢失,引入HLog就是防止这种情况。
5)一个HStore由一个MemStore 和0个或多个StoreFile组成。
MemStore:
是一个写缓存(In Memory Sorted Buffer),所有数据的写在完成WAL日志写后,会 写入MemStore中,由MemStore根据一定的算法将数据Flush到底层HDFS文件中(HFile),通常每个HRegion中的每个 Column Family有一个自己的MemStore。
StoreFile(Hfile):
用于存储HBase的数据(Cell/KeyValue)。在HFile中的数据是按RowKey、Column Family、Column排序,对相同的Cell(即这三个值都一样),则按timestamp倒序排列。
Hbase的读写流程
regionserver
HRegionServer内部管理了一系列的HRegion对象,每个HRegion对应了Table中的一个Region,HRegion中由多个Hstore组成,每个HStore对应了Table中的一个Column Family的存储
可以看出每个Column Family其实就是一个集中的存储单元,因此最好将具备共同IO特性的Column 放到一个Column Family中,这样最高效
HStore存储由两部分组成,一部分是MemStore 一部分是 StoreFile
容错与恢复
每个HRegionServer中都有一个HLog对象,HLog是一个实现Write Ahead Log的类,在每次用户操作写入MemStore的同时,也会写一份数据到HLog文件中,HLog文件定期会滚动出新的,并删除旧的文件(已持久化到StoreFile中的数据)
WAL就像日志中心一样,它被同一个region server中的所有region共享。
当客户端启动一个操作来修改数据,该操作便会被封装成一个KeyValue对象实例中,并通过RPC调用发送出去。
这些调用成批的发送给含有匹配region的HRegionServer。一旦KeyValue到达,它们会被发送到管理相应行的HRegion对象实例。数据便被写入到WAL,然后放入到实际拥有记录的存储文件的MemStore中。
最后当memstore达到一定的大小或者经历一个特定时间之后,数据就会异步地连续写入到文件系统中。
在写入的过程中,数据以一种不稳定的状态存放在内容中,即使在服务器完全崩溃的情况下,WAL也能够保证数据不丢失,因为实际的日志存储在HDFS上。其他服务器可以打开日志然后回放这些修改。
当HRegionServer发生意外终止后,HMaster会通过Zookeeper感知到,HMaster首先会处理遗留的Hlog文件,将其中不同的Region数据进行拆分,分别放到相应的Region的目录下,然后再将失效的Region重新分配,领取到这些region的HregionServer再LoadRegion的过程中,会发现有历史Hlog需要处理,因此会ReplayHLog中的数据到MemStore中,然后fluse到StoreFiles,完成数据恢复.
每个RS维护一个Hlog,而不是每个Region一个
这样做的目的是不断追加单个文件相对于同时写多个文件而言,可以减少磁盘寻址次数,因此可以提高对table的写性能。
带来的麻烦是,如果一台Region Server下线,为了恢复其上的Region,需要将Region Server上的log进行拆分,然后分发到其它Region Server上进行恢复。
1.客户端寻找HRegionServer,以及缓存位置信息
再这个过程中,我们会发现客户会缓存这些位置信息,然而第二步他只是缓存当前RowKey对应的HRegion的位置,因而如果下一个要查的RowKey不在同一个HRegion中,则需要继续查询hbase:meta所在的HRegion,然而随着时间的推移,客户端缓存的位置信息越来越多,以至于不需要再次查找hbase:meta Table的信息,除非某个HRegion因为宕机或者Split被移动,此时需要重新查询并且更新缓存.
2.写数据流程
1)通过1找到该写数据最终需要去的HRegionServer
2)然后客户端将写请求发送给相应的HS 在HRegionServer中它首先会将该写操作写入WAL(Hlog)日志文件中(Flush到磁盘中)。
3)写完WAL日志文件后,HRegionServer根据Put中的TableName和RowKey,startkey、endkey找到对应的HRegion,并根据Column Family找到对应的HStore,并将Put写入到该HStore的MemStore中。此时写成功,并返回通知客户端。
写入MemStore后的操作:
存入MemStore,一直到MemStore满
→ Flush成一个StoreFile,直至增长到一定阈值
→ 触发Compact合并操作 -> 多个StoreFile合并成一个StoreFile,同时进行版本合并和数据删除
→ 当StoreFiles Compact后,逐步形成越来越大的StoreFile
→单个StoreFile大小超过一定阈值(Region split 阈值)后,触发Split操作,把当前Region Split成2个Region,Region会下线,新Split出的2个子Region会被HMaster分配到相应的HRegionServer上,使得原先1个Region的压力得以分流到2个Region上;
什么时候执行MemStore Flush?
1)当一个MemStore的大小超过了hbase.hregion.memstore.flush.size(默认64M)的大小,此时当前的HRegion中所有的MemStore会Flush到HDFS中,不阻塞写操作。(Region级别的flush)
2)当全局MemStore的大小超过了hbase.regionserver.global.memstore.upperLimit(默认0.4,memstores所占最大堆空间比例)的大小,此时当前HRegionServer中所有HRegion中的MemStore都会Flush到HDFS中,阻塞写操作。(RS级别的flush)
3)当一个Region的MemStore总量达到hbase.hregion.memstore.block.multiplier * hbase.hregion.memstore.flush.size(默认2*128M=256M)时,会阻塞这个region的写操作,并强制刷写到HDFS。
触发这个刷新只会发生在MemStore即将写满128M时put了一个巨大的记录的情况,这时会阻塞写操作,强制刷新成功才能继续写入。(Region级别的flush)
4)当前HRegionServer中HLog的大小超过阈值,当前HRegionServer中所有HRegion中的MemStore都会Flush到HDFS中。(RS级别的flush)
3 读数据流程
1)通过1中的找到要读的数据的HRegionServer。
2)根据读取的TableName和RowKey的startkey 、 endkey 找到对应的HRegion。
3)每个regionserver只有一个blockcache(读缓存),读取数据时,先到memestore上读数据,找不到再到blockcahce上找数据,再查不到则到磁盘(storefile)查找,并把读入的数据同时放入blockcache。
4 Region拆分策略
Region概念
一个Table由一个或多个Region组成
一个Region由一个或者多个Store组成,每个store保存一个columns family;
一个Strore又由一个memStore和0至多个StoreFile 组成。memStore存储在内存中, StoreFile存储在HDFS上。
Region大小考量的因素
1)机器个数多,Region个数少,浪费机器,region数目太少就会妨碍可扩展性,降低并行能力,导致压力不够分散;
2)region小,数目太多就会造成性能下降;
Region拆分策略
HRegionServer拆分region的步骤是,先将该region下线,然后拆分,将其子region加入到hbase:meta表中,再将他们加入到原本的HRegionServer中,最后汇报Master。
split前
hbase:meta: region_p --> regionserver1
split中
region_p —> region1
region2
在 region_p 对应的hdfs目录下生成.splits 目录, 里面创建 两个子region的引用文件
tablename/region_p_md5/.splits/region1 引用文件
/region2 引用文件
在表目录下创建子region对应的hdfs目录, 把引用文件拷贝到 指定region目录下
tablename/region1_md5/region1 引用文件
/2region_md5/region2 引用文件
split后
把子region往hbase:meta表里写
hbase:meta
region1 --> regionserver1
region2 --> regionserver1
两个子region从父region获取数据,当数据获取完,删除相应的引用文件
汇报hmaster --> regionserver1 (count(region) 多 --> 平衡 --> regionserver)
可以通过设置RegionSplitPolicy的实现类来指定拆分策略,RegionSplitPolicy类的实现类有:
1.ConstantSizeRegionSplitPolicy
2.IncreasingToUpperBoundRegionSplitPolicy
3.DelimitedKeyPrefixRegionSplitPolicy
4.KeyPrefixRegionSplitPolicy
其中:
ConstantSizeRegionSplitPolicy
仅当region大小超过常量值(hbase.hregion.max.filesize大小,默认为10G)时,才进行拆分。
IncreasingToUpperBoundRegionSplitPolicy
默认region split策略。
即当同一table在同一regionserver上的region数量在[0,100)之间时按照如下的计算公式算,否则按照上一策略计算:
Min (R^3* "hbase.hregion.memstore.flush.size"2, “hbase.hregion.max.filesize”)
R为同一个table中在同一个regionserver中region的个数,
hbase.hregion.memstore.flush.size默认为128M,
hbase.hregion.max.filesize默认为10G。
myns1:table1 --> 插入数据 越来越多 --> nn2.hadoop --> 最开region数量 1 --> 2 --> 4
第一次分裂: 1111282 = 256 --> 1 --> 2
第二次分裂: 222128*2 = 2048 --> 2 --> 4
第三次分裂 : 4 * 4 * 4 * 128 * 2
一个表的region 越分越多 --> hmaster --> 平衡 --> RS --> region 移动(慢)
预分 region 表 数据 --> 够大 – 分region
表 --> 分出region --> rowkey(范围识别) --> hive的分区 先分区 再存储 数据
对应源代码如下:
DelimitedKeyPrefixRegionSplitPolicy
保证以分隔符前面的前缀为splitPoint,保证相同RowKey前缀的数据在一个Region中。
如果定义rowkey时,采用’_'作为字段分隔符(如:userid_eventid),则采用该策略拆分之后,能够确保具有相同userid的记录隶属于同一Region。
假设分割字段是 “_”
userid_eventid --> userid
userid_aaaid
username_aaa —> username
username_bb
KeyPrefixRegionSplitPolicy
保证具有相同前缀的row在一个region中(要求设计中前缀具有同样长度)。
指定rowkey前缀位数划分region,通过读取table的prefix_split_key_policy.prefix_length属性,该属性为数字类型,表示前缀长度,在进行split时,按此长度对splitPoint进行截取。
此种策略比较适合固定前缀的rowkey。当table中没有设置该属性,或其属性不为Integer类型时,指定此策略效果等同与使用IncreasingToUpperBoundRegionSplitPolicy。
假设 prefix_split_key_policy.prefix_length=9
userid001_aaa --> userid001
userid001_bbb
userid002_aaa --> userid002
userid002_bbb
配置拆分策略
hbase配置文件中定义全局的拆分策略,设置hbase.regionserver.region.split.policy;也可以在创建和修改表时候指定。
如果想关闭自动拆分改为手动拆分,建议同时修改hbase.hregion.max.filesize和hbase.regionserver.region.split.policy值。
如果关闭自动拆分策略需要把 hbase.hregion.max.filesize 设置非常大,再采用手动。