Skip to main content

在 Hadoop 中使用 JuiceFS

对于大数据上云场景,用 JuiceFS 替代 HDFS,或共同使用,是很好的增效降本方案,请阅读「从 Hadoop 到云原生,大数据平台如何做存算分离」

如果决定在 Hadoop 上使用 JuiceFS,我们推荐 Hadoop SDK 的方式。理论上你也可以通过 RawLocalFileSystem 访问 JuiceFS 的挂载点,但受限于 HDFS 客户端的实现,这样的实践存在性能问题,不推荐使用。

在 Hadoop 中使用 JuiceFS,有一些重要的区别,请阅读本章以了解。

快速上手

下面是以 Amazon EMR 为例介绍如何在 Hadoop 环境中使用 JuiceFS Hadoop SDK 的视频教程,需要注意视频的配音为英文,建议点击视频链接到 Bilibili 网站播放,并开启自动生成中文字幕功能。

用户组管理

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

内存使用

根据计算任务(如 Spark executor)的读写负载,JuiceFS Hadoop Java SDK 可能需要额外使用 4 * juicefs.memory-size 的堆外内存用来加速读写性能。默认情况下,建议为计算任务至少配置 1.2GB 的堆外内存。

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 能调整各种缓存参数,详见参数配置

缓存位置

默认情况下,Hadoop SDK 使用内存作为缓存位置,由于内存容量往往很有限,且内存占用过多容易引发 OOM 问题。因此建议在生产环境中将缓存位置(即 juicefs.cache-dir 配置)修改为本地盘(如 SSD 盘)路径,并适当调整缓存大小(即 juicefs.cache-size 配置)。

单机缓存

JuiceFS Hadoop SDK 为了更高效地利用本地磁盘缓存,同样也支持和 HDFS 类似的亲和性调度,JuiceFS 对于每个 128MB 的逻辑文件块(大小对齐 HDFS Block,即 dfs.blocksize 配置),会使用一致性哈希算法分配一个 BlockLocation 信息,Spark、MapReduce、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。这样一来,计算集群完全不参与构建缓存组,只从缓存集群读取数据并缓存在它的本地磁盘。

开始使用

请阅读「安装」及其后续章节,开始在 Hadoop 中使用 JuiceFS。