在 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 分钟内自动更新信息,无需重启服务。具体操作如下:
-
在所有节点修改
core-site.xml
,添加如下配置:<property>
<name>juicefs.grouping</name>
<value>jfs://{VOL_NAME}/etc/group</value>
</property> -
在 JuiceFS 上创建
juicefs.grouping
所指向的配置文件 -
修改此文件,添加用户组信息,格式如下:
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。