第五章:大数据 の HBase 进阶
本课主题
- HBase 读写数据的流程
- HBase 性能优化和最住实践
- HBase 管理和集群操作
- HBase 备份和复制
引言
前一篇 HBase 基础 (HBase 基础) 简单介绍了NoSQL是什么和重点讨论 HBase 数据库的特点,在这一篇会进一步介绍 HBase 的其他特性和机制,比如读写数据的流程,在读写过程中 WAL,MemStore 的作用,还会谈谈一些数据缓存机制,明白在什么场景下需要用那一种缓存策略?如何对频繁使用的数据进行快速响应,从检索上提升查询效率和从内存层面上运用不同组合来优化。还会从 HBase 表设计、Scama 设计、索引选项、缓存设置、Region 的预拆分和数据倾斜的角度去了解 HBase 的性能优化和最佳实践,最后会谈谈一些 HBase 维护的操作,比如备份和复制,希望读者看完这篇文章可以了解以下几点:
- 了解 HBase 在读写数据时 WAL, MemStore 和 BlockCache 的作用;
- 了解 HBase 的数据缓存机制和如何通过参数调优来达至最佳效果;
- 了解如何对 HBase 进行性能调优
- 了解 HBase 的备份和复制;
HBase 读写数据的流程
HBase 写操作
MemStore 是数据块中的一个内存区域,它可以提升写出数据的效率,新增或更新的数据会写入 MemStore,然后再由 MemStore 写入磁盘。当客户端收到一个 Put 请求时会先查询 hbase:meta 元数据来定位将要写入的数据的 Region 位置,具体操作细节会交给 Region 实体来完成;
[下图是写入数据的步骤]
- 先写入 WriteAheadLog (WAL) 日志中,它记录数据操作整个流程,WAL 是写入 HDFS 集群文件系统上,一旦写入动作失败,可以从 WAL 恢复过来。默认参数 writeToWAL 为 true,意思是数据会先写入 WAL 日志;
- 然后才写入 MemStore 内存块中。MemStore 内存块如果满了,才会刷新写入本地磁盘的 StoreFile 上。刷新是由独立的 RegionServer 线程来完成的。注意:MemStore 只会在内存区域存在的,如果数据写入了 MemStore 但还没来得写入磁盘已经漰溃,此时,数据便会掉失。
HBase 文件类型
- HLog 是 HBase 的日志文件,它使用了 WAL 的数据格式,它是一个标准的 Hadoop SequenceFile,存储了 HLogKey 以及实际数据,HLogKey 用于服务器 Crash 后恢复那些未被永久存储的数据;
- HFile 用于存储文件的格式,HFile 分解成更小的片段叫做块。默认的块大小是 64K,任何时候的操作都是整块的读取
- 一个 HFile 是由多个块组成的,在 HDFS 上一个 HFile 可以是 GB 大小,HBase 块大小可以在列族级别进行配置,小块可以增加随机读的速度,大块可以提高扫描的性能
以下是MemStore 刷出 StoreFile 的条件
- 达到 hbase.regionserver.global.MemStore.upperLimit,默认是 0.4 或者是 heapSize 的 40%;
- 达到 hbase.hregion.MemStore.flush.size,默认是 128MB;
- 达到 hbase.hregion.preclose.flush.size,默认是 5MB 并且 region 已经关闭;
以下是MemStore 刷新阻塞更新的条件
- MemStore 大小达到 hbase.hregion.MemStore.flush.size (128MB) 和 hbase.hregion.MemStore.block.multiplier (2)
RegionServer 的 Crash 重启流程,如果 RegionServer 崩溃了,由于 MemStore 在内存中,所以数据会掉失,但是,最近的更新也会在 WAL 日志里,存储在 HDFS 上;Region 存储文件 (HFile) 也会存储在 HDFS 中,HDFS 默认复制存储的块,集群里所有节点能够访问在 HDFS 中的文件;Master 可以测出 RegionServer 的失败,Master 协调处理日志所有分拆动作;WAL 分拆是由集群中 RegionServer 来完成,Master 可以指派 Region 到其他 RegionServer 上,当完成分拆之后,RegionServer 应用 WAL 相关的内容。
[下图是写入数据和读取数据与 WAL 和 BlockCache 的关系]
HBase 读操作
当客户端发起 get 的请求,首先会查询 RegionServer 来定位数据在那个 Region 上,然后同时读取该 Region 上的 StoreFile 和 MemStore, 读取数据后会缓存在一个 BlockCache,用于后续的查询,这种缓存的方法可以加速后续频繁访问数据的速度。最后 RegionServer 按照客户端发起请求的数据从 BlockCache 把相关的数据返回给客户端。
[下图是读取数据的步骤]
HBase 数据块缓存
HBase 的 BlockCache 可以通过缓存元数据 hbase:meta 和列族数据信息来提升数据检索速度,HBase 有两种类型的缓存实现
- 第一类是 LruBlockCache,它是最初的HBase 缓存机制,是将 onheap 内存 (JVM Heap) 用于缓存;
- 第二类是 BucketCache,它是新的HBase 缓存机制,它不局限于 onheap 内存,可以将它配置为 offheap,这样就可以使用 JVM 以外的内存;
- 内存的清理策略是用最近使用原则 Least Recently Used (LRU);
LruBlockCache 的特性
LruBlockCache 的默认的块大小是 64KB,缓存信息类型包括提供 RegionServer 服务的具体 Region 信息、HFile 的索引信息,实现 HBase 在 HFile 里快速查找数据和 Bloom Filters 信息 (当启用此功能时),实现缩短查找时间的目的;当 LruBlockCache 写满之后,最近最少使用的块会依据访问的优先级进行清理换出。LruBlockCache 的访问优先级,访问优先级分组用于缓存系统确定那些块被清除掉,LruBlockCache 的缓存数据块被按照访问优先级被分成三组:
- (优先级别 - 低) Single:当我们只有一次读取的数据,这个级别的数据块是第一时间就会被挤出去
- (优先级别 - 中) Mutile:读取多次数据的缓存,这个级别的数据块是当块中没有 SINGLE 级别的数据才会被挤出去
- (优先级别 - 高) n-Memory:对列族属性中的 IN_MEMEORY 设置为 true,这个级别的数据块是最后才会被挤出去,Catalog 表是默认启动了 IN_MEMORY 表的特性;
Single > Mutile > In-Memory 愈容易从内存挤出
BucketCache 的特性
BucketCache 管理以 buckets 形式组织的内存区域,使用 BucketCache 可以减少垃圾回收,因为它会直接管理 BucketCache 分配,而不是由 GC 管理;如果 BucketCache 被部署为 OffHeap,则内存根本不受 GC 管理。OffHeap BucketCache 中狻取数据的速度比 OnHeap Cache 要慢,但空间会比较大,因为垃圾收集较少,所以在读取数据时延达会较少。
缓存的三个策略
使用缓存有以下三个策略,有多种配置缓存的机制:
- LruBlockCache 缓存机制:把元数据和列族信息缓存起来,如果 BucketCache 机制没有启动时,默认是启动 LruBlockCache 的;
- 混合缓存机制,运用 LruBlockCache 和 BucketCache 两个缓存:这个策略会在 LruBlockCache 层面上缓存元数据,在 BucketCache 层面上缓存列族信息,这时启动 BucketCache 缓存机制后默认的操作;
- 可以使用一级和二级缓存机制 (Raw L1+L2):这个机制把元数据和列族信息缓存在LruBlockCache (一级缓存),然后从 LruBlockCache 读取数据缓存在 BucketCache (二级缓存),如果要启动这个缓存机制,要先在 hbase-site.xml 中配置 hbase.bucketcache.combinedcache.enabled=false,这个参数默认是 true;
通过将列族的 IN_MEMORY 属性设置为 true 可以确保该列族的数据只有在绝对必要的情况下才会从缓存中清除。
- 当 BLOCKCACHE = false 和 IN_MEMORY = false,这意味著没有缓存;
- 当 BLOCKCACHE = true 和 IN_MEMORY = false,这意味著使用 最近使用原则 Least Recently Used (LRU) 缓存;
- 当 BLOCKCACHE = true 和 IN_MEMORY = true,这意味著缓存度是最長久的,有优先级别来缓存数据;
启动 BucketCache
把参数 hbase.bucketcache.size 大于 0,BucketCache 默认部署在 OffHeap 上,如果要使用 onHeap 内存,需要将 hbase-site.xml 文件中的 hbase.bucketcahce.ioengine=heap,如果要使用 file-baed 缓存,则需要把 hbase.bucketcahce.ioengine=file:PATH_TO_FILE,使用 BucketCache 有助于减少 JVM 的垃圾收集,以便缓解 RegionServer 的历力,这时因为 LruBlockCache 在 onHeap 上存储较少的对象;在OffHeap 模式下,BucketCache 管理所有内存的分配 (没有引入 GC)。BlockCache 可以通过 RegionServer 的网页界面端口来查询缓存的使用情况。
禁用缓存
可以在每一个列族上禁用读取缓存,使用 HBase Shell 来将读取时不需要缓存的列族 BLOCKCACHE 参数设置为 false,使用 Java APi 在 scan 和 get 操作时使用 setCacheBlocks(false) 方法来禁用缓存,但注意是的我们不能禁用 metadata 的缓存,因为元数据信息会频繁地被使用,那应该在什么情况下可以禁用缓存,如果数据只是使用一次,不用反覆检索或者查找就不需要使用缓存。
BlockCache 报告
可以通过 RegionServer 网页界面的端口 60030 会显示块缓存的详细情况,信息包含当前的配置,当前使用情况,Time-in-the-cache,块数量和块类型
HBase 性能优化和最住实践
ColumnFamily 的优化策略
列族的名称必须是可打印字符;列族的名称和列的描述命名尽量简短,因为 HFile 中的每一行都会包含这些信息,过长的命名会浪费存储空间;不经常使用的数据分开设计和使用不同列族存储设置时分开设计;每张表不超过三个列族;列族允许数据分离,设计列族时,确保同时访问的数据尽量存储在同一个列族中,常用的信息放在同一个列族中;刷新 (Flush) 和 紧缩 (Compact) 操作是以 Region 为单位的,Compact 操作是以每个列族中 StoreFile 的数量触发的,如果某个列族非常大,在进行 Flush 时,其他列族的数据可能会被刷新出去,导致数据掉失,所以如果列族愈多,I/O 负载会愈大;Compresison、Bloom filter 和 replication 都是以列族为单位进行设置的;
[下图是列族常用的属性]
大多数列族都可以压缩,但不建议对存放 JPEG 和 PNG 等已经压缩的文件再进行压缩,压缩解码器有 GZIP、LZO、SNAPPY,选择压缩解码器需要权限压缩后的大小以及压缩时间两个因素。
alter 'movie', {NAME => 'desc', COMPRESSION => 'SNAPPY'}
BlockSize 大小的优化策略
BlockSize 块尺寸用于每次读请求读取的最小数据量,大值可以提高扫描的性能,小值可以增加随机读的速度
BloomFilter 的优化策略
Bloom Filter 是由 Howard Bloom 在1970年提出的二进制向量数据结构,它具有很好的空间和时间效率,能检测一个元素是否属于某个集合。Bloom Filter 是一个数据结构,它可以检测某个数据片是否存在,存在的检测结果是"no" 或者是"maybe",结果 no 表示一定不存在,结果 maybe 不表示数据一定存在。HBase 支持使用 Bloom Filter 改进读取性能,Bloom Filter 的好处是无需读取每个存储文件,让 RegionServer 可以忽略掉不包含某些行 (Row) 或者是行和列 (RowCol) 的文件。
alter 'movie', {NAME => 'desc', BLOOMFILTER => 'ROW'}
Bloom Filter 的最佳埸景是如果有大量的文件是无需读取的,因为它的目的是通过减少大量读取文件的数量来提升读取性能;批量更新数据,这样行 (Row) 分布在少数的存储文件中,Bloom Filter 不适合用于所有行 (Row) 都需耍定期更新,并且这些行分布在不同的存储文件中。虽然 Bloom Fiilter 存放在 StoreFile 中,但它不会给存储带来太大的额外负担。
Schema 的优化策略
设计模型的基本原理包含 Schama 设计X总了 HBase 设计的所有基本方面,其中要思考的是设计行键和列族、将数据隔离开到不同的列族、选择合适的压缩机制和块大小等,通用的设计技巧有优化索引、数据分区和一致性的 Hash 值,在设计时要充分考虑 HBase 体系结构的限制,因为在 HBase 上关联表的开销会非常大,所以应该尽可能避免 Join 操作,数据应该是反规范化设计以避免连接操作,其次行键 (RowKey) 必须更智能,以便利用排序来优代读取。在表的设计有 Tall-Narrow 和 Wide-Flat,它们两者占用的存储空间都是相同的:
- Tall-Narrow (高瘦型),这是一种 "列很少行很多" 的设计,它的原子性更弱,因为所有数据在不同行,all-Narrow (高瘦型) 通常会把更多的细节放在行键设计上,如果你进行 scan 操作,建议使用高瘦型;
- Wide-Flat (矮胖型),这是一种 "列只有一行但有多个列" 的设计,表的行是不可以拆分,如果行非常宽,那么你可以让每个 Region 只有一行,如果你需要每一次查询多种属性的话,可以使用矮胖型;
索引的选项
如果执行许多实时查询 (Ad-Hoc Query),有可能需要使用 RDBMS 系统,如果在 HBase 上要进行关联操作都需要额外的空间和运算,在关系型数据库中的索引管理是更成熟更先进,但 HBase 在大数据情况下扩展会更好,如果必须在 HBase 上进行二次索引,可以有以下方法:
- 使用 API 运行过滤查询,但这不利于一张大表进行全表扫苗;
- 创建一个第二索引,可以通过一个 MapReduce 作业定期更新表,或者在数据发布到集群时双写 (Dual-Write);
- 创建汇总表 (Aggregrate Table),这适用于时间跨度大的数据,通常通过 MapReduce 作业生成,用于预先计算实时查询的数据,例如:计算表中某个值不同实例的数目,并将这些汇总的计数写入另一张表中;
缓存的优化策略
在 HBase 中如何配置缓存,LruBlockCache 是用于读取 OnHeap,是基于内存的缓存,当缓存达到上限时会使用 LRU (Least Recently Used) 算法来清除数据;新 BucketCache 特性允许一级(L1) 和二级(L2) 缓存,BucketCache是默认启动的;如果你是数据使用率很低或者是只用一次,可以通过手动修改列族的 BLOCKCACHE 属性为 false 来禁用数据缓存,这样可以避免很少访问的列族数据污染了缓存区。
如何配置一级和二级缓存
- BucketCache 特性允许设置一级缓存和二级缓存,BucketCache 缓存机制在新 HBase 版本之后是一个默认选项,一级缓存仅存储元数据信息,二级缓存仅存储列族数据;
- 通过设置 CACHE_DATA_IN_L1=true 来对某特定列族的数据设定为一级缓存;
- 通过设置 BUCKET_CACHE_COMBINED_KEY=false,可以将 BucketCache 作为一级缓存和二级缓存使用;
在配置缓存时我们需要考虑是否调用 OnHeap 或者是 OffHeap 的内存,还有使用的应用类型是 Read-Heavy 类型或者是 Write-Heavy 类型,可以通过调整缓存配置来实现性能要求。 在生产环境下建议给 HBase Master JVM 分配 1G 的内存,给 HBase Region Server JVM 分配 12G~16G 的内存, 如果较大的 Heap 尺寸会导致较长时间的 GC 垃圾回收时间,剩馀的系统内存用于 Kernel 的缓存,可以在 hbase-env.sh 里进行内存设置配置
export HBASE_REGIONSERVER OPTS="-Xmx12g -Xms12g -Xmn128m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70" export HBASE_MASTER_OPTS="-Xmx1000m"
数据倾斜导致的热点问题以及优化策略
当只有很少的 RegionServer 处理绝大多数工作负载时就会发生热点问题,因为这会导致集群资源使用不均,行键如果顺序或者是时间序列就有可能导致热点,因为这会导致写出数据都是在同一个 Region 中,如果能够把数据倾斜的数据打散就有可能解决热点问题,以下是几个解决数据倾斜的热点方案:
- 加 salt:在真正的数据前面放一个较小的 Hash 计算后的值,以便将行键 RowKey 随机打散,e.g. <salt><timestamp>
- 字段前置:将行键 RowKey 后面的内容移到递增或者是时间戳字段之前,e.g. <sourceid><timestamp>
- 伪随机数:使用 MD5 之类的单向 HASH 值对数据进行处理:<md5(timestamp)>
Region 预拆分的优化策略
在实际生产环境下是不建议 Region 的数量过少,RegionServer 建议为 20 到小几百个 Region 服务,因为一个 RegionServer 上如果有过大的 Region 会导致扩展问题。每个 RegionServer 服务的 Region 并不是显式配置的,这是由数据量和最大 Region 的大小所决定的。公式是:Region 拆分大小等于该服务器上同一张表的 Region 个数的平方乘以 Region Flush Size 或者设置的最大 Region 拆分大小,取两者之中较小的值。可以修改 hbase.hregion.max.filesize 来决定 Region 的拆分大小,建议 10GB。
Region 预拆分的效果
通过 Region 预拆分来提高 HBase 的性能,预拆分后数据量加载效率更高,以下是创建预拆分 Region 的例子:
CREATE 'myTable', 'cf1', 'cf2', {SPLIT => ['A','M','Z']}
例如向一个新表中的批量加载 100GB 的数据,filsize 初始值为 10GB,当进行预拆分 Region 后,这样每个 Region 都可以得到10GB数据,如果要增加更多数据,可以预拆分成 10-20 个 Region,这样可以避免随著数据的增加而出现自动拆分。预拆分 Region 是离线处理过程,Region 会在拆分的过程中短暂离线,手工拆分 Region 可以减少表的热点问题,如果想停用预拆分 Region 功能,可以对参数 hbase.hregion.max.filesize 设置一个较大的值,比如 100GB,但要注意后续要继续启用拆分,Region 是可以合并在一起,可以利用 HBase Shell 的 merge_region 命令在线完成合并。
HBase 管理和集群操作
HBase Master 的工作
HBase Master 处理 HBase 集群下很多核心功能,包括协调 RegionServer 并管理故障转移,负责将 Region 重分配到其他 RegionServer 上;处理表和列族的修改和增加,同时更新 hbase:meta 数据,也会管理 Region 变化,例如 Region 分裂或分配的收尾工作,多个 Master 可以在同一时间运行,但只有一个 Master 是 Active 状态,当 Master 失败后,其他 Master 竟争成为 Active 状态。
HBase Master 后台进程
HBase 的 LoadBalancer 进程用来将一个表的多个 Region 分发到多个 RegionServer 上;Catalog Janitor 进程检查不可用的 Region 进行垃圾回收 ;Log Cleaner 进程用于删除陈旧的 WAL 文件。
HBase RegionServer 的工作
RegionServer 处理数据的移动,通过 get 和 scan 读取数据然后将数据回传给客户端,存储所有客户端 put 进来的数据和标记所有客户端 delete 的数据;处理所有紧缩动作包括小紧缩 (minor compaction) 和主紧缩 (major compaction);处理所有 Region 的分裂;维护 BlockCache (其中包括 Catalog table、索引、Bloom filter 和数据块都在 BlockCache 中);管理 MemStore 和 WAL,Put 和 Delete 的操作会先写入 WAL 然后才写入 MemStore;MemStore 会不定期刷出,接收来自 Master 的新 Region,为其提供服务,必要时重演 (Replay) WAL。
HBase RegionServer 后台进程
RegionServer 有一个 CompactSplitThread 进程来查找需要拆分的 Region (大于最大 FileSize 的 Region) 和处理小紧缩;MajorCompactionChecker 进程是检查是否需要进行主紧缩;MemstoreFlusher 进程检查 MemStore 是否过满需要被刷出到磁盘;LogRoller 进程用于关闭 WAL 并创建一个新文件。RegionServer 和 DataNode 必须在同一个 节点上,因为可以实现 RegionSever 在读取数据时达到数据本地化的效果。
HBase 与 ZooKeeper 和高可用机制
ZooKeeper 是一个分布式协调工作,一组 ZooKeeper 节点配置在一起工作叫做 Quorum,在 Quorum 中,所有数据在所有节点上间保持同步,多个节点同时运行确保 ZooKeeper 的高可用性,HBase 大量使用 ZooKeeper 来维护状态和配置信息,ZooKeepr 的 Quorum 允许多个 HBase Master 同时运行,每一个 HBase Master 竞争 ZooKeeper 管理的一个锁来争取成为 Active Master,如果某个 Master 在一定时间内无法获取锁,那么其他 HBase Master 将竞争这个锁。
- ZooKeeper 对延达和时钟的偏移非常敏感,需要有充足的带宽和不堵的网络,需要配置 NTP 来确保集群的时钟是同步的;
- 如果同时部署 HBase 的守护进程和 ZooKeeper,那么请将 ZooKeeper 部署到另外的磁盘上,这样做可以减少 I/O 争用和提升 ZooKeeper 的性能,任何共享资源都需要达到高性能。
HBase 使用 ZooKeeper 来检测 HBase Master 和 RegionServer 的故障,因为 JVM GC 会导致长时间暂停,因为在暂停的过程中,JVM 什么都不能执行,这些暂停会导致 RegionServer 的超时,系统会以为 RegionServer 出现故障,所以目的是要尽量降低垃圾回收的时间。HBase 默认超时时间是 90 秒,RegionServer 必须在这个时间内与 ZooKeeper 进行通讯,否则系统会认为 RegionServer 已经崩溃,建议把超时时间降低为 60 秒。
在生产环境下不建议 ZooKeeper Quorum 和 DataNodes、RegionServers 部署在一起;可以创建独立的 ZooKeeper Quorum,所有节点和客户端必须能够访问 ZooKeeper 集合体;Quorum 有3个节点时备高可用性。
HBase 集群部署方案
用于概念验证 (Proof of Concept) 的集群可以让所有 Master 节点共同于一个节点上,包括 HBase Master、ZooKeeper、NameNode、Secondary NameNode,小型生产环境集群应该让 HBase Master 和 ZooKeeper 在独立的节点上部署,与集群中的其他 Master 节点分开,生产环境下,需要考虑引入备用的 HBase Master 部署高可用集群。无论多大的杰群 RegionServer 和 DataNode 必须位于同一个节点上,以便实现 RegionServer 读取数据的本地化。
HBase 均衡器
HBase 和 HDFS 都有均衡器,HBase 使用均衡器来均衡 RegionServer 所服务的 Region;HDFS 的均衡器通过移动 HDFS 上的数据块到不同节点上的 DataNode 实现数据均衡。HDFS 的均衡器对 HBase 是无法感知的,当添加新的节点时需要运行 HDFS 均衡器,不过 HDFS 均衡器会破坏 HBase 的数据本地性,因为原本有一个 RegionServer 的数据会被移动到另一个 RegionServer,但会在主紧缩操作完毕或者 Flush 刷新后,慢慢地实现数据本地化。
如何使用均衡器
HBase 有一个负载均衡器进程,基于 RegionServer 所服务的 Region 数量来进行均衡,均衡器是表感知的,它可以将一个表的 Region 分散到多个 RegionServer 上,均衡器默认每 5 分钟执行一次,均衡器在移动期间,表会暂时的离线,在主紧缩实现之前,移动的 Region 会暂时失去了数据本地性。
HBase 相关错误
HBase 对数据服务信息有严格的要求,每个 Region 必须分配和部署到一个 RegionServer,每个表的行键必须只包含在一个 Region 里,HBase 数据会写出到 HDFS 和 HBase 的 Catalog 表,HBase 能通过 HDFS 上的数据进行自我修复然后更新 Catalog 表以保持匹配。
修复 HBase
有些问题可以在线,但有些问题不得不通过离线进行修复,离线检测的是指 HBase 正在运行,但是集群处于未被激活的状态;一些不一致可能是暂时的,有些错误会在过度期显示出来,但是再检查又不会显示出来,在升级到下一个版本需要执行一次检查,每一个修复操作的严重程度和修复难度都不一样;修复离线问题是最复杂的,不一致可能发生有表和 Region 级别,例如:
- Region 的元数据信息没有存放到 HDFS 上 (离线);
- 一个 Region 与另一个 Region 部分重复 (离线);
- 一个 Region 没有分配给 RegionServer (在线);
- 超过一个 RegionServer 为一个 Region 提供服务 (在线);
- 表的部份行键没有包含在一个 Region 里 (在线);
- hbase:meta 显示 Region 分配不正确 (在线);
建议使用一个单独的集群来试验可能的解决方案并进行验证,拷贝表到一个独立的集群后,测试修复并解决任何问题,修复测试完毕后再应用到集群中
用 hbck 修复 HBase
HBase 有一致性检查工具叫 hbck,这类似于文件系统的检查工具,它会检查所有表和 Region 是否合符 HBase 要求,但不会做仕何的修改,以 hbase 用户身份运行 hbck 需要有文件访问权限
sudo -u hbase hbase hbck
如果 HBase 没有问题,最终的结果会显示 Status: OK;如果 HBase 有问题,最终的结果会显示 inconsistencies detected. Status: INCONSISTENT,常规的 HBase 操作可能会导致暂时的不一致,过一会儿再进行检查来确认;运行 hbck,选择修复模式能修复不一致问题 (仅在所有其他方式都无效才尝试 hbck -repair)
sudo -u hbase hbase hbck -repair
运行修复后,hbck 会运行另一个一致性检查,验证所有问题是否已经修复,成功修复后的输出结果是 0 inconsistencies detected. Status: OK,如果修复后还是显示不一致,运行另一个 hbck 检查校验来查看异常错误。
HBase 安全
HBase 有内置的安全功能可以限制访问和权限,需要在启动 Kerberos 的 Hadoop 集群中启动安全,用户被受于特定的权限,可以受于的权限级别有全局或者 namespace、表、列族、列描述符或者每个 Cell,用户被受于的权限有 Read、Write、Execute 或者 Admin;启动安全可能会将最大的吞吐能力降低 5~10%。
如何配置 HBase 安全
- 必须配置 HBase 使用安全的 RPC 引擎;
- Kerberos 必须被加到 HBase 配置中;
- HBase Master、RegionServer 和客户端必须用安全的 ZooKeeper 进行连接;
- 必须启用控制访问的 HBase 协处理器;
- 访问 HBase 必须授于访问权限;
在 HBase Shell 中授于权限例子 e.g. grant 'username', 'permissions', <table>,<colfam>,<coldesc> ,R=读取表、W=写出表,X=在表上执行协处理器, C=Create,Alter,Delete 表,A=管理表。
授于 create、delete 和 alter 给所有表
hbase> grant 'enmoedu', 'C'
授于 read、write 给所有表
hbase> grant 'enmoedu', 'RW', 'movie'
授于 read 给一个特定的列描述符
hbase> grant 'enmoedu', 'R', 'movie', 'desc', 'title'
从一个用户回收一个权限
hbase> revoke 'enmoedu', 'RW'
HBase 备份和复制
HBase 复制
HBase 有多种备份方法,可以对所有表进行 put 和 delete 操作,使用 HBase 的内置复制或者在集群之间手工拷贝表,HBase 集群支持之间的复制,新添加或删除的数据会自动添加到其他集群,复制是基于每一个列族完成的。
HBase 复制的规则
HBase 通过传输 WAL 日志来复制数据,虽然复制是异步的,但最终也会一致的,只有写入WAL的操作才会被复制,没有写 WAL 的 put 操作是不会被复制,批量导入是不会被复制 (因为该操作禁用了 WAL),更新操作是原子性的,它们至少会被傅输一次。HBase 会使用 ZooKeeper 来维护复制状态,e.g. 要复制的集群列表、要复制的 WAL 日志列表和已经复制完毕的日志位置。
HBase 复制警告
集群间通常相差1~2秒,这是假定了有充份的宽带,如果宽带不足,集群备份会滞后;命令执行的同时,复制就开始了;列族的设置调整不会被复制;停止复制要慎用,因为复制停止期间对数据的写入不会被复制;如果集群间的网络中断了,复制会在网络修复后自动恢复。
[下图是单向复制]
如何设置复制
所有要复制的列族必须配置,相同的表和列族必须在目标集群中存在,但并不是所有的列族都需要被复制,创建一个列族,把 REPLICATION_SCOPE 设置成 1 或 0,这是用于开启或关闭复制,默认是 0 (关闭状态)。
hbase> create 't1', {NAME => 'colfam1', REPLICATION_SCOPE => '1' }
HBase 必须配置启用复制和知道要复制给那个集群,在 Production Cluster 中输入以下复制语句,第一个参数是 peer_id 是标示集群的唯一 ID,第二个参数是 ZooKeeper 的 Quorum,中间以逗号分隔,后面是 HBase 的 root znode,Peer 不是配置文件中设置的,它是保存在 ZooKeeper 中。
hbase> add_peer '2', "bi1,bi2,bi3:2181:/hbase"
复制类型有以下三种略
- Master-Worker 复制是从 Master 到 Worker 的单向复制;
- Master-Master 是集群间的双向复制:两个集群同时开启复制,在生产环境下,增加 DR 集群作为一个 Peer;然后在 DR 集群中添加生产集群作为 Peer;
hbase> add_peer '2', "dr1,dr2,dr3:2181:/hbase" hbase> add_peer '1', "prod1,prod2,prod3:2181:/hbase"
- 循环复制用于有两个集群以上的集群间复制;
验证复制
检查所有 peer 都设置正确,hbase> list_peers,验证 peer 都指向正确的集群 ID,验证所有要复制的 peer,运行 VerifyReplication 验证每一步都是正确的。
HBase 备份
一些备份方法只是保存数据,而表、列族和设置必须手工方式重建,其他备份基于 PIT (基于时间点的),注意,备份时间点之后的内容不会被保存,一些备份方法可以在集群在线的状态下完成,其他的备份方法要求所有 HBase 进程都要停下来之后才能进行操作。CopyTable 可以在集群内拷贝也可以拷贝到另外的集群,比如在同一个集群内,生成一个表的拷贝,首先需要剑建一个和原始表含有相同列族的目标表,然后运行
hbase org.apache.hadoop.hbase.mapreduce.CopyTable --new.name=targettable originaltable
HBase 有内置程序来完成导入和导出表,导出表到 HDFS 的动作只备份数据,而不包括元数据信息
hbase org.apache.hadoop.hbase.mapreduce.Export table hdfspath
从 HDFS 中导入一张表 ,创建 HBase 目录表,然后运行
hbase org.apache.hadoop.hbase.mapreduce.Import table hdfspath
ImportTSV 实现更高级的数据导入,导入的数据必须是带分隔符的文本文件,列族和每一个列的列描述符必须通过 importtsv.columns 进行配置,如果给出的是错误的列数,作业会报错失败。
hbase org.apache.hadoop.hbase.mapreduce.ImportTsv \ -Dimporttsv.columns=HBASE_ROW_KEY,fam1:col table hdfspath
如果有分隔符 e.g. Tab,可以通过 importtsv.separator 进行配置
hbase org.apache.hadoop.hbase.mapreduce.ImportTsv \ -Dimporttsv.columns=HBASE_ROW_KEY,fam1:col \ '-Dimporttsv.separator=|' table hdfspath
ImportTSV 是按行进行 put 操作,可以输出到一个 HFile 中实现批量加载,使用 importtsv.bul.output 并提供用于写出的 HDFS 路径和表名
hbase org.apache.hadoop.hbase.mapreduce.ImportTsv \ -Dimporttsv.columns=HBASE_ROW_KEY,fam1:col \ -Dimporttsv.bulk.output=/path/for/output table hdfspath
LoadIncrementalHFiles 用于导入 ImportTSV 创建的 HFile, 批量加载实现了高效地数据加载,对于时间序列以及顺序数据的加载帮助尤其大,这个批量我动作不会运行单行的 put,通过一次性加载所有数据避免了热点问题,批量加载执行过程中,表仍然是在线状态,但这只能用于批处理或者加载增量的数据。
hbase org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles /path/for/output table
可以进行全备动作,全备可以通过拷贝 HBase 目录到 HDFS 的方式来完成,只能通过离线拷贝的方式来完成,所有 HBase 的守护进程必须停止,防止拷贝期间出现变化,可以使用 HDFS 的 distcp 命令来完成,distcp 命令使用 MapReduce 执行几个节点上的1拷贝动作,也可以通过修改 hbase.rootdir 备份目录的方式来完成恢复备份。
hadoop distcp /hbase /hbasebackup
快照是一个元数据的集合,允许管理员恢复到表的先前状态,快照创建 HBase 表的元数据备份,快照是对包含表数据的文件目录的引用,不拷贝任何数据,快照存储在 HDFS 上,快照不会删除,当不需要的时候通过手工方式删除,快照可以在集群在线状态下完成。
- 创建快照 e.g. hbase> snapshot 'table', 'snapshotName'
- 通过快照创建一个新表 e.g. hbase> clone_snapshot 'snapshotName','newtablename'
- 通过快照还原表到生成快照的那个时刻,表必须先禁用。e.g. hbase> restore_snapshot 'snapshotName'
- 查看已经存在的快照列表 e.g. hbase> list_snapshots
- 导出快照到其他集群上,导出快照操作会同时绩贝数据和元数据到目标集群,数据和元数据都是直接从 HDFS 到 HDFS 的拷贝,不会同到 RegionServer,
- 构成快照的文件不会默认被删除,必须确认有足够的存储空间来存放在生成快照期间的整个表,合并快照引用的区域会引起快照和克隆表中数据的丢失,复制启动时还原一个表会导致两个集群不同步,复制集群中的表没有还原
hbase org.apache.hadoop.hbase.snapshot.ExportSnapshot \ -snapshot 'snapshotName' -copt-to hdfs://binamenode:8082/hbase
- 快照上的 MapReduce,HBase 可以在快照上执行 MapReduce 作业,对于运行资源密集型 MapReduce 作业非常有用,快照能拷贝到不同集群,避免了主生产集群的负载,将文件导出 HBase 要注意的安全问题,绕过了 ACL、标签可见性、HBase 集群的加密,底层文件系统和服务器的权张控制著对快照的访问权限。
4 种备份方法包含 Snapshot、CopyTable、Export 和 distcp。Snapshot、CopyTable、Export 方法提供了基于时间点 (PIT) 的一致备份,distcp 提供了全部的一致性,为了实现完整的一致性,distcp 要求集群在离线状态下执行拷贝操作。备份和复制功能是不相同的,备份包含完整的数据集,支持数据的全部恢复,包含一个具体时间点的数据集;复制接近实时的集群复制,一个集群上的用户错误将会立刻复制到其他集群上!
hbase> set_quota TYPE=>THROTTLE, TABLE=>'movies', LIMIT=>'100req/sec' hbase> set_quota TYPE=>THROTTLE, USER=>'jim', TABLE=>'hits', LIMIT=>'2M/sec'
参考资料