在 Hadoop 中通过挂载的方式使用 JuiceFS

提示:本案例使用的是 JuiceFS 云服务。如果你使用的是 JuiceFS 开源客户端,请注意替换案例中的程序和命令。

Hadoop 或者 Spark 的存储部分(FileSystem API)是可插拔的,支持很多不同的存储系统,默认就可以通过 LocalFS 支持 JuiceFS,只需要把 JuiceFS 挂载到 Hadoop 集群的所有节点即可。

准备工作

很多 Hadoop 集群默认没有配置公网 IP(比如 Ucloud 里面的 UHadoop),而 JuiceFS 在访问元数据时需要能够访问公网,一种解决办法是给所有Hadoop 节点都配置上弹性 IP,另外一种办法是给 Hadoop 集群增加可访问外网的路由器,配置方法如下:

在一台有外网IP的节点上配置IP包转发:

  1. echo 1 > /proc/sys/net/ipv4/ip_forward
  2. echo 1 > /proc/sys/net/ipv4/conf/all/forwarding
  3. echo 1 > /proc/sys/net/ipv4/conf/default/forwarding
  4. iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
  5. iptables -A FORWARD -i eth0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
  6. iptables -A FORWARD -i eth0 -o eth0 -j ACCEPT

(建议将 net.ipv4.ip_forward=1 加入到 /etc/systl.conf, 并使用 iptables-save 来保存规则,这样当节点重启后这些规则仍然是有效的)

在 Hadoop 集群的节点上使用以上节点作为路由器来访问外网(假定内网网段是 10.0.0.0/8, 10.1.0.1 是默认路由器,10.1.100.100 是以上路由器的内网 IP):

  1. ip route add 10.0.0.0/8 via 10.1.0.1
  2. route del default gw 10.1.0.1
  3. route add default gw 10.1.100.100

挂载 JuiceFS

JuiceFS 需要挂载到同一个挂载点,建议使用 /jfs,后面的教程也会假设 JuiceFS 挂载在 /jfs

  1. wget juicefs.com/static/juicefs
  2. chmod +x juicefs
  3. sudo ./juicefs auth NAME --token TOKEN --accesskey ACCESS_KEY --secretkey SECRET_KEY
  4. sudo ./juicefs mount NAME /jfs

为了简化管理,可以将上述命令加入到集群节点的初始化脚本中。

在 Spark 中访问 JuiceFS

一旦 JuiceFS 挂载好后,使用 Spark 来读写 JuiceFS 中的数据将非常简单,只需要将读写数据的路径指向 JuiceFS 的挂载点即可,比如

  1. spark.range(1, 1000).write.parquet("file:///jfs/a/range")
  2. spark.read.parquet("file:///jfs/a/range")

如果能够更改 Hadoop 的配置文件(core-site.xml),使用 LocalFS 作为默认的文件系统,

  1. <property>
  2. <name>fs.defaultFS</name>
  3. <value>file:///</value>
  4. </property>

或者把以下加入到 Spark 的配置文件 $SPARK_HOME/conf/spark-defaults.conf

  1. spark.hadoop.fs.defaultFS = file:///jfs/”

或者把一下加入到 Spark 脚本的前面:

  1. Spark > spark.sparkContext.hadoopConfiguration.set(“fs.defaultFS”, file:///”)

那么以上可以简写为:

  1. Spark > spark.range(1, 1000).write.parquet("/jfs/a/range")
  2. Spark > spark.read.parquet("/jfs/a/range")

Hadoop 中其他组件访问 JuiceFS 的方法也非常类似。

在 Hive 中使用 JuiceFS

Hive 同样是支持 JuiceFS 的,当 JuiceFS 不是 Hive 的默认存储时,需要把表创建为 External Table, 并制定存储位置为 JuiceFS 中,比如:

  1. $ mkdir /jfs/hive/test_json
  1. Hive > CREATE external TABLE test_json(id BIGINT,text STRING)ROW FORMAT SERDE 'org.apache.hadoop.hive.contrib.serde2.JsonSerde' STORED AS TEXTFILE location 'file:///jfs/hive/test_json';
  2. Hive > LOAD DATA INPATH "file:///jfs/hive/test.json" OVERWRITE INTO TABLE test_json;
  3. Hive > select * from test_json;

Hive 的 扩展包也可以放到 JuiceFS 中,比如:

  1. Hive > Add Jar file:///jfs/hive/lib/hive-json-serde.jar;

如果把 JuiceFS 设置为 Hive 的默认存储,使用上基本不需要要做任何改变。

注意:Hive metastore 所在的节点也需要挂载JuiceFS到同样的挂载点。

数据迁移

从 HDFS 迁移到 JuiceFS 比较简单,大致有一下几个步骤:

  • 部署 JuiceFS:在 Hadoop 集群中的每个节点上挂载 JuiceFS 到相同的挂载点,
  • 将新数据写入 JuiceFS:修改应用代码或者配置中的写入数据路径为 file:///jfs/xxx,使得新数据会写入到 JuiceFS 中。
  • 如果 HDFS 已有部分数据,使用 distcp 命令(由 Hadoop 提供)将数据并行复制到 JuiceFS 中。
  • 修改读已有数据的代码,直接从 JuiceFS 读数据。
  • 删除 HDFS 中存储的数据。

在 JuiceFS 上运行 HBase

HBase 也同样支持 JuiceFS ,只需要把配置文件 hbase-site.xml 中的 hbase.rootdir 指定为 JuiceFS 中的一个目录即可 (同样要求将 JuiceFS 挂载到 HBase 集群的所有节点的相同位置),比如:

  1. <property>
  2. <name>hbase.rootdir</name>
  3. <value>file:///jfs/hbase</value>
  4. </property>

注意:要将该目录的所有者设置为 hadoop (运行 HBase 服务的用户) 。

将数据从 HDFS 迁移到 JuiceFS 步骤:

  • 为运行在 HDFS 中的表创建快照
  1. hbase> snapshot 'MyTable', 'MySnapshot'
  • 将创建的快照从 HDFS 拷贝到 JuiceFS
  1. $ hbase org.apache.hadoop.hbase.snapshot.ExportSnapshot -snapshot MySnapshot -copy-to file:///jfs/hbase -mappers 16
  • 将 HBase 的数据目录改为 JuiceFS 并重启
  • 在 HBase 中创建表,并从快照恢复数据
  1. hbase> restore_snapshot 'MySnapshot'