Skip to main content

使用 JuiceFS Hadoop Java SDK

我们推荐以 Hadoop SDK 的方式在 Hadoop 下使用 JuiceFS。理论上你也可以通过 RawLocalFileSystem 让 HDFS 通过 FUSE mount 接入 JuiceFS,但受限于 HDFS 的实现,这样的实践存在性能问题,不推荐使用。

JuiceFS Hadoop Java SDK 不会自动去创建文件系统对应的 bucket,需要提前创建好。

与 HDFS 的区别

JuiceFS 与 HDFS 在某些方面有所不同,使用前请先了解。

用户组管理

Hadoop 中用户组信息是可配置的(hadoop.security.group.mapping),默认使用系统用户组信息(ShellBasedUnixGroupsMapping),HDFS 使用的是 NameNode 所在节点的用户组信息,通过管理命令(hdfs dfsadmin -refreshUserToGroupsMappings)来刷新缓存。

JuiceFS 默认使用的是每个客户端在创建时所在节点的用户组信息,无法刷新。当要修改用户组信息时,需要同步到所有部署 JuiceFS 的节点,并重启使用 JuiceFS 的服务,因此我们推荐将该信息用下方的手段实现动态配置。

JuiceFS Hadoop SDK 可以通过指定配置文件来设置用户组信息,可以将 group 配置文件放置在 JuiceFS 上。这样所有节点就都可以读取同一份 group 配置文件,当需要向修改用户组配置的时候,也只需要修改此配置文件,所有 JuiceFS 客户端会在 2 分钟内自动更新信息,无需重启服务。具体操作如下:

  1. 在所有节点修改 core-site.xml,添加如下配置:

    <property>
    <name>juicefs.grouping</name>
    <value>jfs://{VOL_NAME}/etc/group</value>
    </property>
  2. 在 JuiceFS 上创建 juicefs.grouping 所指向的配置文件

  3. 修改此文件,添加用户组信息,格式如下:

    groupname:username1,username2

内存使用

JuiceFS Hadoop SDK 需要额外使用 300~500 MiB 内存用来预读数据,提高性能。所以比如在使用 Spark 的时候,建议每个 executor 配置多个 CPU。因为每个 executor 使用一个 JuiceFS 客户端,一个 executor 内多个 task 可以共享这部分内存。

hflush 实现

当客户端 commit 时,会调用 HDFS 的 hflush 方法,JuiceFS 与 HDFS 在 hflush 的实现上有别:

HDFS 是将数据提交到多台 datanode 的内存里就算成功,因此时延比较低。提交完成以后,数据就对其他客户端可见。

JuiceFS 的 hflush 有多种模式,通过参数 juicefs.hflush 设置:

  • writeback(默认)

    此模式下调用 hflush 接口只会将数据提交到本地磁盘(后台有线程会异步将数据上传到对象存储),但在客户端异常退出的情况下,可能由于部分数据没来得及上次对象存储而导致数据丢失。

    开启 writeback 以后,可以通过 juicefs.hflush-delay 来控制 hflush 间隔,定时将数据写入本地缓存盘。该配置默认为 0,表示立即写入本地缓存盘。

  • sync

    此模式下调用 hflush 接口会同步地将数据提交到对象存储。但由于是数据需要提交到对象存储,不可避免的有较高的时延,但有更强的一致性保证。

缓存调优

JuiceFS 具有强大的缓存功能,在缓存一章里详细介绍,此处仅针对性补充 Hadoop 场景下的一些实践。与 JuiceFS Linux 客户端类似,Hadoop SDK 能调整各种缓存参数,详见参数配置

单机缓存

为了使单机缓存能更好的被利用,JuiceFS 给每个 128MB 的逻辑文件块(同 HDFS 的 block)分配一个 BlockLocation 信息,Spark、MR、Presto 等计算引擎会利用此信息将任务调度到同一台机器上,读缓存就会生效。BlockLocation 是通过预先知道的机器列表算出来的,使用一致性哈希算法,减少机器上下线导致的缓存失效。JuiceFS 可以通过 YARN、Spark、Presto 等提供的接口获得计算节点列表,通过 juicefs.discover-nodes-url 参数设置。

分布式缓存

请详读「客户端缓存数据共享」来了解分布式缓存功能。

在 Hadoop SDK 中可以通过设置 juicefs.cache-group 来启用,设置了相同名字的机器组成一个共享缓存组。这种共享缓存模式比较适合 JuiceFS 客户端比较固定的情况,比如 Presto、Spark Thrift Server 等。而对于动态伸缩的计算集群,比如 Spark on Kubernetes,用专门的缓存集群更为合适。将计算集群的 juicefs.cache-group 设置为和缓存集群一样的名字,同时将计算集群的 juicefs.no-sharing 设置为 true。这样一来,计算集群完全不参与构建缓存组,只从缓存集群读取数据并缓存在它的本地磁盘。

用类似下方的挂载命令来创建缓存集群:

sudo juicefs mount $VOL_NAME /jfs --cache-dir=xxx --cache-size=xxx --cache-mode=0777 --cache-group=xxx

准备工作

JuiceFS Hadoop SDK 需要通过外网访问 JuiceFS 元数据服务,需要部署 NAT 等给 Hadoop 集群提供外网访问能力。

说明

JuiceFS 的元数据服务部署在与客户相同的公有云和相同区域中(可能是不同可用区),JuiceFS Hadoop SDK 是通过外网出口访问区域内的服务。如果 JuiceFS 元数据服务私有化部署在内网,则无此要求。

自动安装 JuiceFS Hadoop SDK

Python 脚本安装

安装脚本 setup-hadoop.py,在 Cloudera Manager 节点、Ambari 节点或者公有云 EMR Master 节点上按下面步骤运行安装。

此脚本使用 Python 编写,支持 Python 2 和 Python 3。可以自动下载并安装 juicefs-hadoop.jar,并且自动安装部署到整个集群,同时也可以自动部署 JuiceFS 相关配置到 core-site.xml(仅支持 HDP 和 CDH)。

使用说明

python setup-hadoop.py COMMAND

COMMAND could be:
-h 显示帮助信息
install 在本机安装 JuiceFS JAR
install_all 在所有机器上安装 JuiceFS JAR, 需要把脚本运行节点和其他节点的 root 用户 SSH 打通
config 自动填写配置,目前支持 Ambari 和 ClouderaManager
deploy_config 自动配置下发到部署了客户端的机器,目前支持 Ambari 和 ClouderaManager
test 验证 JuiceFS JAR 是否真确安装
test_all 验证所有机器 JuiceFS JAR 是否正确安装

使用步骤

  1. 安装 JAR 文件

    python setup-hadoop.py install

    此操作会将 juicefs-hadoop.jar 下载到 /usr/local/lib 下, 并在 Hadoop 各个发行版下面对应组件的 lib/ 目录下建立软连接,具体放置目录会在日志中打出。

  2. 配置

    python setup-hadoop.py config

    此操作会自动将必要配置项写入 HDFS 的 core-site.xml,并在日志中打印出来。

    对于 CDH 和 HDP 环境,运行此命令,并按照提示输入管理员的账号密码。如果在这台机器上成功执行过 juicefs authjuicefs mount,会自动读取 /root/.juicefs/ 中的认证信息, 然后通过 RESTful API 自动将配置项写入 core-site.xml

    此操作还会按照 juicefs.cache-dir 配置的目录在机器上创建缓存目录。

  3. 将 JAR 文件分发到整个集群

    • CDH 或者 HDP 环境,执行:

      python setup-hadoop.py install_all
    • 其他公有云 EMR 环境,执行:

      export NODE_LIST=node1,node2
      python setup-hadoop.py install_all
    • Apache Hadoop 社区版自定义安装,执行:

      # 组件 classpath,用逗号隔开
      export EXTRA_PATH=$HADOOP_HOME/share/hadoop/common/lib,$SPARK_HOME/jars,$PRESTO_HOME/plugin/hive-hadoop2
      export NODE_LIST=node1,node2
      python setup-hadoop.py install_all

    此操作将会把 juicefs-hadoop.jar/etc/juicefs/.juicefs 通过 scp 的方式安装部署到指定的节点上去。

  4. 全新安装或者升级需要重启的相关服务

    • 部署配置

      需要到 CDH 或者 HDP,或者其他 EMR 管理界面操作。

    • 无需重启组件

      • HDFS
      • HUE
      • ZooKeeper
      • YARN
    • 需要重启组件

      以下各组件服务,只有当用到 JuiceFS 时才需要重启。

      • Hive

        如果启用 HA,可以通过滚动重启,不影响使用。

        • Hive Metastore Server
        • HiveServer2
      • Spark on YARN

        如果只是使用 spark-sql -f 提交任务,则无需重启。

        • ThriftServer
      • Spark Standalone

        • Master
        • Worker
      • Presto

        • Coordinator
        • Worker
      • Impala

        • Catalog Server
        • Daemon
      • HBase

        • Master
        • RegionServer
      • Flume

手动安装 JuiceFS Hadoop SDK

  1. 下载最新的 juicefs-hadoop.jar
  2. 将下载的 JAR 文件路径加入到应用的 classpath 中,可通过 hadoop classpath 命令查看 classpath 路径。
提示

一些组件有默认放置 JAR 文件的目录,放在那些目录中会被自动加入到 classpath 中。

JuiceFS Hadoop SDK 参数配置

将以下配置参数加入到 Hadoop 配置文件 core-site.xml 中。

核心配置

配置项默认值描述
fs.jfs.implcom.juicefs.JuiceFileSystem指定 jfs:// 这个存储类型所使用的实现。
fs.AbstractFileSystem.jfs.implcom.juicefs.JuiceFSMR 等应用需要指定 AbstractFileSystem 的实现
juicefs.token访问 JuiceFS 的凭证,在控制台的设置页或者访问控制页可以看到。
juicefs.accesskey对象存储的访问ID(Access Key ID)。如果计算节点已经有访问对象存储的权限,则无需提供。
juicefs.secretkey对象存储的私钥 (Secret Access Key)。如果计算节点已经有访问对象存储的权限,则无需提供。

缓存配置

配置项默认值描述
juicefs.cache-dir本地缓存目录,可以指定多个文件夹,用冒号 : 分隔,也可以使用通配符(比如 * )。通常应用没有权限创建这些目录,需要手动创建并给予 0777 权限,便于多个应用共享缓存数据
juicefs.cache-size0磁盘缓存容量,单位 MB。如果配置多个目录,这是所有缓存目录的空间总和。
juicefs.cache-replica1磁盘缓存副本数。
juicefs.cache-group配置此项则使用 P2P cache,各个相同 group 之间的 JuiceFS 客户端可以共享缓存,推荐在主要使用 Spark 的环境使用此配置,因为 Spark 在单个任务处理多个小文件时,计算没有数据本地化。
juicefs.cache-full-blocktrue是否缓存连续读数据,在磁盘空间有限或者磁盘性能低下的时候,设置为 false。
juicefs.memory-size300预读最大使用内存量,单位 MB。
juicefs.auto-create-cache-dirtrue是否自动创建缓存目录。为 false 时,它会忽略不存在的缓存目录。
juicefs.free-space0.2最低剩余磁盘空间比例,当剩余磁盘空间低于这个比例时,它会清空缓存数据以释放空间,默认 20%。
juicefs.metacachetrue是否启用元数据缓存。
juicefs.discover-nodes-url指定发现集群计算节点列表的方式,每 10 分钟刷新一次。

YARN:yarn
Spark Standalone:http://spark-master:web-ui-port/json/
Spark ThriftServer:http://thrift-server:4040/api/v1/applications/
Presto:http://coordinator:discovery-uri-port/v1/service/presto/

其他配置

配置项默认值描述
juicefs.access-log访问日志的路径。需要所有应用都有写权限,可以配置为 /tmp/juicefs.access.log 。该文件会自动轮转,保留最近 7 个文件。
juicefs.debugfalse是否启用 Debug 级别的日志。
juicefs.max-uploads50单进程写入对象存储最大并发数
juicefs.superuserhdfs超级用户
juicefs.bucket指定存储桶名称
juicefs.upload-limit0单进程写入对象存储速度限制,单位 byte/s
juicefs.object-timeout5访问对象存储单次读请求的最长时间,单位 秒
juicefs.externalfalse是否使用公网域名访问对象存储
juicefs.rsaPrivKeyPath用于数据存储加密的 RSA 密钥路径
juicefs.rsaPassphrase用于数据存储加密的 RSA 密钥密码
juicefs.file.checksumfalse用于 Hadoop DistCp 时是否验证 checksum
juicefs.grouping指定 group 文件放置位置,用来配置用户组和用户映射信息,推荐配置在 jfs://myjfs/etc/group。文件内容格式:groupname:username1,username2

当使用多个 JuiceFS 文件系统时,上述所有配置项均可对单个文件系统指定,需要将文件系统名字 VOL_NAME 放在配置项的中间,比如:

<property>
<name>juicefs.{VOL_NAME}.token</name>
<value>false</value>
</property>

常见发行版手动配置方法

如果你不希望通过自动化脚本安装 Hadoop SDK,可以参考本节内容来进行手动安装。

CDH

使用 Parcel 安装

  1. 在 Cloudera Manager 节点下载 ParcelCSD,将 CSD 文件放入的 /opt/cloudera/csd 目录,将 Parcel 文件解压并将内容放入 /opt/cloudera/parcel-repo 目录。

  2. 重启 Cloudera Manager

    service cloudera-scm-server restart
  3. 激活 Parcel

    打开 CDH 管理界面 → Hosts → Check for New Parcels → JUICEFS → Distribute → Active

  4. 添加服务

    打开 CDH 管理界面 → 集群名 → Add Service → JuiceFS → 选择安装机器 → 配置缓存目录(cache_dirs

  5. 部署 JAR 文件

  6. 升级

    如果需要升级,则下载新的 Parcel 文件,并进行第 3 步。

通过 Cloudera Manager 修改配置

  • Hadoop

    CDH 5.x

    通过 HDFS 服务界面修改 core-site.xml

    常用配置

    fs.jfs.impl=com.juicefs.JuiceFileSystem
    fs.AbstractFileSystem.jfs.impl=com.juicefs.JuiceFS
    juicefs.cache-size=10240
    juicefs.cache-dir=xxxxxx
    juicefs.cache-group=yarn
    juicefs.discover-nodes-url=yarn
    juicefs.accesskey=xxxxxx
    juicefs.secretkey=xxxxxx
    juicefs.token=xxxxxx
    juicefs.access-log=/tmp/juicefs.access.log

    CDH 6.x

    除了上述 5.x 内容外。您还需通过 YARN 服务界面修改 mapreduce.application.classpath,增加以下配置

    $HADOOP_COMMON_HOME/lib/juicefs-hadoop.jar
  • HBase

    通过 HBase 服务界面修改 hbase-site.xml

    配置:

    <property>
    <name>hbase.rootdir</name>
    <value>jfs://{VOL_NAME}/hbase</value>
    </property>
    <property>
    <name>hbase.wal.dir</name>
    <value>hdfs://your-hdfs-uri/hbase-wal</value>
    </property>

    通过 ZooKeeper 客户端删除 zookeeper.znode.parent 配置的 znode(默认 /hbase),此操作将会删除原有 HBase 集群里的所有数据。 :::

  • Hive

    通过 Hive 服务界面修改 hive.metastore.warehouse.dir,可修改 Hive 建表默认位置(非必须)

    jfs://myjfs/your-warehouse-dir
  • Impala

    通过 Impala 服务界面修改 Impala 命令行参数高级配置

    此参数可以使用 20 / 本地挂载磁盘数 来设置,修改此参数主要是为了增加 JuiceFS 的读取 IO 线程数。

    -num_io_threads_per_rotational_disk=4
  • Solr

    通过 Solr 服务界面修改 Solr 服务环境高级配置代码段

    hdfs_data_dir=jfs://myjfs/solr

最后重启集群,让配置修改生效。

HDP

将 JuiceFS 集成到 Ambari

  1. 下载 HDP 安装文件,解压后将内容放到 /var/lib/ambari-server/resources/stacks/HDP/{YOUR-HDP-VERSION}/services

  2. 重启 Ambari

    systemctl restart ambari-server
  3. 添加 JuiceFS 服务

    打开 Ambari 管理界面 → Services → Add Service → JuiceFS → 选择安装机器 → 配置 → deploy

    在配置步骤,主要是配置缓存目录(cache_dirs)和下载版本(download_url)。

    如果 Ambari 没有外网,可以直接将下载好的 JAR 包收到放到 share_download_dir 下,默认为 HDFS 的 /tmp 目录。

  4. 升级 JuiceFS

    修改 download_url 的版本号,保存并 Refresh configs。

通过 Ambari 修改配置

  • Hadoop

    通过 HDFS 服务界面修改 core-site.xml,具体配置见 详细配置表

  • MapReduce2

    通过 MapReduce2 服务界面修改配置 mapreduce.application.classpath,在末尾增加 :/usr/hdp/${hdp.version}/hadoop/lib/juicefs-hadoop.jar(变量无需替换)。

  • Hive

    通过 Hive 服务界面修改 hive.metastore.warehouse.dir,可修改 hive 建表默认位置(非必须):

    jfs://myjfs/your-warehouse-dir

    如果配置了 Ranger 服务,则需要配置 HIVE 服务 ranger.plugin.hive.urlauth.filesystem.schemes,追加 jfs 支持

    ranger.plugin.hive.urlauth.filesystem.schemes=hdfs:,file:,wasb:,adl:,jfs:
  • Druid

    通过 Druid 界面修改目录地址(如无权限,需手动创建目录):

    "druid.storage.storageDirectory": "jfs://myjfs/apps/druid/warehouse"
    "druid.indexer.logs.directory": "jfs://myjfs/user/druid/logs"
  • HBase

    通过 HBase 服务界面修改一下参数

    hbase.rootdir=jfs://myjfs/hbase
    hbase.wal.dir=hdfs://your-hdfs-uri/hbase-wal

    通过 ZooKeeper 客户端删除 zookeeper.znode.parent 配置的 znode(默认 /hbase),此操作将会删除原有 HBase 集群里的所有数据。

  • Sqoop

    使用 Sqoop 将数据导入 Hive 时,Sqoop 会首先把数据导入 target-dir,然后在通过 hive load 命令将数据加载到 Hive 表,所以使用 Sqoop 时,需要修改 target-dir

    • 1.4.6

      使用此版本的 Sqoop 时还需要修改 fs, 此参数修改默认文件系统,所以需要将 HDFS 上面的 mapreduce.tar.gz 复制到 JuiceFS 上的相同路径,默认目录在 HDFS /hdp/apps/${hdp.version}/mapreduce/mapreduce.tar.gz

      sqoop import \
      -fs jfs://myjfs/ \
      --target-dir jfs://myjfs/tmp/your-dir
    • 1.4.7

      sqoop import \
      --target-dir jfs://myjfs/tmp/your-dir

最后,重启相应服务让配置修改生效。

阿里云 EMR

新建 EMR 集群集成 JuiceFS

  1. 在 EMR 软件配置界面配置高级设置

    在软件配置 → 高级设置 → 软件自定义配置填入以下配置,缓存配置按需修改。

    [
    {
    "ServiceName": "HDFS",
    "FileName": "core-site",
    "ConfigKey": "fs.jfs.impl",
    "ConfigValue": "com.juicefs.JuiceFileSystem"
    },
    {
    "ServiceName": "HDFS",
    "FileName": "core-site",
    "ConfigKey": "fs.AbstractFileSystem.jfs.impl",
    "ConfigValue": "com.juicefs.JuiceFS"
    },
    {
    "ServiceName": "HDFS",
    "FileName": "core-site",
    "ConfigKey": "juicefs.cache-group",
    "ConfigValue": "yarn"
    },
    {
    "ServiceName": "HDFS",
    "FileName": "core-site",
    "ConfigKey": "juicefs.cache-dir",
    "ConfigValue": "/mnt/disk*/jfs"
    },
    {
    "ServiceName": "HDFS",
    "FileName": "core-site",
    "ConfigKey": "juicefs.cache-size",
    "ConfigValue": "1000000"
    },
    {
    "ServiceName": "HDFS",
    "FileName": "core-site",
    "ConfigKey": "juicefs.discover-nodes-url",
    "ConfigValue": "yarn"
    },
    {
    "ServiceName": "HDFS",
    "FileName": "core-site",
    "ConfigKey": "juicefs.token",
    "ConfigValue": ""
    },
    {
    "ServiceName": "HDFS",
    "FileName": "core-site",
    "ConfigKey": "juicefs.conf-dir",
    "ConfigValue": "/etc/juicefs"
    },
    {
    "ServiceName": "HDFS",
    "FileName": "core-site",
    "ConfigKey": "juicefs.access-log",
    "ConfigValue": "/tmp/juicefs.access.log"
    }
    ]
  2. 在基础信息界面的高级设置里面添加引导操作

    下载 emr-boot.sh 脚本和 juicefs-hadoop.jar,并上传到您的对象存储上。

    「脚本位置」填写 emr-boot.sh 在 OSS 上面的地址,「参数」填写 juicefs-hadoop-{version}.jar 在 OSS 上面的地址。

    • 可以访问公网

      --jar oss://{bucket}/resources/juicefs-hadoop-{version}.jar --endpoint {endpoint}
      或者
      --jar https://{bucket}.{endpoint}/resources/juicefs-hadoop-{version}.jar
    • 无外网连接(私有部署)

      由于 JuiceFS 需要联网下载部分必须配置文件来发行服务器的地址,因此在私有环境下(无外网连接),需要将此文件事先准备好。此配置文件可以在挂载 JuiceFS 的机器上面 /root/.juicefs 下面找到,文件名:{jfs-name}.conf

      将此配置文件同样上传到 OSS 上,然后在引导操作的参数里面填写下面配置:

      --jar oss://{bucket}/{jar-path}
      --conf-file oss://{bucket}/{conf-file-path}

已有 EMR 集群集成 JuiceFS

  • Hadoop

    通过 HDFS 服务界面修改 core-site.xml

    常用配置:

    fs.jfs.impl=com.juicefs.JuiceFileSystem
    fs.AbstractFileSystem.jfs.impl=com.juicefs.JuiceFS
    juicefs.cache-size=10240
    juicefs.cache-dir=xxxxxx
    juicefs.cache-group=yarn
    juicefs.discover-nodes-url=yarn
    juicefs.accesskey=xxxxxx
    juicefs.secretkey=xxxxxx
    juicefs.token=xxxxxx
    juicefs.access-log=/tmp/juicefs.access.log
  • Hive

    通过 Hive 服务界面修改 hive.metastore.warehouse.dir,可修改 Hive 建表默认位置(非必须):

    jfs://{jfs-name}/{warehouse-dir}

最后,重启相应服务让配置修改生效。

腾讯云 EMR

新建 EMR 集群集成 JuiceFS

  1. 在 EMR 可用区与软件配置界面配置高级设置

    在软件配置填入以下配置,缓存配置按需修改。

    [
    {
    "serviceName": "HDFS",
    "classification": "core-site.xml",
    "serviceVersion": "2.8.5",
    "properties": {
    "fs.jfs.impl": "com.juicefs.JuiceFileSystem",
    "fs.AbstractFileSystem.jfs.impl": "com.juicefs.JuiceFS",
    "juicefs.token": "",
    "juicefs.accesskey": "",
    "juicefs.secretkey": "",
    "juicefs.cache-group": "yarn",
    "juicefs.cache-dir": "/data*/jfs",
    "juicefs.cache-size": "10000000",
    "juicefs.discover-nodes-url": "yarn",
    "juicefs.superuser": "hadoop",
    "juicefs.conf-dir": "/etc/juicefs",
    "juicefs.access-log": "/tmp/juicefs.access.log"
    }
    }
    ]
    注意

    serviceVersion 需要和 Hadoop 版本匹配

  2. 在基础信息界面的高级设置里面添加引导操作

    下载 emr-boot.sh 脚本和 juicefs-hadoop.jar,并上传到您的对象存储上。

    对象存储需授权,引导操作的运行时机为「集群启动前」。

    「脚本位置」填写 emr-boot.sh 在 COS 上面的地址,「参数」填写 juicefs-hadoop-{version}.jar 在 COS 上面的地址。

    • 可以访问公网

      --jar cosn://{bucket}/{jar-path}
    • 无外网连接(私有部署)

      由于 JuiceFS 需要联网下载部分必须配置文件来发行服务器的地址,因此在私有环境下(无外网连接),需要将此文件事先准备好。此配置文件可以在挂载 JuiceFS 的机器上面 /root/.juicefs 下面找到,文件名:{jfs-name}.conf

      将此配置文件同样上传到 COS 上,然后在引导操作的参数里面填写下面配置:

      --jar cosn://{bucket}/{jar-path}
      --conf-file cosn://{bucket}/{conf-file-path}
  3. 启动集群

已有 EMR 集群集成 JuiceFS

需要授予集群 COS 访问权限

  • Hadoop

    通过 HDFS 服务界面修改 core-site.xml

    常用配置:

    fs.jfs.impl=com.juicefs.JuiceFileSystem
    fs.AbstractFileSystem.jfs.impl=com.juicefs.JuiceFS
    juicefs.cache-size=10240
    juicefs.cache-dir=xxxxxx
    juicefs.cache-group=yarn
    juicefs.discover-nodes-url=yarn
    juicefs.accesskey=xxxxxx
    juicefs.secretkey=xxxxxx
    juicefs.token=xxxxxx
    juicefs.access-log=/tmp/juicefs.access.log
    注意

    由于腾讯云 EMR 默认使用 hadoop 用户启动 HDFS,HDFS 的 superuserhadoop。为了保持一致所以还需要指定 juicefs.superuser=hadoop

  • Hive

    通过 Hive 服务界面修改 hive.metastore.warehouse.dir,可修改 Hive 建表默认位置(非必须):

    jfs://{jfs-name}/{warehouse-dir}

最后,重启相应服务让配置修改生效。

金山云 KMR

HDP 环境的配置方法

AWS EMR

新建 EMR 集群集成 JuiceFS

  1. 在 Software and Steps 界面填写配置

    • 基础配置

      [
      {
      "classification": "core-site",
      "properties": {
      "fs.jfs.impl": "com.juicefs.JuiceFileSystem",
      "fs.AbstractFileSystem.jfs.impl": "com.juicefs.JuiceFS",
      "juicefs.cache-size": "10240",
      "juicefs.access-log": "/tmp/juicefs.access.log",
      "juicefs.discover-nodes-url": "yarn",
      "juicefs.conf-dir": "/etc/juicefs",
      "juicefs.cache-full-block": "false",
      "juicefs.token": "",
      "juicefs.cache-group": "yarn",
      "juicefs.cache-dir": "/mnt*/jfs"
      }
      }
      ]
    • 使用 HBase on JuiceFS 配置。

      juicefs.cache-sizejuicefs.free-space 需要按需配置。juicefs.token 需要到 JuiceFS 控制台获取。

      [
      {
      "classification": "core-site",
      "properties": {
      "fs.jfs.impl": "com.juicefs.JuiceFileSystem",
      "juicefs.cache-size": "10240",
      "juicefs.access-log": "/tmp/juicefs.access.log",
      "juicefs.discover-nodes-url": "yarn",
      "juicefs.conf-dir": "/etc/juicefs",
      "juicefs.cache-full-block": "false",
      "juicefs.token": "",
      "juicefs.cache-group": "yarn",
      "juicefs.free-space": "0.3",
      "juicefs.cache-dir": "/mnt*/jfs",
      "fs.AbstractFileSystem.jfs.impl": "com.juicefs.JuiceFS"
      }
      },
      {
      "classification": "hbase-site",
      "properties": {
      "hbase.rootdir": "jfs: //{name}/hbase"
      }
      }
      ]
  2. 在 General Cluster Settings 界面添加引导操作

    下载 emr-boot.sh 脚本和 juicefs-hadoop.jar,并上传到您的对象存储上。

    「脚本位置」填写 emr-boot.sh 的 S3 地址,「参数」填写 juicefs-hadoop-{version}.jar 的 S3 地址。

    • 可以访问公网

      --jar s3://{bucket}/resources/juicefs-hadoop-{version}.jar
    • 无外网连接(私有部署)

      由于 SDk 需要联网下载配置文件来发现 metadata 服务器地址,因此在私有环境下(无外网连接),需要将此文件事先准备好。此配置文件可以从任意一台挂载了 JuiceFS 的机器获取,名为 /root/.juicefs/$VOL_NAME.conf

      将此配置文件同样上传到 S3 上,然后在引导操作的参数里面填写下面配置:

      --jar s3://{bucket}/{jar-path}
      --conf-file s3://{bucket}/{conf-file-path}

已有 EMR 集群集成 JuiceFS

在 EMR Master 节点上按照 手动安装 Hadoop SDK 的方法配置 JAR 文件,然后通过 EMR 界面修改配置:

  • Hadoop

    通过 HDFS 服务界面修改 core-site.xml,常用配置:

    fs.jfs.impl=com.juicefs.JuiceFileSystem
    fs.AbstractFileSystem.jfs.impl=com.juicefs.JuiceFS
    juicefs.cache-size=10240
    juicefs.cache-dir=xxxxxx
    juicefs.cache-group=yarn
    juicefs.discover-nodes-url=yarn
    juicefs.accesskey=xxxxxx
    juicefs.secretkey=xxxxxx
    juicefs.token=xxxxxx
    juicefs.access-log=/tmp/juicefs.access.log
  • HBase

    修改 hbase-site

    "hbase.rootdir": "jfs://myjfs/hbase"

    修改 hbase

    "hbase.emr.storageMode": "jfs"

等 EMR 配置刷新后,重启相应服务。

UCloud UHadoop

在 Master 节点上按照 手动安装 Hadoop SDK 的方法配置 JAR 文件。

修改 core-site.xml,具体配置见 详细配置表

最后,重启集群让配置修改生效。

自定义组件

常用组件的 juicefs-hadoop.jar 安装目录

NameInstalling Paths
Hadoop${HADOOP_HOME}/share/hadoop/common/lib/
Hive${HIVE_HOME}/auxlib
Spark${SPARK_HOME}/jars
Presto${PRESTO_HOME}/plugin/hive-hadoop2
Flink${FLINK_HOME}/lib
Datax${DATAX_HOME}/plugin/writer/hdfswriter/libs
${DATAX_HOME}/plugin/reader/hdfsreader/libs/

Apache Spark

  1. 安装 juicefs-hadoop.jar 文件

  2. 添加 JuiceFS 配置,Apache Spark 有多种方法引入配置:

    • 修改 core-site.xml 文件

    • 命令行传入

      spark-shell --master local[*] \
      --conf spark.hadoop.fs.jfs.impl=com.juicefs.JuiceFileSystem \
      --conf spark.hadoop.fs.AbstractFileSystem.jfs.impl=com.juicefs.JuiceFS \
      --conf spark.hadoop.juicefs.token=xxx \
      --conf spark.hadoop.juicefs.accesskey=xxx \
      --conf spark.hadoop.juicefs.secretkey=xxx \
      ...
    • 通过修改 $SPARK_HOME/conf 目录下的 spark-defaults.conf 文件

  1. 安装 juicefs-hadoop.jar 文件

  2. 添加 JuiceFS 配置,Apache Flink 有多种方法引入配置:

    • 通过修改 core-site.xml 文件
    • 通过修改 flink-conf.yaml 文件

Presto

  1. 安装 juicefs-hadoop.jar 文件
  2. 通过修改过 core-site.xml 添加 JuiceFS 配置

DataX

  1. 安装 juicefs-hadoop.jar 文件

  2. 修改 DataX 配置文件:

    "defaultFS": "jfs://myjfs",
    "hadoopConfig": {
    "fs.jfs.impl": "com.juicefs.JuiceFileSystem",
    "fs.AbstractFileSystem.jfs.impl": "com.juicefs.JuiceFS",
    "juicefs.token": "xxxxxxxxxxxxx",
    "juicefs.accesskey": "xxxxxxxxxxxxx",
    "juicefs.secretkey": "xxxxxxxxxxxxx"
    }

测试验证

此处罗列各类 Hadoop 应用的验证步骤,确保能正常使用 JuiceFS。

Hadoop

hadoop fs -ls jfs://${VOL_NAME}/
hadoop fs -mkdir jfs://${VOL_NAME}/jfs-test
hadoop fs -rm -r jfs://${VOL_NAME}/jfs-test

Hive、SparkSQL、Impala

create table if not exists person(
name string,
age int
)

location 'jfs://${VOL_NAME}/tmp/person';
insert into table person values('tom',25);
insert overwrite table person select name, age from person;
select name, age from person;
drop table person;

Spark Shell

import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.fs._
val conf = sc.hadoopConfiguration
val p = new Path("jfs://${VOL_NAME}/")
val fs = p.getFileSystem(conf)
fs.listStatus(p)

HBase

create 'test', 'cf'
list 'test'
put 'test', 'row1', 'cf:a', 'value1'
scan 'test'
get 'test', 'row1'
disable 'test'
drop 'test'

Flume

jfs.sources =r1
jfs.sources.r1.type = org.apache.flume.source.StressSource
jfs.sources.r1.size = 10240
jfs.sources.r1.maxTotalEvents=10
jfs.sources.r1.batchSize=10
jfs.sources.r1.channels = c1

jfs.channels = c1
jfs.channels.c1.type = memory
jfs.channels.c1.capacity = 100
jfs.channels.c1.transactionCapacity = 100

jfs.sinks = k1
jfs.sinks.k1.type = hdfs
jfs.sinks.k1.channel = c1
jfs.sinks.k1.hdfs.path =jfs://${VOL_NAME}/tmp/flume
jfs.sinks.k1.hdfs.writeFormat= Text
jfs.sinks.k1.hdfs.fileType= DataStream
echo 'hello world' > /tmp/jfs_test
hadoop fs -put /tmp/jfs_test jfs://${VOL_NAME}/tmp/
rm -f /tmp/jfs_test
./bin/flink run -m yarn-cluster ./examples/batch/WordCount.jar --input jfs://${VOL_NAME}/tmp/jfs_test --output jfs://${VOL_NAME}/tmp/result

将数据迁移到 JuiceFS

参考「迁移 HDFS 到 JuiceFS」

最佳实践

Hadoop

Hadoop 生态组件一般通过 org.apache.hadoop.fs.FileSystem 类与 HDFS 对接,JuiceFS 同样也通过继承这个类来支持 Hadoop 生态的各个组件。

Hadoop SDK 启用后,就可以通过 hadoop fs 命令操作 JuiceFS:

hadoop fs -ls jfs://{VOL_NAME}/

如果想省去 jfs:// 协议前缀,可以将 fs.defaultFS 设置为 JuiceFS 地址,在 core-site.xml 里面增加如下配置:

<property>
<name>fs.defaultFS</name>
<value>jfs://{VOL_NAME}</value>
</property>
注意

修改 defaultFS 会导致所有没有带协议的路径默认均指向 JuiceFS,可能会导致一些其他问题,建议先在测试环境中测试。

Hive

在 Hive 中建库建表时,使用 LOCATION 来指定存储数据的具体路径。

  • 建库建表

      -- create database
    CREATE DATABASE ... database_name
    LOCATION 'jfs://{VOL_NAME}/path-to-database';

    -- create table
    CREATE TABLE ... table_name
    LOCATION 'jfs://{VOL_NAME}/path-to-table';

    Hive create 的表,默认会在 database 的 location 下。如果 database 的 location 已经在 JuiceFS 上,新建 table 默认也会在 JuiceFS 上。

  • 改库改表

    ALTER DATABASE database_name
    SET LOCATION 'jfs://{VOL_NAME}/path-to-database';

    ALTER TABLE table_name
    SET LOCATION 'jfs://{VOL_NAME}/path-to-table';

    ALTER TABLE table_name PARTITION(...)
    SET LOCATION 'jfs://{VOL_NAME}/path-to-partition';

    Hive 支持使用多种文件系统存储数据。对于未分区表,整张表的数据必须是在同一个文件系统上。对于分区表,每个分区可以独立设置文件系统。

    如果想默认建库就在 JuiceFS 上,可以通过将 hive.metastore.warehouse.dir 修改为 JuiceFS 上的路径。

Spark

Spark 有多种运行模式,如 Standalone、YARN、Kubernetes、Thrift Server 等。

由于 JuiceFS 的特殊的缓存架构设计,JuiceFS 需要保证客户端的机器 IP 尽量不变才能保证缓存的高效利用。 因此,Spark 各种运行模式对于 JuiceFS 的最主要区别就是 executor 进程是否常驻,executor 所在机器的 IP 是否经常变化。

在 executor 进程常驻(例如 Thrift Server 模式),或者在 executor 所在的机器 IP 基本固定并且集群使用率比较高时(Spark on YARN,Standalone),使用「多机分布式缓存」方案 。juicefs.discover-nodes-url 参数需要做相应的设置。

在 executor 进程经常变化,并且机器 IP 也经常变化时(Spark on K8s),使用「独立缓存集群」方案。juicefs.discover-nodes-url 设置为 all

  • Spark shell

    scala> sc.textFile("jfs://{VOL_NAME}/path-to-input").count

HBase

HBase 主要在 HDFS 存储两部分数据,WAL 文件以及 HFile。写入数据时,会先写 WAL,然后再通过 hflush 将数据写入 RegionServer 的 memstore。这样可以保证即使 RegionServer 异常退出时,已经提交的数据仍然可以通过 WAL 恢复。当 RegionServer 里面的数据已经落入 HDFS 形成 HFile 后,WAL 文件会被删除,所以整体 WAL 文件对空间的使用量不会很大。

由于 JuiceFS hflush 的实现与 HDFS 有别(详见hflush 实现),当 juicefs.hflush 设置为 sync 时,JuiceFS 的 hflush 性能比较慢,因此建议将 WAL 文件写入 HDFS,最终的 HFile 写入 JuiceFS。

<property>
<name>hbase.rootdir</name>
<value>jfs://{VOL_NAME}/hbase</value>
</property>
<property>
<name>hbase.wal.dir</name>
<value>hdfs://{NAME_SPACE}/hbase-wal</value>
</property>

Apache Flink 若使用 Streaming File Sink 从文件系统读写数据。为了保证数据的可靠性,Flink 需要在 checkpoint 时使用 RollingPolicy

对于版本小于 2.7 的 Hadoop 版本,由于 HDFS 没有 truncate 功能,需要使用 OnCheckpointRollingPolicy,每次 checkpoint 都关闭并生成新的文件写入数据,会导致大量小文件。

Hadoop2.7 及以上版本的 HDFS,可以使用 DefaultRollingPolicy,可以根据文件大小、时间以及空闲时间来滚动文件。

JuiceFS 实现了 truncate 功能,所以同样也可以使用 DefaultRollingPolicy

Flink 支持使用 plugin 的模式对接文件系统,将 juicefs-hadoop.jar 文件放到 lib 目录下即可,详见手动安装 JuiceFS Hadoop SDK.

Flume

JuiceFS 同样利用 HDFS sink 与 Flume 集成。hdfs.batchSize 表示多少消息调用一次 hflush 接口。

为了保证数据不丢失,juicefs.hflush 应设置为 sync,同时应该将 hdfs.batchSize 调大,将每个批次的数量控制在消息总大小 4MB(默认每个对象块的大小)左右。

另外如果启用了数据压缩(hdfs.fileType 设为 CompressedStream),极端情况下如果出现对象存储不可写入的情况,可能会导致整个压缩文件损坏,导致之前已经 hflush 的数据仍然不可读。如果有这方面的顾虑,建议将 hdfs.fileType 设置为 DataStream,后续再通过 ETL 任务进行数据压缩。

Sqoop

使用 Sqoop 将数据导入 Hive 时,Sqoop 会首先把数据导入 target-dir,然后在通过 hive load 命令将数据加载到 Hive 表,所以使用 Sqoop 时,需要修改 target-dir

  • 1.4.6

    使用此版本的 Sqoop 时还需要将 fs 设为 JuiceFS,因此还需将 HDFS 上面的 mapreduce.tar.gz 复制到 JuiceFS 上的相同路径,默认目录在 HDFS /hdp/apps/${hdp.version}/mapreduce/mapreduce.tar.gz

    sqoop import \
    -fs jfs://{VOL_NAME}/ \
    --target-dir jfs://{VOL_NAME}/path-to-dir
  • 1.4.7

    sqoop import \
    --target-dir jfs://{VOL_NAME}/path-to-dir