14 Star 71 Fork 13

He3DB / He3FS

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
hadoop_java_sdk.md 31.59 KB
一键复制 编辑 原始数据 按行查看 历史
裴庭伟 提交于 2022-08-31 15:45 . init commit based 0.6.0
sidebar_label sidebar_position slug
Hadoop 使用 JuiceFS
3
/hadoop_java_sdk

在 Hadoop 生态使用 JuiceFS 存储

JuiceFS 提供与 HDFS 接口高度兼容的 Java 客户端,Hadoop 生态中的各种应用都可以在不改变代码的情况下,平滑地使用 JuiceFS 存储数据。

环境要求

1. Hadoop 及相关组件

JuiceFS Hadoop Java SDK 同时兼容 Hadoop 2.x、Hadoop 3.x,以及 Hadoop 生态中的各种主流组件。

2. 用户权限

JuiceFS 默认使用本地的 用户UID 映射,在分布式环境下使用时,为了避免权限问题,请参考文档将需要使用的 用户UID 同步到所有 Hadoop 节点。也可以通过定义一个全局的用户和用户组文件给集群共享读取,查看详情

3. 文件系统

通过 JuiceFS Java 客户端为 Hadoop 生态提供存储,需要提前创建 JuiceFS 文件系统。部署 Java 客户端时,在配置文件中指定已创建文件系统的元数据引擎地址。

创建文件系统可以参考 JuiceFS 快速上手指南

:::note 注意 如果要在分布式环境中使用 JuiceFS,创建文件系统时,请合理规划要使用的对象存储和数据库,确保它们可以被每个集群节点正常访问。 :::

4. 内存资源

JuiceFS Hadoop Java SDK 最多需要额外使用 4 * juicefs.memory-size 的 off-heap 内存用来加速读写性能,默认情况下,最多需要额外 1.2GB 内存(取决于写入负载)。

安装与编译客户端

安装预编译客户端

请参考「安装与升级」文档了解如何下载预编译的 JuiceFS Hadoop Java SDK。

手动编译客户端

:::note 注意 不论为哪个系统环境编译客户端,编译后的 JAR 文件都为相同的名称,且只能部署在匹配的系统环境中,例如在 Linux 中编译则只能用于 Linux 环境。另外,由于编译的包依赖 glibc,建议尽量使用低版本的系统进行编译,这样可以获得更好的兼容性。 :::

编译依赖以下工具:

Linux 和 macOS

克隆仓库:

$ git clone https://github.com/juicedata/juicefs.git

进入目录,执行编译:

:::note 注意 如果使用 Ceph 的 RADOS 作为 JuiceFS 的存储引擎,需要先安装 librados-dev 包并且在编译 libjfs.so 时加上 -tags ceph。 :::

$ cd juicefs/sdk/java
$ make

编译完成后,可以在 sdk/java/target 目录中找到编译好的 JAR 文件,包括两个版本:

  • 包含第三方依赖的包:juicefs-hadoop-X.Y.Z.jar
  • 不包含第三方依赖的包:original-juicefs-hadoop-X.Y.Z.jar

建议使用包含第三方依赖的版本。

Windows

用于 Windows 环境的客户端需要在 Linux 或 macOS 系统上通过交叉编译的方式获得,编译依赖 mingw-w64,需要提前安装。

与编译面向 Linux 和 macOS 客户端的步骤相同,比如在 Ubuntu 系统上,先安装 mingw-w64 包,解决依赖问题:

$ sudo apt install mingw-w64

克隆并进入 JuiceFS 源代码目录,执行以下代码进行编译:

$ cd juicefs/sdk/java
$ make win

部署客户端

让 Hadoop 生态各组件能够正确识别 JuiceFS,需要进行以下配置:

  1. 将编译好的 JAR 文件和 $JAVA_HOME/lib/tools.jar 放置到组件的 classpath 内,常见大数据平台和组件的安装路径见下表。
  2. 将 JuiceFS 相关配置写入配置文件(通常是 core-site.xml),详见客户端配置参数

建议将 JAR 文件放置在一个统一的位置,其他位置通过符号链接进行调用。

大数据平台

名称 安装路径
CDH /opt/cloudera/parcels/CDH/lib/hadoop/lib
/opt/cloudera/parcels/CDH/spark/jars
/var/lib/impala
HDP /usr/hdp/current/hadoop-client/lib
/usr/hdp/current/hive-client/auxlib
/usr/hdp/current/spark2-client/jars
Amazon EMR /usr/lib/hadoop/lib
/usr/lib/spark/jars
/usr/lib/hive/auxlib
阿里云 EMR /opt/apps/ecm/service/hadoop/*/package/hadoop*/share/hadoop/common/lib
/opt/apps/ecm/service/spark/*/package/spark*/jars
/opt/apps/ecm/service/presto/*/package/presto*/plugin/hive-hadoop2
/opt/apps/ecm/service/hive/*/package/apache-hive*/lib
/opt/apps/ecm/service/impala/*/package/impala*/lib
腾讯云 EMR /usr/local/service/hadoop/share/hadoop/common/lib
/usr/local/service/presto/plugin/hive-hadoop2
/usr/local/service/spark/jars
/usr/local/service/hive/auxlib
UCloud UHadoop /home/hadoop/share/hadoop/common/lib
/home/hadoop/hive/auxlib
/home/hadoop/spark/jars
/home/hadoop/presto/plugin/hive-hadoop2
百度云 EMR /opt/bmr/hadoop/share/hadoop/common/lib
/opt/bmr/hive/auxlib
/opt/bmr/spark2/jars

社区开源组件

名称 安装路径
Spark ${SPARK_HOME}/jars
Presto ${PRESTO_HOME}/plugin/hive-hadoop2
Flink ${FLINK_HOME}/lib

客户端配置参数

请参考以下表格设置 JuiceFS 文件系统相关参数,并写入配置文件,一般是 core-site.xml

核心配置

配置项 默认值 描述
fs.jfs.impl io.juicefs.JuiceFileSystem 指定要使用的存储实现,默认使用 jfs:// 作为 scheme。如想要使用其它 scheme(例如 cfs://),则修改为 fs.cfs.impl 即可。无论使用的 scheme 是什么,访问的都是 JuiceFS 中的数据。
fs.AbstractFileSystem.jfs.impl io.juicefs.JuiceFS 指定要使用的存储实现,默认使用 jfs:// 作为 scheme。如想要使用其它 scheme(例如 cfs://),则修改为 fs.AbstractFileSystem.cfs.impl 即可。无论使用的 scheme 是什么,访问的都是 JuiceFS 中的数据。
juicefs.meta 指定预先创建好的 JuiceFS 文件系统的元数据引擎地址。可以通过 juicefs.{vol_name}.meta 格式为客户端同时配置多个文件系统。具体请参考「多文件系统配置」

缓存配置

配置项 默认值 描述
juicefs.cache-dir 设置本地缓存目录,可以指定多个文件夹,用冒号 : 分隔,也可以使用通配符(比如 * )。请预先创建好这些目录,并给予 0777 权限,便于多个应用共享缓存数据。
juicefs.cache-size 0 设置本地缓存目录的容量,单位 MiB,默认为 0,即不开启缓存。如果配置了多个缓存目录,该值代表所有缓存目录容量的总和。
juicefs.cache-full-block true 是否缓存所有读取的数据块,false 表示只缓存随机读的数据块。
juicefs.free-space 0.1 本地缓存目录的最小可用空间比例,默认保留 10% 剩余空间。
juicefs.attr-cache 0 目录和文件属性缓存的过期时间(单位:秒)
juicefs.entry-cache 0 文件项缓存的过期时间(单位:秒)
juicefs.dir-entry-cache 0 目录项缓存的过期时间(单位:秒)
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/

I/O 配置

配置项 默认值 描述
juicefs.max-uploads 20 上传数据的最大连接数
juicefs.max-deletes 2 删除数据的最大连接数
juicefs.get-timeout 5 下载一个对象的超时时间,单位为秒。
juicefs.put-timeout 60 上传一个对象的超时时间,单位为秒。
juicefs.memory-size 300 读写数据的缓冲区最大空间,单位为 MiB。
juicefs.prefetch 1 预读数据块的线程数
juicefs.upload-limit 0 上传带宽限制,单位为 Mbps,默认不限制。
juicefs.download-limit 0 下载带宽限制,单位为 Mbps,默认不限制。

其它配置

配置项 默认值 描述
juicefs.bucket 为对象存储指定跟格式化时不同的访问地址
juicefs.debug false 是否开启 debug 日志
juicefs.access-log 访问日志的路径。需要所有应用都有写权限,可以配置为 /tmp/juicefs.access.log。该文件会自动轮转,保留最近 7 个文件。
juicefs.superuser hdfs 超级用户
juicefs.users null 用户名以及 UID 列表文件的地址,比如 jfs://name/etc/users。文件格式为 <username>:<UID>,一行一个用户。
juicefs.groups null 用户组、GID 以及组成员列表文件的地址,比如 jfs://name/etc/groups。文件格式为 <group-name>:<GID>:<username1>,<username2>,一行一个用户组。
juicefs.umask null 创建文件和目录的 umask 值(如 0022),如果没有此配置,默认值是 fs.permissions.umask-mode
juicefs.push-gateway Prometheus Pushgateway 地址,格式为 <host>:<port>
juicefs.push-auth Prometheus 基本认证信息,格式为 <username>:<password>
juicefs.push-graphite Graphite 地址,格式为 <host>:<port>
juicefs.push-interval 10 指标推送的时间间隔,单位为秒。
juicefs.fast-resolve true 是否开启快速元数据查找(通过 Redis Lua 脚本实现)
juicefs.no-usage-report false 是否上报数据。仅上版本号等使用量数据,不包含任何用户信息。
juicefs.block.size 134217728 单位为字节,同 HDFS 的 dfs.blocksize,默认 128 MB
juicefs.file.checksum false DistCp 使用 -update 参数时,是否计算文件 Checksum

多文件系统配置

当需要同时使用多个 JuiceFS 文件系统时,上述所有配置项均可对特定文件系统进行指定,只需要将文件系统名字放在配置项的中间,比如下面示例中的 jfs1jfs2

<property>
  <name>juicefs.jfs1.meta</name>
  <value>redis://jfs1.host:port/1</value>
</property>
<property>
  <name>juicefs.jfs2.meta</name>
  <value>redis://jfs2.host:port/1</value>
</property>

配置示例

以下是一个常用的配置示例,请替换 juicefs.meta 配置中的 {HOST}{PORT}{DB} 变量为实际的值。

<property>
  <name>fs.jfs.impl</name>
  <value>io.juicefs.JuiceFileSystem</value>
</property>
<property>
  <name>fs.AbstractFileSystem.jfs.impl</name>
  <value>io.juicefs.JuiceFS</value>
</property>
<property>
  <name>juicefs.meta</name>
  <value>redis://{HOST}:{PORT}/{DB}</value>
</property>
<property>
  <name>juicefs.cache-dir</name>
  <value>/data*/jfs</value>
</property>
<property>
  <name>juicefs.cache-size</name>
  <value>1024</value>
</property>
<property>
  <name>juicefs.access-log</name>
  <value>/tmp/juicefs.access.log</value>
</property>

Hadoop 环境配置

请参照前述各项配置表,将配置参数加入到 Hadoop 配置文件 core-site.xml 中。

CDH6

如果使用的是 CDH 6 版本,除了修改 core-site 外,还需要通过 YARN 服务界面修改 mapreduce.application.classpath,增加:

$HADOOP_COMMON_HOME/lib/juicefs-hadoop.jar

HDP

除了修改 core-site 外,还需要通过 MapReduce2 服务界面修改配置 mapreduce.application.classpath,在末尾增加(变量无需替换):

/usr/hdp/${hdp.version}/hadoop/lib/juicefs-hadoop.jar

Flink

将配置参数加入 conf/flink-conf.yaml。如果只是在 Flink 中使用 JuiceFS, 可以不在 Hadoop 环境配置 JuiceFS,只需要配置 Flink 客户端即可。

Hudi

:::note 注意 Hudi 自 v0.10.0 版本开始支持 JuiceFS,请确保使用正确的版本。 :::

请参考「Hudi 官方文档」了解如何配置 JuiceFS。

Kafka Connect

可以使用 Kafka Connect 和 HDFS Sink Connector(HDFS 2, HDFS 3)将数据落盘存储到 JuiceFS。

首先需要将 JuiceFS 的 SDK 添加到 Kafka Connect 的 classpath 内,如 /usr/share/java/confluentinc-kafka-connect-hdfs/lib.

在新建 Connect Sink 任务时,做如下配置:

  • 指定 hadoop.conf.dir 为包含 core-site.xml 配置文件的目录,若没有运行在 Hadoop 环境,可创建一个单独目录,如 /usr/local/juicefs/hadoop,然后将与 JuiceFS 相关的配置添加到 core-site.xml
  • 指定 store.urljfs:// 的路径

举例:

# 省略其他配置项...
hadoop.conf.dir=/path/to/hadoop-conf
store.url=jfs://path/to/store

重启服务

当需要使用以下组件访问 JuiceFS 数据时,需要重启相关服务。

:::note 注意 在重启之前需要保证 JuiceFS 配置已经写入配置文件,通常可以查看机器上各组件配置的 core-site.xml 里面是否有 JuiceFS 相关配置。 :::

组件名 服务名
Hive HiveServer
Metastore
Spark ThriftServer
Presto Coordinator
Worker
Impala Catalog Server
Daemon
HBase Master
RegionServer

HDFS、Hue、ZooKeeper 等服务无需重启。

若访问 JuiceFS 出现 Class io.juicefs.JuiceFileSystem not foundNo FilesSystem for scheme: jfs 错误,请参考 FAQ

环境验证

JuiceFS Java 客户端部署完成以后,可以采用以下方式验证部署是否成功。

Hadoop

$ hadoop fs -ls jfs://{JFS_NAME}/

:::info 说明 这里的 JFS_NAME 是创建 JuiceFS 文件系统时指定的名称。 :::

Hive

CREATE TABLE IF NOT EXISTS person
(
  name STRING,
  age INT
) LOCATION 'jfs://{JFS_NAME}/tmp/person';

监控指标收集

请查看「监控」文档了解如何收集及展示 JuiceFS 监控指标

从 HDFS 迁移数据到 JuiceFS

从 HDFS 迁移数据到 JuiceFS,一般是使用 DistCp 来拷贝数据,它支持数据校验 (Checksum) 来保证数据的正确性。

DistCp 是使用 HDFS 的 getFileChecksum() 接口来获得文件的校验码,然后对比拷贝后的文件的校验码来确保数据是一样的。

Hadoop 默认使用的 Checksum 算法是 MD5-MD5-CRC32, 严重依赖 HDFS 的实现细节。它是根据文件目前的分块形式,使用 MD5-CRC32 算法汇总每一个数据块的 Checksum(把每一个 64K 的 block 的 CRC32 校验码汇总,再算一个 MD5),然后再用 MD5 计算校验码。如果 HDFS 集群的分块大小不同,就没法用这个算法进行比较。

为了兼容 HDFS,JuiceFS 也实现了该 MD5-MD5-CRC32 算法,它会将文件的数据读一遍,用同样的算法计算得到一个 checksum,用于比较。

因为 JuiceFS 是基于对象存储实现的,后者已经通过多种 Checksum 机制保证了数据完整性,JuiceFS 默认没有启用上面的 Checksum 算法,需要通过 juicefs.file.checksum 配置来启用。

因为该算法依赖于相同的分块大小,需要通过 juicefs.block.size 配置将分块大小设置为跟 HDFS 一样(默认值是 dfs.blocksize,它的默认值是 128MB)。

另外,HDFS 里支持给每一个文件设置不同的分块大小,而 JuiceFS 不支持,如果启用 Checksum 校验的话会导致拷贝部分文件失败(因为分块大小不同),JuiceFS Hadoop Java SDK 对 DistCp 打了一个热补丁(需要 tools.jar)来跳过这些分块不同的文件(不做比较,而不是抛异常)。

基准测试

以下提供了一系列方法,使用 JuiceFS 客户端内置的压测工具,对已经成功部署了客户端环境进行性能测试。

1. 本地测试

元数据性能

  • create

    hadoop jar juicefs-hadoop.jar nnbench create -files 10000 -baseDir jfs://{JFS_NAME}/tmp/benchmarks/NNBench -local

    此命令会 create 10000 个空文件

  • open

    hadoop jar juicefs-hadoop.jar nnbench open -files 10000 -baseDir jfs://{JFS_NAME}/tmp/benchmarks/NNBench -local

    此命令会 open 10000 个文件,并不读取数据

  • rename

    hadoop jar juicefs-hadoop.jar nnbench rename -files 10000 -baseDir jfs://{JFS_NAME}/tmp/benchmarks/NNBench -local
  • delete

    hadoop jar juicefs-hadoop.jar nnbench delete -files 10000 -baseDir jfs://{JFS_NAME}/tmp/benchmarks/NNBench -local
  • 参考值

    操作 TPS 时延(ms)
    create 644 1.55
    open 3467 0.29
    rename 483 2.07
    delete 506 1.97

I/O 性能

  • 顺序写

    hadoop jar juicefs-hadoop.jar dfsio -write -size 20000 -baseDir jfs://{JFS_NAME}/tmp/benchmarks/DFSIO -local
  • 顺序读

    hadoop jar juicefs-hadoop.jar dfsio -read -size 20000 -baseDir jfs://{JFS_NAME}/tmp/benchmarks/DFSIO -local

    如果多次运行此命令,可能会出现数据被缓存到了系统缓存而导致读取速度非常快,只需清除 JuiceFS 的本地磁盘缓存即可

  • 参考值

    操作 吞吐(MB/s)
    write 647
    read 111

如果机器的网络带宽比较低,则一般能达到网络带宽瓶颈

2. 分布式测试

以下命令会启动 MapReduce 分布式任务程序对元数据和 IO 性能进行测试,测试时需要保证集群有足够的资源能够同时启动所需的 map 任务。

本项测试使用的计算资源:

  • 服务器:3 台 4 核 32 GB 内存的云服务器,突发带宽 5Gbit/s。
  • 数据库:阿里云 Redis 5.0 社区 4G 主从版

元数据性能

  • create

    hadoop jar juicefs-hadoop.jar nnbench create -maps 10 -threads 10 -files 1000 -baseDir jfs://{JFS_NAME}/tmp/benchmarks/NNBench

    此命令会启动 10 个 map task,每个 task 有 10 个线程,每个线程会创建 1000 个空文件,总共 100000 个空文件

  • open

    hadoop jar juicefs-hadoop.jar nnbench open -maps 10 -threads 10 -files 1000 -baseDir jfs://{JFS_NAME}/tmp/benchmarks/NNBench

    此命令会启动 10 个 map task,每个 task 有 10 个线程,每个线程会 open 1000 个文件,总共 open 100000 个文件

  • rename

    hadoop jar juicefs-hadoop.jar nnbench rename -maps 10 -threads 10 -files 1000 -baseDir jfs://{JFS_NAME}/tmp/benchmarks/NNBench

    此命令会启动 10 个 map task,每个 task 有 10 个线程,每个线程会 rename 1000 个文件,总共 rename 100000 个文件

  • delete

    hadoop jar juicefs-hadoop.jar nnbench delete -maps 10 -threads 10 -files 1000 -baseDir jfs://{JFS_NAME}/tmp/benchmarks/NNBench

    此命令会启动 10 个 map task,每个 task 有 10 个线程,每个线程会 delete 1000 个文件,总共 delete 100000 个文件

  • 参考值

    • 10 并发

      操作 IOPS 时延(ms)
      create 4178 2.2
      open 9407 0.8
      rename 3197 2.9
      delete 3060 3.0
    • 100 并发

      操作 IOPS 时延(ms)
      create 11773 7.9
      open 34083 2.4
      rename 8995 10.8
      delete 7191 13.6

I/O 性能

  • 连续写

    hadoop jar juicefs-hadoop.jar dfsio -write -maps 10 -size 10000 -baseDir jfs://{JFS_NAME}/tmp/benchmarks/DFSIO

    此命令会启动 10 个 map task,每个 task 写入 10000MB 的数据

  • 连续读

    hadoop jar juicefs-hadoop.jar dfsio -read -maps 10 -size 10000 -baseDir jfs://{JFS_NAME}/tmp/benchmarks/DFSIO

    此命令会启动 10 个 map task,每个 task 读取 10000MB 的数据

  • 参考值

    操作 平均吞吐(MB/s) 总吞吐(MB/s)
    write 198 1835
    read 124 1234

3. TPC-DS

测试数据集 100GB 规模,测试 Parquet 和 ORC 两种文件格式。

本次测试仅测试前 10 个查询。

使用 Spark Thrift JDBC/ODBC Server 开启 Spark 常驻进程,然后通过 Beeline 连接提交任务。

测试硬件

节点类型 机器型号 CPU 内存 磁盘 数量
Master 阿里云 ecs.r6.xlarge 4 32GiB 系统盘:100GiB 1
Core 阿里云 ecs.r6.xlarge 4 32GiB 系统盘:100GiB
数据盘:500GiB 高效云盘 x 2
3

软件配置

Spark Thrift JDBC/ODBC Server
${SPARK_HOME}/sbin/start-thriftserver.sh \
  --master yarn \
  --driver-memory 8g \
  --executor-memory 10g \
  --executor-cores 3 \
  --num-executors 3 \
  --conf spark.locality.wait=100 \
  --conf spark.sql.crossJoin.enabled=true \
  --hiveconf hive.server2.thrift.port=10001
JuiceFS 缓存配置

Core 节点的 2 块数据盘挂载在 /data01/data02 目录下,core-site.xml 配置如下:

<property>
  <name>juicefs.cache-size</name>
  <value>200000</value>
</property>
<property>
  <name>juicefs.cache-dir</name>
  <value>/data*/jfscache</value>
</property>
<property>
  <name>juicefs.cache-full-block</name>
  <value>false</value>
</property>
<property>
  <name>juicefs.discover-nodes-url</name>
  <value>yarn</value>
</property>
<property>
  <name>juicefs.attr-cache</name>
  <value>3</value>
</property>
<property>
  <name>juicefs.entry-cache</name>
  <value>3</value>
</property>
<property>
  <name>juicefs.dir-entry-cache</name>
  <value>3</value>
</property>

测试

任务提交的命令如下:

${SPARK_HOME}/bin/beeline -u jdbc:hive2://localhost:10001/${DATABASE} \
  -n hadoop \
  -f query{i}.sql

结果

JuiceFS 可以使用本地磁盘作为缓存加速数据访问,以下数据是分别使用 Redis 和 TiKV 作为 JuiceFS 的元数据引擎跑 4 次后的结果(单位秒)。

ORC
Queries JuiceFS (Redis) JuiceFS (TiKV) HDFS
q1 20 20 20
q2 28 33 26
q3 24 27 28
q4 300 309 290
q5 116 117 91
q6 37 42 41
q7 24 28 23
q8 13 15 16
q9 87 112 89
q10 23 24 22

orc

Parquet
Queries JuiceFS (Redis) JuiceFS (TiKV) HDFS
q1 33 35 39
q2 28 32 31
q3 23 25 24
q4 273 284 266
q5 96 107 94
q6 36 35 42
q7 28 30 24
q8 11 12 14
q9 85 97 77
q10 24 28 38

parquet

FAQ

1. 出现 Class io.juicefs.JuiceFileSystem not found 异常

出现这个异常的原因是 juicefs-hadoop.jar 没有被加载,可以用 lsof -p {pid} | grep juicefs 查看 JAR 文件是否被加载。需要检查 JAR 文件是否被正确地放置在各个组件的 classpath 里面,并且保证 JAR 文件有可读权限。

另外,在某些发行版 Hadoop 环境中,需要修改 mapred-site.xml 中的 mapreduce.application.classpath 参数,添加 juicefs-hadoop.jar 的路径。

2. 出现 No FilesSystem for scheme: jfs 异常

出现这个异常的原因是 core-site.xml 配置文件中的 JuiceFS 配置没有被读取到,需要检查组件配置的 core-site.xml 中是否有 JuiceFS 相关配置。

1
https://gitee.com/he3db/he3fs.git
git@gitee.com:he3db/he3fs.git
he3db
he3fs
He3FS
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891