本文首先简单介绍了 HBase, 然后重点讲述了 HBase 的高并发和实时处理数据 ,HBase 数据模型, HBase 物理存储, HBase 系统 https://www.2cto.com/os/ 架构, HBase 调优, HBase Shell 访问等.
不过在此之前, 你可以先了解 Hadoop 生态系统, 若想运行 HBase, 则需要先搭建好 Hadoop 集群环境.
好了, 让我们来学习 HBase 吧!
HBase 简介
HBase 的发展史
2006 年底由 PowerSet 的 Chad Walters 和 Jim Kellerman 发起, 2008 年成为 Apache Hadoop 的一个子项目. 现已作为产品在多家企业被使用, 如:
- WorldLingo
- Streamy.com
- OpenPlaces
- Yahoo!
- Adobe
淘宝
- Trend Micro
Hbase 是什么
HBase 是一种构建在 HDFS 之上的分布式, 面向列的存储系统. 在需要实时读写, 随机访问超大规模数据集时, 可以使用 HBase.
尽管已经有许多数据存储和访问的策略和实现方法, 但事实上大多数解决方案, 特别是一些关系类型的, 在构建时并没有考虑超大规模和分布式的特点. 许多商家通过复制和分区的方法来扩充数据库 https://www.2cto.com/database/ 使其突破单个节点的界限, 但这些功能通常都是事后增加的, 安装和维护都和复杂. 同时, 也会影响 RDBMS 的特定功能, 例如联接, 复杂的查询, 触发器, 视图和外键约束这些操作在大型的 RDBMS 上的代价相当高, 甚至根本无法实现.
HBase 从另一个角度处理伸缩性问题. 它通过线性方式从下到上增加节点来进行扩展. HBase 不是关系型数据库, 也不支持 SQL, 但是它有自己的特长, 这是 RDBMS 不能处理的, HBase 巧妙地将大而稀疏的表放在商用的服务器集群上.
HBase 是 Google Bigtable 的开源实现, 与 Google Bigtable 利用 GFS 作为其文件存储系统类似, HBase 利用 Hadoop HDFS 作为其文件存储系统; Google 运行 MapReduce 来处理 Bigtable 中的海量数据, HBase 同样利用 Hadoop MapReduce 来处理 HBase 中的海量数据; Google Bigtable 利用 Chubby 作为协同服务, HBase 利用 Zookeeper 作为对应.
HBase 的特点
大: 一个表可以有上亿行, 上百万列.
面向列: 面向列表 (簇) 的存储和权限控制, 列 (簇) 独立检索.
稀疏: 对于为空 (NULL) 的列, 并不占用存储空间, 因此, 表可以设计的非常稀疏.
无模式: 每一行都有一个可以排序的主键和任意多的列, 列可以根据需要动态增加, 同一张表中不同的行可以有截然不同的列.
数据多版本: 每个单元中的数据可以有多个版本, 默认情况下, 版本号自动分配, 版本号就是单元格插入时的时间戳.
数据类型单一: HBase 中的数据都是字符串, 没有类型.
HBase 的高并发和实时处理数据
Hadoop 是一个高容错, 高延时的分布式文件系统和高并发的批处理系统, 不适用于提供实时计算; HBase 是可以提供实时计算的分布式数据库, 数据被保存在 HDFS 分布式文件系统上, 由 HDFS 保证期高容错性, 但是再生产环境中, HBase 是如何基于 hadoop 提供实时性呢? HBase 上的数据是以 StoreFile(HFile)二进制流的形式存储在 HDFS 上 block 块儿中; 但是 HDFS 并不知道的 hbase 存的是什么, 它只把存储文件是为二进制文件, 也就是说, hbase 的存储数据对于 HDFS 文件系统是透明的. 下面是 HBase 文件在 HDFS 上的存储示意图.
HBase HRegion servers 集群中的所有的 region 的数据在服务器启动时都是被打开的, 并且在内冲初始化一些 memstore, 相应的这就在一定程度上加快系统响 应; 而 Hadoop 中的 block 中的数据文件默认是关闭的, 只有在需要的时候才打开, 处理完数据后就关闭, 这在一定程度上就增加了响应时间.
从根本上说, HBase 能提供实时计算服务主要原因是由其架构和底层的数据结构决定的, 即由 LSM-Tree + HTable(region 分区) + Cache 决定 -- 客户端可以直接定位到要查数据所在的 HRegion server 服务器, 然后直接在服务器的一个 region 上查找要匹配的数据, 并且这些数据部分是经过 cache 缓存的. 具体查询流程如下图所示:
具体数据访问流程如下:
Client 会通过内部缓存的相关的 - ROOT - 中的信息和. META. 中的信息直接连接与请求数据匹配的 HRegion server;
然后直接定位到该服务器上与客户请求对应的 Region, 客户请求首先会查询该 Region 在内存中的缓存 --Memstore(Memstore 是一个按 key 排序的树形结构的缓冲区);
如果在 Memstore 中查到结果则直接将结果返回给 Client;
在 Memstore 中没有查到匹配的数据, 接下来会读已持久化的 StoreFile 文件中的数据. 前面的章节已经讲过, StoreFile 也是按 key 排序的树形结构的文件 -- 并且是特别为范围查询或 block 查询优化过的,; 另外 HBase 读取磁盘文件是按其基本 I/O 单元 (即 HBase Block) 读数据的.
具体就是过程就是:
如果在 BlockCache 中能查到要造的数据则这届返回结果, 否则就读去相应的 StoreFile 文件中读取一 block 的数据, 如果还没有读到要查的 数据, 就将该数据 block 放到 HRegion Server 的 blockcache 中, 然后接着读下一 block 块儿的数据, 一直到这样循环的 block 数据直到找到要请求的数据并返回结果; 如果将该 Region 中的数据都没有查到要找的数据, 最后接直接返回 null, 表示没有找的匹配的数据. 当然 blockcache 会在其大小大于一的阀值 (heapsize * hfile.block.cache.size * 0.85) 后启动基于 LRU 算法的淘汰机制, 将最老最不常用的 block 删除.
HBase 数据模型
HBase 以表的形式存储数据. 表由行和列组成. 列划分为若干个列族(row family), 如下图所示.
HBase 的逻辑数据模型:
HBase 的物理数据模型(实际存储的数据模型):
逻辑数据模型中空白 cell 在物理上是不存储的, 因为根本没有必要存储, 因此若一个请求为要获取 t8 时间的 contents:html, 他的结果就是空. 相似的, 若请求为获取 t9 时间的 anchor:my.look.ca, 结果也是空. 但是, 如果不指明时间, 将会返回最新时间的行, 每个最新的都会返回
Row Key
与 NoSQL 数据库一样, Row Key 是用来检索记录的主键. 访问 HBase table 中的行, 只有三种方式:
1)通过单个 Row Key 访问.
2)通过 Row Key 的 range 全表扫描.
3)Row Key 可以使任意字符串(最大长度是 64KB, 实际应用中长度一般为 10 ~ 100bytes), 在 HBase 内部, Row Key 保存为字节数组.
在存储时, 数据按照 * Row Key 的字典序 (byte order) 排序存储 *. 设计 Key 时, 要充分排序存储这个特性, 将经常一起读取的行存储到一起(位置相关性).
注意 字典序对 int 排序的结果是 1,10,100,11,12,13,14,15,16,17,18,19,20,21,..., 9,91,92,93,94,95,96,97,98,99. 要保存整形的自然序, Row Key 必须用 0 进行左填充.
行的一次读写是原子操作(不论一次读写多少列). 这个设计决策能够使用户很容易理解程序在对同一个行进行并发更新操作时的行为.
列族
HBase 表中的每个列都归属于某个列族. 列族是表的 Schema 的一部分(而列不是), 必须在使用表之前定义. 列名都以列族作为前缀, 例如 courses:history,courses:math 都属于 courses 这个列族.
访问控制, 磁盘和内存的使用统计都是在列族层面进行的. 在实际应用中, 列族上的控制权限能帮助我们管理不同类型的应用, 例如, 允许一些应用可以添加新的基本数据, 一些应用可以读取基本数据并创建继承的列族,
一些应用则只允许浏览数据(甚至可能因为隐私的原因不能浏览所有数据).
时间戳
HBase 中通过 Row 和 Columns 确定的一个存储单元称为 Cell. 每个 Cell 都保存着同一份数据的多个版本. 版本通过时间戳来索引, 时间戳的类型是 64 位整型. 时间戳可以由 HBase(在数据写入时自动)赋值,
此时时间戳是精确到毫秒的当前系统时间. 时间戳也 可以由客户显示赋值. 如果应用程序要避免数据版本冲突, 就必须自己生成具有唯一性的时间戳. 每个 Cell 中, 不同版本的数据按照时间倒序排序, 即最新的数据排在最前面.
为了避免数据存在过多版本造成的管理 (包括存储和索引) 负担, HBase 提供了两种数据版本回收方式. 一是保存数据的最后 n 个版本, 二是保存最近一段时间内的版本(比如最近七天). 用户可以针对每个列族进行设置.
Cell
Cell 是由 {row key,column(=<family> + <label>),version} 唯一确定的单元. Cell 中的数据是没有类型的, 全部是字节码形式存储.
HBase 物理存储
Table 在行的方向上分割为多个 HRegion, 每个 HRegion 分散在不同的 RegionServer 中.
每个 HRegion 由多个 Store 构成, 每个 Store 由一个 memStore 和 0 或多个 StoreFile 组成, 每个 Store 保存一个 Columns Family
HBase 系统架构
HBase 架构图如下:
从 HBase 的架构图上可以看出, HBase 中的组件 https://www.2cto.com/kf/all/zujian/ 包括 Client,Zookeeper,HMaster,HRegionServer,HRegion,Store,MemStore,StoreFile,HFile,HLog 等, 接下来介绍他们的作用.
HBase 中的每张表都通过行键按照一定的范围被分割成多个子表(HRegion), 默认一个 HRegion 超过 256M 就要被分割成两个, 这个过程由 HRegionServer 管理, 而 HRegion 的分配由 HMaster 管理.
Client
包含访问 HBase 的接口, 并维护 cache 来加快对 HBase 的访问.
Zookeeper 的作用
HBase 依赖 Zookeeper, 默认情况下 HBase 管理 Zookeeper 实例(启动或关闭 Zookeeper),Master 与 RegionServers 启动时会向 Zookeeper 注册.
Zookeeper 的作用:
保证任何时候, 集群中只有一个 master
存储所有 Region 的寻址入口
实时监控 Region server 的上线和下线信息. 并实时通知给 master
存储 HBase 的 schema 和 table 元数据
HMaster 的作用
为 Region server 分配 region
负责 Region server 的负载均衡
发现失效的 Region server 并重新分配其上的 region.
HDFS 上的垃圾文件回收.
处理 schema 更新请求.
HRegionServer 的作用
维护 master 分配给他的 region, 处理对这些 region 的 io 请求.
负责切分正在运行过程中变的过大的 region.
注意: client 访问 hbase 上的数据时不需要 master 的参与, 因为数据寻址访问 zookeeper 和 region server, 而数据读写访问 region server.master 仅仅维护 table 和 region 的元数据信息, 而 table 的元数据信息保存在 zookeeper 上, 因此 master 负载很低.
HRegion
table 在行的方向上分隔为多个 Region.Region 是 HBase 中分布式存储和负载均衡的最小单元, 即不同的 region 可以分别在不同的 Region Server 上, 但同一个 Region 是不会拆分到多个 server 上.
Region 按大小分隔, 每个表一般是只有一个 region. 随着数据不断插入表, region 不断增大, 当 region 的某个列族达到一个阈值 (默认 256M) 时就会分成两个新的 region.
每个 region 由以下信息标识:
<表名, startRowkey, 创建时间>
由目录表 (-ROOT - 和. META.) 记录该 region 的 endRowkey
Region 被分配给哪个 Region Server 是完全动态的, 所以需要机制来定位 Region 具体在哪个 region server.
下面我们来看看 Region 是如何被定位的.
HRegion 定位
通过 zk 里的文件 / hbase/rs 得到 - ROOT - 表的位置.-ROOT - 表只有一个 region.
通过 - ROOT - 表查找. META. 表的第一个表中相应的 region 的位置. 其实 - ROOT - 表是. META. 表的第一个 region;.META. 表中的每一个 region
在 - ROOT - 表中都是一行记录.
通过. META. 表找到所要的用户表 region 的位置. 用户表中的每个 region 在. META. 表中都是一行记录.
-ROOT - 表永远不会被分隔为多个 region, 保证了最多需要三次跳转, 就能定位到任意的 region.client 会将查询的位置 信息保存缓存起来, 缓存不会主动失效, 因此如果 client 上的缓存全部失效, 则需要进行 6 次网络来回, 才能定位到正确的 region, 其中三次用来发现 缓存失效, 另外三次用来获取位置信息.
提示:
-ROOT - 表: 表包含. META. 表所在的 region 列表, 该表只有一个 Region;Zookeeper 中记录了 - ROOT - 表的 location
.META. 表: 表包含所有的用户空间 region 列表, 以及 Region Server 的服务器地址
Store
每一个 region 由一个或多个 store 组成, 至少是一个 store,hbase 会把一起访问的数据放在一个 store 里面, 即为每个 ColumnFamily 建一个 store, 如果有几个 ColumnFamily, 也就有几个 Store. 一个 Store 由一个 memStore 和 0 或者 多个 StoreFile 组成. HBase 以 store 的大小来判断是否需要切分 region
MemStore
memStore 是放在内存里的. 保存修改的数据即 keyValues. 当 memStore 的大小达到一个阀值 (默认 64MB) 时, memStore 会被 flush 到文 件, 即生成一个快照. 目前 hbase 会有一个线程来负责 memStore 的 flush 操作.
StoreFile
memStore 内存中的数据写到文件后就是 StoreFile,StoreFile 底层是以 HFile 的格式保存.
HLog
HLog(WAL log):WAL 意为 write ahead log, 用来做灾难恢复使用, HLog 记录数据的所有变更, 一旦 region server 宕机, 就可以从 log 中进行恢复.
HLog 文件就是一个普通的 Hadoop Sequence File, Sequence File 的 value 是 key 时 HLogKey 对象, 其中记录了写入数据的归属信息, 除了 table 和 region 名字外, 还同时包括 sequence number 和 timestamp,timestamp 是写入时间, sequence number 的起始值为 0, 或者是最近一次存入文件系统中的 sequence number. Sequence File 的 value 是 HBase 的 KeyValue 对象, 即对应 HFile 中的 KeyValue.
LogFlusher
前面提到, 数据以 KeyValue 形式到达 HRegionServer, 将写入 WAL 之后, 写入一个 SequenceFile. 看过去没问题, 但是因为数 据流在写入文件系统时, 经常会缓存以提高性能. 这样, 有些本以为在日志文件中的数据实际在内存中.
这里, 我们提供了一个 LogFlusher 的类. 它调用 HLog.optionalSync(), 后者根据 hbase.regionserver.optionallogflushinterval (默认是 10 秒), 定期调用 Hlog.sync(). 另外, HLog.doWrite()也会根据
hbase.regionserver.flushlogentries (默认 100 秒)定期调用 Hlog.sync().Sync() 本身调用 HLog.Writer.sync(), 它由 SequenceFileLogWriter 实现.
LogRoller
Log 的大小通过 $HBASE_HOME/conf/hbase-site.xml 的 hbase.regionserver.logroll.period 限制, 默认是一个小时. 所以每 60 分钟, 会打开一个新的 log 文件. 久而久之, 会有一大堆的文件需要维护. 首先, LogRoller 调用 HLog.rollWriter(), 定时滚动日志, 之后, 利用 HLog.cleanOldLogs()可以清除旧的日志. 它首先取得存储文件中的最大的 sequence number, 之后检查是否存在一个 log 所有的条目的 "sequence number" 均低于这个值, 如果存在, 将删除这个 log. 每个 region server 维护一个 HLog, 而不是每一个 region 一个, 这样不同 region(来自不同的 table)的日志会混在一起, 这样做的目的是不断追加 单个文件相对于同时写多个文件而言, 可以减少磁盘寻址次数, 因此可以提高 table 的写性能. 带来麻烦的时, 如果一个 region server 下线, 为了恢复其上的 region, 需要将 region server 上的 log 进行拆分, 然后分发到其他 region server 上进行恢复.
HBase 工作流程
目前为止, 相信你已经了解了 HBase 组件的使用和作用, 但你可能还不太清楚上面提及的这些 HBase 组件间是如何运作的, 下面我们来看看 HBase 的工作流程.
Client
首先当一个请求产生时, HBase Client 使用 RPC(远程过程调用)机制与 HMaster 和 HRegionServer 进行通信, 对于管理类操作, Client 与 HMaster 进行 RPC; 对于数据读写操作, Client 与 HRegionServer 进行 RPC.
Zookeeper
HBase Client 使用 RPC(远程过程调用)机制与 HMaster 和 HRegionServer 进行通信, 但如何寻址呢? 由于 Zookeeper 中存储了 - ROOT - 表的地址和 HMaster 的地址, 所以需要先到 Zookeeper 上进行寻址.
HRegionServer 也会把自己以 Ephemeral 方式注册到 Zookeeper 中, 使 HMaster 可以随时感知到各个 HRegionServer 的健康状态. 此外, Zookeeper 也避免了 HMaster 的单点故障.
HMaster
当用户需要进行 Table 和 Region 的管理工作时, 就需要和 HMaster 进行通信. HBase 中可以启动多个 HMaster, 通过 Zookeeper 的 Master Eletion 机制保证总有一个 Master 运行.
管理用户对 Table 的增删改查操作
管理 HRegionServer 的负载均衡, 调整 Region 的分布
在 Region Split 后, 负责新 Region 的分配
在 HRegionServer 停机后, 负责失效 HRegionServer 上的 Regions 迁移
HRegionServer
当用户需要对数据进行读写操作时, 需要访问 HRegionServer.HRegionServer 存取一个子表时, 会创建一个 HRegion 对象, 然后对表的每个列族创建一个 Store 实例, 每个 Store 都会有一个 MemStore 和 0 个或多个 StoreFile 与之对应, 每个 StoreFile 都会对应一个 HFile, HFile 就是实际的存储文件. 因此, 一个 HRegion 有多少个列族就有多少个 Store. 一个 HRegionServer 会有多个 HRegion 和一个 HLog.
当 HStore 存储是 HBase 的核心了, 其中由两部分组成: MemStore 和 StoreFiles. MemStore 是 Sorted Memory Buffer, 用户
写入数据首先 会放在 MemStore, 当 MemStore 满了以后会 Flush 成一个 StoreFile(实际存储在 HDHS 上的是 HFile), 当 StoreFile 文件数量增长到一定阀值, 就会触发 Compact 合并操作, 并将多个 StoreFile 合并成一个 StoreFile, 合并过程中会进行版本合并和数据删除, 因此可以看出 HBase 其实只有增加数据, 所有的更新和删除操作都是在后续的 compact 过程中进行的, 这使得用户的 读写操作只要进入内存中就可以立即返回, 保证了 HBase I/O 的高性能.
下面以一个具体数据 Put 的流程, 让我们加深对 HBase 工作流程的认识.
HBase Put 流程
下面是 put 流程的时序图:
客户端:
客户端发起 Put 写请求, 讲 put 写入 writeBuffer, 如果是批量提交, 写满缓存后自动提交
根据 rowkey 将 put 吩咐给不同 regionserver
服务端:
RegionServer 将 put 按 rowkey 分给不同的 region
Region 首先把数据写入 wal
wal 写入成功后, 把数据写入 memstore
Memstore 写完后, 检查 memstore 大小是否达到 flush 阀值
如果达到 flush 阀值, 将 memstore 写入 HDFS, 生成 HFile 文件
HBase Compact &&Split
当 StoreFile 文件数量增长到一定阀值, 就会触发 Compact 合并操作, 并将多个 StoreFile 合并成一个 StoreFile, 当这个 StoreFile 大小超过一定阀值后, 会触发 Split 操作, 同时把当前 Region Split 成 2 个 Region, 这是旧的 Region 会下线, 新 Split 出的 2 个 Region 会被 HMaster 分配到相应的 HregionServer 上, 使得原先 1 个 Region 的压力得以分散到 2 个 Region 上.
如下图四个 Storefile 文件 (从 memstore 文件经过 flush 而得到, 默认 64M 的 storefile 文件) 经过 Compact 合并成一个大的 256M storefile 文件, 当设定的 Region 阀值为 128M 时, 就会 Split 为两个 128M 的 Storefile 文件, 然后 HMaster 再把这两个 storefile 文件分配到不停地 Regionserver 上.
HFile
HBase 中所有的数据文件都存储在 Hadoop HDFS 上, 主要包括两种文件类型:
Hfile:HBase 中 KeyValue 数据的存储格式, HFile 是 Hadoop 的 二进制格式文件, 实际上 StoreFile 就是对 Hfile 做了轻量级包装, 即 StoreFile 底层就是 HFile
HLog File:HBase 中 WAL(write ahead log)的存储格式, 物理上是 Hadoop 的 Sequence File
HFile 的存储格式如下:
HFile 文件是不定长的, 长度固定的只有其中的两块: Trailer 和 FileInfo.
Trailer 中有指针指向其他数据块的起始点, FileInfo 记录了文件的一些 meta 信息. Data Block 是 hbase io 的基本单元, 为了提高效率, HRegionServer 中有基于 LRU 的 block cache 机制.
每个 Data 块的大小可以在创建一个 Table 的时候通过参数指定(默认块大小 64KB), 大号的 Block 有利于顺序 Scan, 小号的 Block 利于随机查询.
每个 Data 块除了开头的 Magic 以外就是一个个 KeyValue 对拼接而成, Magic 内容就是一些随机数字, 目的是防止数 据损坏, 结构如下.
上图可知, 开始是两个固定长度的数值, 分别表示 key 的长度和 alue 的长度. 紧接着是 Key, 开始是固定长度的数值, 表示 RowKey 的长度, 紧接着是 RowKey, 然后是固定长度的数值, 表示 Family 的长度, 然后是 Family, 接着是 Qualifier, 然后是两个固定长度的数值, 表示 Time Stamp 和 Key Type(Put/Delete).Value 部分没有那么复杂的结构, 就是纯粹的二进制数据.
HBase 的三维有序 (即字典顺序) 存储
Hfile 是 HBase 中 KeyValue 数据的存储格式. 从上面的 HBase 物理数据模型中可以看出, HBase 是面向列表 (簇) 的存储. 每个 Cell 由 {row key,column(=<family> + <label>),version} 唯一确定的单元, 他们组合在一起就是一个 KeyValue. 根据上述描述, 这个 KeyValue 中的 key 就是{row key,column(=<family> + <label>),version} , 而 value 就是 cell 中的值.
HBase 的三维有序存储中的三维是指: rowkey(行主键),column key(columnFamily+<label>),timestamp(时间戳或者版本号)三部分组成的三维有序存储.
rowkey
rowkey 是行的主键, 它是以字典顺序排序的. 所以 rowkey 的设计是至关重要的, 关系到你应用层的查询效率. 我们在根据 rowkey 范围查询的时候, 我们一般是知道 startRowkey, 如果我们通过 scan 只传 startRowKey : d 开头的, 那么查询的是所有比 d 大的都查了, 而我们只需要 d 开头的数据, 那就要通过 endRowKey 来限制. 我们可以通过设定 endRowKey 为: d 开头, 后面的根据你的 rowkey 组合来设定, 一般是加比 startKey 大一位.
column key
column key 是第二维, 数据按 rowkey 字典排序后, 如果 rowkey 相同, 则是根据 column key 来排序的, 也是按字典排序.
我们在设计 table 的时候要学会利用这一点. 比如我们的收件箱. 我们有时候需要按主题排序, 那我们就可以把主题这设置为我们的 column key, 即设计为 columnFamily + 主题., 这样的设计.
timestamp
timestamp 时间戳, 是第三维, 这是个按降序排序的, 即最新的数据排在最前面. 这个就没有什么说的了. 网上其他的博客也提到比较多.
HLog Replay
根据以上的叙述, 我们已经了解了关于 HStore 的基本原理, 但我们还必须要了解一下 HLog 的功能, 因为上述的 HStore 在系统正常工作的前提下是没问题的, 但是在分布式 系统环境中, 无法避免系统出错或者宕机, 因为一旦 HRegionServer 意外退出, MemStore 中的内存数据将会丢失, 这就需要引入 HLog. 每个 HRegionServer 中都有一个 HLog 对象, HLog 是一个实现 Write Ahead Log 的类, 在每一次用户操作写入 MemStore 的同时, 也会写一份数据到 HLog 文件中, HLog 文件定期 (当文件已持久化到 StoreFile 中的数据) 会滚出新的, 并且删除旧的文件. 当 HRegionServer 意外终止 后, HMaster 会通过 Zookeeper 感知到, HMaster 首先会处理遗留的 Hlog 文件, 将其中不同 Region 的 Log 数据进行拆分, 分别放到相应 Region 的目录下, 然后再将失效的 Region 重新分配, 领取到这些 Region 的 Regionserver 在 Load Region 的过程中, 会发现历史 HLog 需要处理, 因此 Replay HLog 中的数据到 MemStore 中, 然后 flush 到 StoreFiles, 完成数据恢复.
HLog 存储格式
WAL(Write Ahead Log):RegionServer 在处理插入和删除过程中, 用来记录操作内容的日志, 只有日志写入成功, 才会通知客户端操作成功.
上图中是 HLog 文件的结构, 其实 HLog 文件就是一个普通的 Hadoop Sequence File,Sequence File 的 Key 是 HLogKey 对象, HLogKey 中记录了写入数据的归属信息, 除了 table 和 Region 名字外, 同时还包括 sequence number 和 timestamp,timestamp 是 "写入时间",sequence number 的起始值为 0, 或者是最近一次存入文件系统中的 sequence number.
HLog Sequence File 的 Value 是 HBase 的 KeyValue 对象昂, 即对应 HFile 中的 KeyValue.
HBase 的高可用
当出现上图三种情况的高可用策略:
HDFS 机架识别策略: 当数据文件损坏时, 会找相同机架上备份的数据文件, 如果相同机架上的数据文件也损坏会找不同机架备份数据文件.
HBase 的 Region 快速恢复: 当节点损坏时, 节点上的丢失 region, 会在其他节点上均匀快速恢复.
Master 节点的 HA 机制: Master 为一主多备. 当 Master 主节点宕机后, 剩下的备节点通过选举, 产生主节点.
HBase 性能和优化
影响 HBase 性能的因素
上图中, 从 HDFS 以下都属于 HBase 的支撑系统.
从构成集群机器的底层硬件到把硬件和操作系统(尤其是文件系统),JVM,HDFS 连接起来的网络之间的所有部件都会影响到 HBase 的性能. HBase 系统的状态也会影响到 HBase 的系统. 例如, 在集群中执行合并的时候或者 Memstore 刷写的时候与什么都没有做的时候相比, 其性能表现是不同的. 应用系统的性能还取决于它和 HBase 的交互方式, 所以模式设计和其他环节一样起到了必不可少的作用.
在评判 HBase 性能时, 所有这些因素都有影响; 在优化集群时, 需要查看所有这些因素.
优化 HBase 支撑系统
(1)硬件选择
总的原则是, 根据业务情况和集群规模大小选择合理的硬件.
(2)网络配置
基于当前阶段硬件的典型分布式系统都会受到网络的限制, HBase 也不例外. 在节点和机架顶置交换机 https://www.2cto.com/net/switch/ 之间建议采用 10Gb 以太网交换机. 千万不要过于满额配置地使用网络, 否则在高负载时, 会影响 HBase 应用系统的性能.
(3)操作系统
一般情况下, 只要使用 Hadoop 和 HBase, 操作系统通常选择 Linux https://www.2cto.com/os/linux/ . 可以选择 Red Hat Enterprise Linux,CentOS, 也可以选择成功部署过的其他操作系统.
(4)本地文件系统
本地 Linux 文件系统在 HBase 集群体系里起到了重要作用, 并且严重影响到 HBase 的性能. 虽然 EXT4 是推荐使用的本地文件系统, 但没有大规模使用, 相反 EXT3 和 XFS 已经在生产系统里得到成功使用, 建议使用 EXT3 和 XFS 作为本地文件系统.
(5)HDFS
根据业务访问特点优化
根据业务访问特点, 将 Hbase 的工作负载大致分为以下四类:
(1)随机读密集型
对于随机读密集型工作负载, 高效利用缓存和更好地索引会给 HBase 系统带来更高的性能.
(2)顺序读密集型
对于顺序读密集型工作负载, 读缓存不会带来太多好处; 除非顺序读的规模很小并且限定在一个特定的行键范围内, 否则很可能使用缓存会比不使用缓存需要更频繁地访问硬盘.
(3)写密集型
写密集型工作负载的优化方法需要有别于读密集型负载. 缓存不再起到重要作用. 写操作总是进入 MemStore, 然后被刷写生成新的 Hfile, 以后再被合并. 获得更好写性能的办法是不要太频繁刷写, 合并或者拆分, 因为在这段时间里 IO 压力上升, 系统会变慢.
(4)混合型
对于完全混合型工作负载, 优化方法会变得复杂些. 优化时, 需要混合调整多个参数来得到一个最优的组合.
其它角度来优化 HBase 性能
(1)JVM 垃圾回收优化
(2)本地 memstore 分配缓存优化
(3)Region 拆分优化
(4**)Region 合并优化 **
(5)Region 预先加载优化
(6)负载均衡优化
(7)启用压缩
(8)GZIP,snappy,lzo, 推荐 snappy, 压缩比稍差于 lzo; 但是压缩速度高于 lzo, 并且与 lzo 有差不多的 解压缩速度.
(9)进行预分区, 从而避免自动 split, 提高 hbase 响应速度
(10)避免出现 region 热点现象, 启动按照 table 级别进行 balance
HBase 常见的调优参数
HBase shell 访问
HBase Shell 提供了大多数的 HBase 命令, 通过 HBase Shell 用户可以方便地创建, 删除及修改表, 还可以向表中添加数据, 列出表中的相关信息等.
在启动 HBase 之后, 用户可以通过下面的命令进入 HBase Shell 之中, 命令如下所示:
[[email protected] ~]$hbase shell
输入 help 可以看到命令分组.(注意命令都是小写, 有大小写的区分)
部分命令
下边分组举例 Shell 的各种操作.
general 操作
查询 HBase 服务器状态 status.
查询 hbase 版本 version
ddl 操作
1, 创建一个表
create 'table1', 'tab1_id', 'tab1_add', 'tab1_info'
2, 列出所有的表
3, 获得表的描述
describe "table1"
4, 删除一个列族 disable alter enable 注意删除前, 需要先把表 disable
- disable 'table1'
- alter 'table1', {
- NAME=>'tab1_add', METHOD=>'delete'
- }
- enable 'table1'
5, 查看表是否存在
exists 'table2'
6, 判断表是否为'enable'
is_enabled 'table1'
7, 删除一个表
- disable 'table1'
- drop 'table1'
dml 操作
1, 插入几条记录
- put 'member', 'scutshuxue', 'info:age', '24'
- put 'member', 'scutshuxue', 'info:birthday', '1987-06-17'
- put 'member', 'scutshuxue', 'info:company', 'alibaba'
- put 'member', 'scutshuxue', 'address:contry', 'china'
- put 'member', 'scutshuxue', 'address:province', 'zhejiang'
- put 'member', 'scutshuxue', 'address:city', 'hangzhou'
put 命令比较简单, 只有这一种用法:
hbase> put 't1′,'r1′, 'c1′,'value', ts1
t1 指表名, r1 指行键名, c1 指列名, value 指单元格值. ts1 指时间戳, 一般都省略掉了.
2, 全表扫描 scan
3, 获得数据 get
1) 获得一行的所有数据
2) 获得某行, 某列族的所有数据
3) 获得某行, 某列族, 某列的所有数据
4, 更新一条记录 put(把 scutshuxue 年龄改为 99)
put 'member', 'scutshuxue', 'info:age', 99
5, 删除 delete, deleteall
1) 删除行'scutshuxue', 列族为'info' 中 age 的值
delete 'member', 'scutshuxue', 'info:age'
2) 删除整行
deleteall 'member', 'scutshuxue'
6, 查询表中有多少行
count 'member'
7, 给'xiaoming'这个 id 增加'info:age'字段, 并使用 counter 实现递增
incr 'member', 'xiaoming', 'info:age'
8, 将整个表清空
truncate 'member'
可以看出, HBase 是通过先对表执行 disable, 然后再执行 drop 操作后重建表来实现 truncate 的功能的.
来源: http://www.bubuko.com/infodetail-3059130.html