作者简介:

陈海峰,移动云数据库 Apache HBase 开发人员,对 Apache HBase、RBF、Apache Spark 有浓厚兴趣。

背景

Apache HBase 是 Apache Hadoop 生态体系中的大规模、可扩展、分布式的数据存储服务。同时它还是 NoSQL 数据库。它的设计初衷是为包含了数百万列的数十亿行记录提供随机的、强一致性的实时查询。默认情况下,HBase 的数据会保存在 HDFS 上,HBase 为 HDFS 做了很多优化来保证稳定性与性能。但是维护 HDFS 本身一点也不轻松,要不断进行监控、运维、调优、扩容、灾难恢复等一系列事情,而且在公有云上搭建 HDFS 的费用也是相当高的。为了节省费用、降低维护成本,一些用户使用 S3(或其他对象存储)存储 HBase 的数据。使用 S3 省去了监控运维的麻烦,同时还实现了存储计算分离,让 HBase 的扩容缩容都变得更加容易。

然而,HBase 数据接入对象存储却不是一件容易的事儿。对象存储一方面因为自身特性,功能和性能有限,一旦数据被写入对象存储后,数据对象即不可改变,另一方面使用文件系统语义访问块存储有天然局限性。在使用 Hadoop 原生的 AWS 客户端来访问对象存储时,目录重命名操作会遍历整个目录下文件进行拷贝和删除,性能非常低下。另外重命名操作也会导致原子性问题,即原本的重命名操作分解为拷贝和删除两个操作,在极端情况下易产生用户数据视图不一致情况。类似的还有查询目录所有文件的总大小,原理是通过遍历迭代依次获取某个目录的所有文件信息。如果目录下的子目录和文件数量庞大的话,查询目录所有文件总大小复杂度更大,性能更差。

方案选型

经过大量方案调研和社区问题跟踪,目前云 HBase 数据接入对象存储有三种方案。

第一种是 HBase 使用 Hadoop 原生 AWS 客户端来访问对象存储,即 S3AFileSystem。HBase 内核代码只需要稍加改动即可使用 S3AFileSystem。这种 HBase 直接对接对象存储的方案一个需要解决的痛点问题,即目录的 rename。HBase 在 Hlog 文件管理、MemStore Flush、表创建、region compaction 和 region split 时都会涉及目录的 rename。社区对 StoreFIle 进行了优化,解决了一部分的 rename 性能问题。完全解决目录操作性能问题需要对 HBase 内核源码进行大刀阔斧地变动。

第二个方案是引入 Alluxio 作为缓存加速,不仅大大提升读写性能,而且引入文件元数据管理,彻底解决了目录操作性能低下问题。看似圆满的结局,背后却有很多限制条件。当 Alluxio 配置仅仅使用内存时,对目录操作耗时才是 ms 级别。如果配置 Alluxio 的 UFS,Alluxio 中的元数据操作有两个步骤:第一步是修改 Alluxio master 的状态,第二步是向 UFS 发送请求。可以看到,元数据操作仍然不是原子的,当操作正在执行或发生任何故障时,其状态是不可预测的。Alluxio 依赖 UFS 来实现元数据操作,比如重命名文件操作会变成复制和删除操作。HBase 中数据必定是需要落盘的,Alluxio 解决不了目录操作性能问题。

第三种方案是在 HBase 与对象存储之间引入 JuiceFS 共享文件系统。使用 JuiceFS 存储数据,数据本身会被持久化在对象存储(例如,移动云 EOS),相对应的元数据可以按需持久化在 Redis、MySQL 等多种数据库中。此方案中对目录操作完成是在 Metadata Engine 中完成,与对象存储无交互,操作耗时在 ms 级别,可以解决 HBase 数据接入对象存储的痛点问题。但是由于 JuiceFS 内核采用 Go 语言编写,对后期性能调优和日常维护带来一定挑战。

权衡上述三个方案利弊,最终采用 JuiceFS 作为云 HBase 支持对象存储的解决方案。下面着重讨论 JuiceFS 在云 HBase 支持对象存储中的实践以及性能调优。

方案介绍

首先介绍下 JuiceFS 的架构。JuiceFS 由两个主要部分组成:JuiceFS 元数据(Metadata)服务和对象存储。JuiceFS Java SDK 完全兼容 HDFS API,同时也提供基于 FUSE 的客户端挂载,完全兼容 POSIX。作为文件系统,JuiceFS 会分别处理数据及其对应的元数据,数据会被存储在对象存储中,元数据会被存储在元数据引擎中。在数据存储方面,JuiceFS 支持几乎所有的公有云对象存储,同时也支持 OpenStack Swift、Ceph、MinIO 等支持私有化部署的开源对象存储。在元数据存储方面,JuiceFS 采用多引擎设计,目前已支持 Redis、TiKV、MySQL/MariaDB、PostgreSQL、SQLite 等作为元数据服务引擎。

任何存入 JuiceFS 的文件都会被拆分成固定大小的 "Chunk",默认的容量上限是 64 MiB。每个 Chunk 由一个或多个 "Slice" 组成,Slice 的长度不固定,取决于文件写入的方式。每个 Slice 又会被进一步拆分成固定大小的 "Block",默认为 4 MiB。最后,这些 Block 会被存储到对象存储。与此同时,JuiceFS 会将每个文件以及它的 Chunks、Slices、Blocks 等元数据信息存储在元数据引擎中。

使用 JuiceFS,文件最终会被拆分成 Chunks、Slices 和 Blocks 存储在对象存储。因此,对象存储平台中找不到存入 JuiceFS 的源文件,存储桶中只有一个 chunks 目录和一堆数字编号的目录和文件。

HBase 组件使用 JuiceFS 需要以下配置。首先将编译好的客户端 SDK 置于 HBase classpath 内。其次将 JuiceFS 相关配置写入配置文件 core-site.xml,如下表所示。最后使用 juicefs 客户端格式化文件系统。

配置项 默认值 描述
fs.jfs.impl io.juicefs.JuiceFileSystem 指定要使用的存储实现,默认使用 jfs://
fs.AbstractFileSystem.jfs.impl io.juicefs.JuiceFS
juicefs.meta 指定预先创建好的 JuiceFS 文件系统的元数据引擎地址。

在元数据存储方面,使用 MySQL 作为元数据存储。格式化文件系统命令如下。可见,格式化文件系统需要提供以下信息:

  • --storage:设置存储类型,比如移动云 EOS;
  • --bucket:设置对象存储的 Endpoint 地址;
  • --access-key:设置对象存储 API 访问密钥 Access Key ID;
  • --secret-key:设置对象存储 API 访问密钥 Access Key Secret。
juicefs format --storage eos \
--bucket https://myjfs.eos-wuxi-1.cmecloud.cn \
--access-key ABCDEFGHIJKLMNopqXYZ \
--secret-key ZYXwvutsrqpoNMLkJiHgfeDCBA \
mysql://username:password@(ip:port)/database NAME

方案验证与优化

介绍完 Juicefs 使用方法后,开始进行测试工作。测试环境中选用了一台 48 核、187G 内存的服务器。在 HBase 集群中,分别有一个 HMaster、一个 RegionServer 和三个 zookeeper。在 Meta data engine 选用主从复制的三节点 MySQL。对象存储则使用移动云对象存储 EOS,网络策略走公网。Juicefs 配置 chunk 大小为 64M,物理存储块大小为 4M,无 cache,MEM 使用 300M。我们搭建了两套 HBase 集群,一套是 HBase 直接落盘到移动云对象存储上,另一套是在 HBase 和移动云对象存储之间引入 Juicefs。顺序写和随机读是 HBase 集群两个关键性能指标,使用 PE 测试工具测试这两个性能指标。测试读写性能如下表所示。

集群环境

集群环境 HBase-juicefs-EOS (row/s) 集群环境 HBase-EOS (row/s)
顺序写 79465 33343
随机读 6698 6476

根据测试结果,采用 Juicefs 方案,集群顺序写性能提升非常明显,随机读性能却没有提升。究其原因,写请求写入 Client 内存缓冲区即可返回,因此通常来说 JuiceFS 的 Write 时延非常低(几十微秒级别)。JuiceFS 在处理读请求时,一般会按照 4M Block 对齐的方式去对象存储读取,实现一定的预读功能,同时,读取到的数据会写入本地 Cache 目录,以备后用。在顺序读时,这些提前获取的数据都会被后续的请求访问到,Cache 命中率非常高,因此也能充分发挥出对象存储的读取性能。但是在随机读取时,JuiceFS 的预先缓存效率不高,反而会因为读放大和本地 Cache 的频繁写入与驱逐使得系统资源的实际利用率降低。

为了提升随机读性能,两个方向可以考虑。一个是尽可能提升缓存的整体容量,以期达到能几乎完全缓存所需数据的效果,在海量数据的使用场景下,这个优化方向不太可行。另一个方向是深耕 JuiceFS 内核,优化读数据逻辑。

目前我们所做的优化包括:1)关闭预读机制和缓存功能,简化读数据逻辑;2)尽可能避免缓存整个块数据,更多地使用 Range HTTP 请求数据;3)设置较小的 block 大小;4)尽可能提高对象存储的读取性能。经研发环境测试,经优化后随机读性能提升大约 70%。

结合前期测试工作,云 HBase 在使用对象存储作为底层数据存储系统后,在获得与数据存储在 HDFS 差不多读写性能基础上,用户花费却只有数据存储在 HDFS 的一半以下,由此可以看出云 HBase 支持对象存储是鱼与熊掌兼得的一次研发实践。

如有帮助的话欢迎关注我们项目 Juicedata/JuiceFS 哟! (0ᴗ0✿)

移动云使用 JuiceFS 支持 Apache HBase 增效降本的探索的更多相关文章

  1. 【HBase学习】Apache HBase项目简介

    原创声明:转载请注明作者和原始链接 http://www.cnblogs.com/zhangningbo/p/4068957.html       英文原版:http://hbase.apache.o ...

  2. GoldenGate实时投递数据到大数据平台(7)– Apache Hbase

    Apache Hbase安装及运行 安装hbase1.4,确保在这之前hadoop是正常运行的.设置相应的环境变量, export HADOOP_HOME=/u01/hadoop export HBA ...

  3. How-to: Enable User Authentication and Authorization in Apache HBase

    With the default Apache HBase configuration, everyone is allowed to read from and write to all table ...

  4. Apache HBase RPC身份验证中间人安全措施绕过漏洞(CVE-2013-2193)

    漏洞版本: Apache Group HBase 0.94.x Apache Group HBase 0.92.x 漏洞描述: BUGTRAQ ID: 61981 CVE(CAN) ID: CVE-2 ...

  5. The Apache HBase™ Reference Guide

    以下内容由http://hbase.apache.org/book.html#getting_started节选并改编而来. 运行环境:hadoop-1.0.4,hbase-0.94.22,jdk1. ...

  6. Apache HBase Performance Tuning 官文总结

    Apache HBase Performance Tuning RAM, RAM, RAM. 不要让HBase饿死. 请使用64位的平台 必须将swapping设定为0 使用本地硬件来完成hdfs的c ...

  7. Apache HBase 集群安装文档

    简介: Apache HBase 是一个分布式的.面向列的开源 NoSQL 数据库.具有高性能.高可靠性.可伸缩.面向列.分布式存储的特性. HBase 的数据文件最终落地在 HDFS 之上,所以在 ...

  8. hadoop版本与支持的hbase版本对照…

    hadoop版本与支持的hbase版本对照表 分类: hbase2013-05-20 17:19 701人阅读 评论(2) 收藏 举报 HbaseHadoop As of Hive 0.9.0 the ...

  9. Use Apache HBase™ when you need random, realtime read/write access to your Big Data.

    Apache HBase™ is the Hadoop database, a distributed, scalable, big data store. Use Apache HBase™ whe ...

随机推荐

  1. js 图片上传给后台的3种格式

    1. file格式 (创建formData来完成file上传) 我们的接口需求: 代码: <input type="file" id="imgfile" ...

  2. 免费的天气API

    高德地图天气 天气查询-API文档 请求示例: { "status": "1", "count": "1", " ...

  3. python---概述

    python的主要应用领域 云计算:云计算的最火的语言,典型应用OpenStack. web开发:众多优秀的web框架,典型地有Django,众多大型网站也是python开发,比如YouTube.豆瓣 ...

  4. Mybatis-plugins分页助手实现查询数据分页

    其他具体代码接上文->mybatis自定义处理器 1.导入坐标 <dependency> <groupId>com.github.pagehelper</group ...

  5. LC-34

    package getSecondBiggestNum.nums; public class LC34 { public int[] searchRange(int[] nums, int targe ...

  6. linux磁盘之lsblk命令

    lsblk命令可以显示很多跟磁盘相关分区.所属关系以及lvm的重要信息,所以这个命令最好掌握.lsblk命令默认情况下将以树状列出所有块设备,包括查看磁盘挂载信息.lsblk命令包含在util-lin ...

  7. GRPC-go版本

    GRPC-go版本 1.安装GO,protobuf 只适合有梯子的 GO的安装没必要说了 protobuf :https://github.com/protocolbuffers/protobuf/r ...

  8. Java学习day30

    线程分为用户线程和守护线程,虚拟机必须确保用户线程执行完毕,虚拟机不用等待守护线程执完毕 并发:同一个对象被多个线程同时操作,例如上万了同时抢100张票,手机银行和柜台同时取同一张卡里的钱 处理多线程 ...

  9. vue3响应式模式设计原理

    vue3响应式模式设计原理 为什么要关系vue3的设计原理?了解vue3构建原理,将有助于开发者更快速上手Vue3:同时可以提高Vue调试技能,可以快速定位错误 1.vue3对比vue2 vue2的原 ...

  10. Node爬取网站数据

    npm安装cheerio和axios npm isntall cheerio npm install axios 利用cheerio抓取对应网站中的标签根据链接使用axios获取对应页面数据 cons ...