目录
一, 集群架构
集群角色
工作机制
二, 存储机制
A. 存储模型
B. LSM 与 Compaction
C. Region 分裂
D. 自动均衡
三, 访问机制
四, 鉴权
五, 高可靠
1. 集群高可靠
2. 隔离性
3. 容灾
参考文档
在前面的文章中, 介绍过 HBase 的入门操作知识, 但对于正考虑将 HBase 用于生产系统的项目来说还是远远不够.
一般在对 HBase 做选型之前, 还需要学习一些它的架构原理, 弹性扩展及可靠性方面的知识.
本文来自笔者此前对 HBase 做的学习概括, 可方便于对 HBase 的技术全景进行快速的掌握.
一, 集群架构
尽管 HBase 可以工作在本地文件系统之上, 但在生产环境中, HBase 需要依托 HDFS 作为其底层的数据存储, 而 HDFS 提供了默认的 3 副本来实现数据文件的高可靠.
整个 HBase 集群主要由 Zookeeper,Master,RegionServer,HDFS 所组成, 如下图:
集群角色
Master
HBase Master 用于管理多个 Region Server, 包括监测各个 Region Server 的状态, 分配 Region 及自动均衡等. 具体职责包括:
负责管理所有的 RegionServer, 实现 RegionServer 的高可用
管理所有的数据分片 (Region) 到 RegionServer 的分配, 包括自动均衡
执行建表 / 修改表 / 删除表等 DDL 操作
HBase 允许多个 Master 节点共存, 当多个 Master 节点共存时, 只有一个 Master 是提供服务的, 这种主备角色的 "仲裁" 由 ZooKeeper 实现.
Region Server
Region Server 是真正的数据读写服务器, 即客户端会直接连接 Region Server 进行操作.
一个 Region Server 会包括了多个 Region, 这里的 Region 则是真正存放 HBase 数据的区域单元, 当一个表很大时, 会拆分成很多个 Region 进行存放.
可以说, Region 是 HBase 分布式的基本单位.
Zookeeper
Zookeeper 对于 HBase 的作用是至关重要的.
Zookeeper 提供了 HBase Master 的高可用实现, 并保证同一时刻有且仅有一个主 Master 可用.
Zookeeper 保存了 Region 和 Region Server 的关联信息(提供寻址入口), 并保存了集群的元数据(Schema/Table).
Zookeeper 实时监控 Region server 的上线和下线信息, 并实时通知 Master.
就目前来说, Zookeeper 已经成为了分布式系统架构中最常用的标准框架之一. 除了 HBase 之外, 有许多分布式大数据相关的开源框架, 都依赖于 Zookeeper 实现 HA.
HDFS
HDFS 是 Hadoop 的分布式文件系统, 提供了高可靠高扩展的文件存储能力. 其内部也是一个集群结构, 包含 NameNode,DataNode 角色.
其中 NameNode 存储的是 HDFS 文件目录树的元数据, 包含文件与 Block 的关联信息, 而 DataNode 则是 HDFS 的数据存放节点.
HDFS 作为一个分布式文件系统, 自然需要文件目录树的元数据信息, 另外, 在 HDFS 中每一个文件都是按照 Block 存储的, 文件与 Block 的关联也通过元数据信息来描述. NameNode 提供了这些元数据信息的存储.
工作机制
在一个完整的 HBase 分布式集群中, 各个组件的交互工作如下图所示:
首先 Zookeeper 维护了 Master 与各个 Region Server 之间的关系及状态. 当一个 Client 需要访问 HBase 集群时, 会先和 Zookeeper 进行通信, 并得到 Master 和 RegionServer 的地址信息.
对于创建表 / 删除表 / 修改表来说, 客户端会通过 Master 来进行操作, 而正常的表数据读写, 则是通过找到对应的 Region Server 来操作.
Region Server 的作用
每一个 Region Server 会管理很多个 Region(区域), 这个就是之前提到的 HBase 数据分布式及高可靠的一个单元. 每个 Region 只会存储一个表中的的一段数据, 这是按 RowKey 的区间来分隔的.
而且, 一个 Region 的存储空间有一个上限(Threshold), 当存放数据的大小达到该上限时, Region 就会进行分裂并产生多个新的 Region, 随着一个 Region Server 上的 Region 越来越多, Master 可以监测到不均衡的情况, 并自动将 Region 进行重新分配.
因此, 数据可以源源不断的写入到 HBase 时, 通过这种 Region 的分裂, 自动均衡来支持海量数据的存储.
对于一个 Region 来说, 其内部是由 多个 Store 构成的, 而一个 Store 对应于一个 ColumnFamily(列族).
在实现上一个 Store 对象会包含一个 MemStore 以及多个 StoreFile. 当数据写入 Region 时, 先写入 MemStore(保持有序).
当 MemStore 写满了之后就会 Flush 到 StoreFile, 这里的 StoreFile 就对应了一个 HDFS 中的 HFile 文件.
最终 Region 会对应到多个 持久化的 HFile, 当这些 HFile 越来越多时, Region Server 会执行合并操作 (Compaction) 来合并为一个大的 HFile, 以此来优化读取性能, 这个机制则是基于 LSM 的原理实现的.
HLog 和可靠性
HBase 提供了 HLog 来保证数据写入的可靠性, HLog 本质上就是一种 WAL(事务机制中常见的预写日志), 其同样是通过 HDFS 来持久化的(对应于一个 Sequence 文件). 每个 Region Server 都包含一个 HLog, 其中记录了所有发生在 Region Server 上的数据变更操作.
当数据发生写入时, 会先记录日志到 HLog 中, 然后再写入 MemStore, 最终才持久化到 HFile 中. 这样当 Region Server 宕机时, 尽管 MemStore 中的数据会丢失, 但还可以通过 HLog 来恢复之前的数据, 从而保证了高可靠.
那么, HFile 是否可靠呢? 这点则是由 HDFS 来保证的, 一个 HFile 默认会有 3 个副本.
除此之外, HLog 也是 HBase 实现集群同步复制的关键手段.
二, 存储机制
接下来, 我们看看 HBase 中的数据是怎样被存储及管理的.
A. 存储模型
首先需要澄清的一点是, Region 和 Column Family (简称 CF) 的区别.
Region 是 HBase 分布式存储的基本单位, 其本质上是一种水平切分单位, 可以理解为数据的分片; 而 Column Family(列族)则是垂直切分的单位, 可理解为一种列的分组.
这两者的区别可以参考下图:
无论是 Region, 还是 CF, 都是逻辑上的一个概念, 对于物理上的实现则如下图所示:
存储模块说明
一个 Region 包含多个 Store, 一个 store 对应一个 CF
Store 包括位于内存中的 Memstore 和多个持久化的 Storefile;
写操作先写入 Memstore, 当 Memstore 中的数据大小达到某个阈值后会 Flush 到一个单独的 Storefile
当 Storefile 文件的数量增长到一定阈值后, 系统会进行合并, 形成更大的 Storefile(Compaction)
当一个 Region 所有 Storefile 的大小总和超过一定阈值后, 会把当前的 Region 分割为两个(分裂)
Master 自动检测 RegionServer 上 Region 的分配情况, 自动进行均衡迁移
客户端检索数据, 优先从 Memstore 查询, 然后再查询 Storefile
HFile 结构
HFile 是 HDFS 的存储单元, 其结构如下图:
HFile 由很多个数据块 (Block) 组成, 并且有一个固定的结尾块. 其中的数据块是由一个 Header 和多个 Key-Value 的键值对组成.
在结尾的数据块中包含了数据相关的索引信息, 系统也是通过结尾的索引信息找到 HFile 中的数据.
HFile 中的数据块大小默认为 64KB. 如果访问 HBase 数据库的场景多为有序的访问, 那么建议将该值设置的大一些.
如果场景多为随机访问, 那么建议将该值设置的小一些. 一般情况下, 通过调整该值可以提高 HBase 的性能
B. LSM 与 Compaction
HBase 在存储上是基于 LSM 树 实现的, 与传统的 B/B + 树原理不同的是, LSM 树非常适用于写入要求非常高的场景.
LSM 的原理
将一个大的 B(B+)树拆分成 N 棵小树, 数据首先写入内存中(有序), 随着数据写入越来越多, 内存中的数据会被 flush 到磁盘中形成一个文件;
在读取数据时, 则需要合并磁盘中历史数据和内存中最近修改的操作后返回. 由于数据是顺序写入的, 因此 LSM 的写入性能非常高, 但读取时可能会访问较多的磁盘文件, 性能较差.
为了缓解读性能低下的问题, LSM 树会定时将磁盘中的多个文件 (小树) 进行合并, 以优化读性能.
在 HBase 的实现中, 内存中的数据则是对应于 MemStore, 而磁盘中的数据则对应于 StoreFile (HFile 实现). 当 MemStore 写满后会 Flush 到一个 HFile 中.
随着 HFile 文件的不断增多, Region 的读性能就会受到影响(IOPS 增加). 因此 HBase 的 Region Server 会定期进行 Compaction 操作, 将多个 HFile 合并为一个大的 有序的 HFile.
HBase 中运行的 Compaction 动作有两种:
Minor Compaction, 列族中小范围的 HFile 文件合并, 一般较快, 占用 IO 低
Major Compaction, 列族中所有的 HFile 文件合并, 同时清理 TTL 过期以及延迟删除的数据, 该过程会产生大量 IO 操作, 性能影响较大.
具体的过程如下图所示:
图片出处: http://www.nosqlnotes.com/
Flush 性能影响
如果 Memstore 很小, 意味着 Flush 的次数会很多, 一旦 Compaction 的速度跟不上就会产生大量的 HFile 文件, 这会导致读性能恶化, 为了减缓这个问题, HBase 使用了 In Memory Flush And Compact 的方法, 即数据在 MemStore 中先经分段(Segement),Flush,Compaction 过程, 到达一定大小后再 Flush 到 HFile. 在这里, MemStore 使用了 ConcurrentSkipListMap(并发跳跃表) 来保证一定的读写并发能力. ConcurrentSkipListMap 在容量超过一定大小后性能下降明显, 因此 MemStore 也不能设置得太大, 当前的默认值在 128MB.
触发 Flush 行为的条件包括:
Memstore 级别: Region 中任意一个 MemStore 达到了 hbase.hregion.memstore.flush.size 控制的上限(默认 128MB), 会触发 Memstore 的 flush.
Region 级别: Region 中 Memstore 大小之和达到了 hbase.hregion.memstore.block.multiplier hbase.hregion.memstore.flush.size 控制的上限(默认 2 128M = 256M), 会触发 Memstore 的 flush.
RegionServer 级别: Region Server 中所有 Region 的 Memstore 大小总和达到了 hbase.regionserver.global.memstore.upperLimit * hbase_heapsize 控制的上限(默认 0.4, 即 RegionServer 40% 的 JVM 内存), 将会按 Memstore 由大到小进行 flush, 直至总体 Memstore 内存使用量低于 hbase.regionserver.global.memstore.lowerLimit * hbase_heapsize 控制的下限(默认 0.38, 即 RegionServer 38% 的 JVM 内存).
RegionServer 中 HLog 数量达到上限: 将会选取最早的 HLog 对应的一个或多个 Region 进行 flush(通过参数 hbase.regionserver.maxlogs 配置).
HBase 定期 flush: 确保 Memstore 不会长时间没有持久化, 默认周期为 1 小时. 为避免所有的 MemStore 在同一时间都进行 flush 导致的问题, 定期的 flush 操作有 20000 左右的随机延时.
手动执行 flush: 用户可以通过 shell 命令 flush 'tablename'或者 flush 'region name'分别对一个表或者一个 Region 进行 flush.
除此以外, 为了保证 Compaction 的进度与 Flush 对齐, HBase 会在 HFile 数量到达一定阀值后阻塞 Flush 操作, 如下面的参数:
hbase.hstore.blockingStoreFiles, 触发 Flush 阻塞等待的 StoreFiles 数量上限, 2.x 版本默认为 16
hbase.hstore.blockingWaitTime, 阻塞 Flush 的时间, 2.x 版本默认为 90s
Compaction 策略
Compaction 的目的是优化读性能, 但会导致 IO 放大, 这是因为在合并过程中, 文件需要不断的被读入, 写出, 加上 HDFS 的多副本复制, 则会再一次增加多次的 IO 操作.
此外, Compaction 利用了缓冲区合并来避免对已有的 HFile 造成阻塞, 只有在最后合并 HFile 元数据时会有一点点的影响, 这几乎可以忽略不计.
但 Compaction 完成后会淘汰 Block Cache, 这样便会造成短期的读取时延增大.
在性能压测时通常可以看到由 Compaction 导致的一些 "毛刺" 现象, 但这是不可避免的, 我们只能是根据业务场景来选择一些合理的 Compaction 策略.
一般, Minor Compaction 会配置为按需触发, 其合并的范围小, 时间短, 对业务性能的影响相对可控.
但 Major Compaction 则建议是在业务闲时手动触发, 以避免业务造成严重的卡顿.
关于如何选择合并文件的范围, HBase 提供了以下几种策略:
Stripe Compaction
将一个 Region 划分为多个子区域(Stripes),Compaction 严格控制在单个 Stripe 范围内发生, 这样可以有效降低 Compaction 对 IO 资源的占用.
Stripe 范围是根据 RowKey 来设定的, 因此这适用于 RowKey 单调递增写入的场景
Date Tiered Compaction
与 Stripe Compaction 类似, 但却是基于时间戳来决定子区域的范围, 适合时序数据的场景(仅按时间范围检索)
MOB Compaction
与 MOB 特性绑定的 Compaction,MOB 用于存储文件数据, 其将元数据与文件数据分离存储, 其中文件数据不参与 Compaction, 这样就大大减少了 Compaction 带来的 IO 放大的影响.
RatioBased Compaction
基于比例计算的 Compaction 策略, 在 0.96 之前默认的策略, 该策略会根据下列参数来选择 Compaction 的文件.
hbase.hstore.compaction.ratio: 最小待合并文件数
hbase.hstore.compaction.min: 最小待合并文件数
hbase.hstore.compaction.max: 最大待合并文件数
hbase.hstore.compaction.min.size 最小合并文件总大小
一般由于旧文件都是经过 Compaction 的会比较大, 因此通常会基于新文件来做合并.
关于该策略的详细讨论可参考这里 https://yq.aliyun.com/articles/675998
Exploring Compaction
RatioBased Compaction 演进后的默认版本, 基本算法类似, 但 Exploring 会根据性价比来进一步筛选, 此时考虑的因素为:
文件数量较多(读性能增益), 总体大小偏小(降低 IO 放大)
C. Region 分裂
假设某个 Region 增长到了极限, 将会切分为两个子 Region(原来的 Region 称为父 Region)该过程的步骤如下:
RegionServer 初始化两个子 Region 信息, 写入一个 ZK 节点数据:/hbase/region-in-transition/region-name=SPLITING
Master 通过 Watch 机制获知该 region 状态改变, 此时可通过 Master 的 UI 界面观察到;
RegionServer 创建. split 临时目录, 用于保存 split 后的子 Region 信息;
RegionServer 关闭父 Region 并执行 Flush 操作, 此后在短暂的时间内对于父 Region 的读写操作都会失败;
RegionServer 在. split 文件夹下新建两个子 Region 的目录, 同时分别生成拆分后的 reference 文件(仅仅是引用信息);
RegionServer 将. split 文件夹下的子 Region 的目录拷贝到 HBase 根目录下, 形成两个新的 Region;
RegionServer 修改 hbase.meta 表(连接该元数据表对应的 RegionServer), 将父 Region 标记为 Split 完成, Offline=true, 即表示分裂完成后下线;
RegionServer 打开两个子 Region, 表示可接收读写操作;
RegionServer 修改 hbase.meta 表, 将子 Region 上线的信息写入;
RegionServer 修改 ZK 节点数据:/hbase/region-in-transition/region-name=SPLIT, 此后 Master 获知分裂完成. 如果有正在运行的均衡任务, 则会考虑进一步处理;
可以发现, 整个分裂过程仅仅是创建了一些数据文件的引用及元数据更新操作, 对于业务的影响是非常微小的.
那么, 在分裂后的一段时间内, 引用数据文件还会持续存在, 一直到当子 Region 发生 Compaction 操作时, 才会将父 Region 的 HFile 数据拷贝到子 Region 目录.
关于 Region 切分的细节分析进一步参考
http://hbasefly.com/2017/08/27/hbase-split/?dspinw=x0dnj2&uypslg=eyr0j3
D. 自动均衡
HBase 的 Region 分配和自动均衡是由 Master 节点控制的, 在初始化表时会先分配一个 Region, 然后指定给某个 Region Server. 如果使用预分区, 那么 Master 会按照轮询的方式平均分配到每个 Region Server.
此后, 随着 Region 不断的增大和裂变, Region Server 上的 Region 数量开始变得不均衡.
如果开启了自动均衡开关, Master 会通过定时器来检查集群中的 Regions 在各个 RegionServer 之间的负载是否是均衡. 一旦检测到不均衡的情况, 就会生成相应的 Region 迁移计划.
关于均衡的方式, HBase 提供以下两种策略:
DefaultLoadBalancer 默认的策略, 根据 Region 个数来进行均衡
StochasticLoadBalancer 根据读写压力评估来进行均衡
由于 HBase 的的数据 (包括 HLog,StoreFile 等) 都是写入到 HDFS 文件系统中的, 因此 HBase 的 Region 迁移是非常轻量级的.
在做 Region 迁移时, Region 所对应的 HDFS 文件是不变的, 此时只需要将 Region 的元数据重新分配到目标 Region Server 就可以了.
迁移过程的步骤包含:
1. 创建 Region 迁移计划, 指定 RegionID, 源 Region Server 和目标 Region Server;
2. 源 Region Server 解绑, 此时会关闭 Region
3. 目标 Region Server 绑定, 重新打开 Region
三, 访问机制
HBase 支持多种读写客户端访问方式, 具体包括:
基于 Java Client, 一般是通过 RPC 调用 HBase.
基于 RestFul API, 需要启用 REST Server 代理组件, 该组件通过 Java Client 实现.
基于 Thrift API, 需要启用 Thrift Server 代理组件, 该组件通过 Java Client 实现.
基于 MapReduce 的批处理 API
基于 HBase Shell, 其内部也是通过 Java Client 实现的.
无论使用何种调用方式, 始终还是离不开最基础的 RPC 调用流程.
该流程的交互逻辑如下图所示:
连接 ZooKeeper
在进行数据操作之前, 客户端首先需要接入 ZooKeeper, 并初始化一个 ZooKeeper Session.
该 Session 由 ZooKeeper Client 与 ZooKeeper Server 端之间创建, 并通过心跳机制保持长连接
获取 meta Region 路由信息
HBase 将 Region 分布的元数据存放在 hbase.meta 这个表中, 该表记录了每一个用户表 Region 的路由以及状态信息, 它的 RowKey 包含如下的信息:
表名 Table Name
- Region StartKey
- Region ID
客户端通过 Zookeeper 先找到 meta Region 所在的 Region Server, 然后获得 meta Region 信息.
之后根据操作的 RowKey 就可以定位到对应的 Region ID, 最后再通过 Zookeeper 的映射表就可以得到 Region 所在的 Region Server 了.
需要注意的是, 客户端一般会对 meta Region 信息进行缓存, 避免每次都要耗费时间读取.
读写 Region Server
在得到真实数据所在的 Region Server 之后, 客户端便通过 RPC 接口向目标 Region Server 发起访问.
对于一些批量请求, 客户端会先通过 Region 进行分组, 再并发的向多个 Region Server 发出请求.
对于使用 REST Server 或是 Thrift Server 等中间组件的情况, 调用流程如下图:
四, 鉴权
HBase 的安全同时依赖于 Zookeeper,HDFS.
ACL 权限
HBase 支持 RWXCA 权限模型设置:
读取(R) - 可以读取给定范围的数据.
写入(W) - 可以在给定范围写入数据.
执行(X) - 可以在给定范围内执行协处理器端点.
创建(C) - 可以在给定范围内创建表或删除表(甚至不创建它们).
管理员(A) - 可以执行群集操作, 例如在给定的范围内平衡群集或分配区域.
需要以最小权限原则为数据库表配置对应的用户权限
同样, 为了保证整体的安全性, 需要对 ZooKeeper,HDFS 都设定合理的 ACL 控制, 包括文件系统.
身份认证和授权
HBase 集群中可使用 KerberOS 来实现节点之间的身份鉴权, 包括:
节点接入 Zookeeper
节点连接 Master,RegionServer
节点接入 HDFS
外加的 REST Server,Thrift Server
Kerberos 是一个常见的身份认证及鉴权协议系统, 使用 Kerberos 的系统在设计上采用 C/S 结构及 AES 对称加密技术, 并且能够进行双方认证.
支持防止窃听, 防止 replay 攻击, 保护数据完整性等特性. Kerberos 认证过程需要依赖于单独的 Kerberos Server(KDC), 一个认证过程如下图:
Kerberos Authentication: 客户端请求认证服务器(AS), 获得 Ticket Granting Ticket (TGT)
Kerberos Authorization: 客户端通过 TGT 票据请求 TGS(Ticket 授权服务), 通过后会获得一个授权的 Service Ticket
Service Request: 客户端使用 Service Ticket 访问目标服务, 目标服务会对 Service Ticket 进行本地校验, 如果通过则表示认证成功.
关于 KerberOS 的详细原理, 可以参考 NoSQL 漫谈 - 图解 KerberOS 这篇文章
对于 HBase 集群来说, 各个节点使用 KerberOS 认证时, 需要先配置 keytab 文件, 该文件中就记录了实体 ID(pricipal), 以及密钥的信息.
而这些实体 ID 及密钥都是由 KerberOS 服务生成并管理的.
传输层安全
对客户端 RPC 设置 hbase.rpc.protection=privacy 可以开启 RPC 加密功能, 这对性能存在一定损失(约 10%)
还可以使用 TLS 传输协议进一步提升安全性.
五, 高可靠
1. 集群高可靠
Zookeeper 高可靠
Zookeeper 本身是集群多节点的架构, 其内部使用 Paxos 算法来实现选举和数据的强一致性.
在部署上通常可以选择 3 节点的架构来保证可靠性.
Master 高可靠
HBase 可以开启 Backup Master 来实现 Master 节点高可用, 同一时间内只有主 Master 可以工作, Master 宕机后由 备 Master 自动接管
Master 的 HA 机制是借助 Zookeeper 完成的
RegionServer 高可靠
Region Server 通常会部署为多个节点, 每个节点分别接管不同的 Region
而 Master 会对 Region Server 的状态进行检测, 一旦发现 Region Server 宕机, 则会将该 Server 上的 Region 列表重新指派给一个新的 Region Server.
此外, Master 还会将已宕机的 Region Server 的 HLog 做一定拆分, 并分发到新的 Region Server 上做数据恢复.
该过程不涉及数据迁移, 只是元数据的变更, 操作数据量少并不会对业务造成很大的影响.
数据高可靠
Region Server 本身提供了 HLog(WAL) 来提供断电保护, 当 Server 异常宕机时, MemStore 内丢失的数据可以通过 HLog 来回放恢复.
HDFS 高可靠
HDFS 本身提供了一系列的可靠性机制, 包括:
NameNode 可以部署多个
DataNode 可以部署多个
HFile 存在多副本(默认 3 个), 保证了数据文件可靠性
2. 隔离性
在部署上, 通常依据一些原则策略来保证可靠性:
控制节点与数据节点分离部署
主备 Master,Region 节点分离部署
NameNode 之间, DataNode 之间分离部署
数据节点磁盘物理隔离
3. 容灾
尽管 HDFS 提供了三副本的机制, 但对于关键业务来说, 往往需要支持跨机房的容灾能力.
HBase 支持 Replication 机制, 该机制设计的主导思想是基于操作日志 (put/get/delete) 做数据同步的功能, 这类似于 MySQL 的 BinLog, 或者是 MongoDB 的 OpLog.
Replication 的关键就在于前面所提到过的 HLog, 这个日志除了用作数据断电保护之外, 还被用来实现集群复制的功能.
如下图:
客户端的 put/delete 操作会先被 RegionServer 写入本地的 HLog , 之后由一个独立的线程将 HLog 内容以缓冲写的形式推送到 Slave 集群中的某个 Region Server 上.
整个复制的 HLog 信息, 包括复制偏移量都会保存在 Zookeeper 上, 同时复制动作是异步的, 即不会阻塞当前的客户端读写.
参考文档
HBase 深入浅出
详细介绍了 HBase 的由来以及特性, 文中提供了 HBase 集群, 存储机制的一些简介, 非常适合入门阅读
HBase 集群组件通讯端口(较全)
HBase - 所有 Region 切分的细节都在这里了
一条数据的 HBase 之旅
Hbase 架构与原理
https://www.jianshu.com/p/3832ae37fac4
HBase 的一致性
https://www.cnblogs.com/captainlucky/p/4720986.html
深入理解 HBase Memstore
https://www.cnblogs.com/cxzdy/p/5121365.html
HBase Region Balance 实践
http://openinx.github.io/2016/06/21/hbase-balance/
阿里 Hbase 的业务和容灾实践
关于 HBase 的安全
http://www.mamicode.com/info-detail-449760.html
图解 KerberOS
HBase 官方文档中文版
来源: https://www.cnblogs.com/littleatp/p/12079507.html