Ubuntu 22.04 安装 Apache Uniffle 0.10.0 指南
Ubuntu 22.04 实测的 Apache Uniffle 0.10.0 安装教程:JDK 8、Hadoop 依赖、coordinator 与 shuffle-server 配置启动、Spark shuffle 验证与卸载清理。
Ubuntu 22.04 安装 Apache Uniffle 0.10.0 指南
一、版本与环境说明
本文所有命令与回显均来自在 Ubuntu 22.04.5 LTS 服务器上的真实安装验证,账号为 root。
| 项目 | 值 |
|---|---|
| 操作系统 | Ubuntu 22.04.5 LTS(x86_64) |
| Apache Uniffle | 0.10.0(bin 发行包,gitCommitId 2df9eebe) |
| JDK | OpenJDK 1.8.0_504(apt 源 openjdk-8-jdk) |
| Hadoop | 3.3.6(仅提供 classpath 依赖,不需要启动 HDFS) |
| Spark(验证用) | 3.5.9(bin-hadoop3 发行包) |
| 部署目录 | /opt/uniffle |
| 数据目录 | /data/uniffle/shuffle_data |
Uniffle 0.10.0 的 bin 发行包基于 hadoop2.8 构建,解压后的目录名为 apache-uniffle-0.10.0-hadoop2.8,属正常现象。该版本从 0.9.x 起做了大幅重构:shuffle-server 的配置文件名为 conf/server.conf(不再是 shuffle-server.conf),全部参数采用 rss. 前缀命名空间,JVM 堆大小在 conf/rss-env.sh 中设置,并新增了 dashboard 组件与 uniffle 统一命令行工具。
二、部署前置条件
- 以 root 账号登录服务器,具备 sudo 或直接 root 权限。
- 服务器可访问外网或已配置可用的 apt 内网源(用于安装 JDK)。
- 硬件建议:内存 4GB 起(coordinator 与 shuffle-server 各限 512MB 堆,另需给系统与验证用 Spark 留余量);磁盘 20GB 起(安装包约 1GB,加上日志与 shuffle 数据)。
- 端口规划(本文实测端口,同机部署必须错开,详见注意事项):
- coordinator:RPC 19991、HTTP 19990
- shuffle-server:RPC 19997、HTTP 19996
三、版本选型说明
截至本文撰写日,Apache 官方下载页 downloads.apache.org/uniffle/ 下最新稳定版为 0.10.0,发行物为 apache-uniffle-0.10.0-bin.tar.gz(二进制包,约 263MB)与 apache-uniffle-0.10.0-src.tar.gz(源码包)。生产环境选二进制包即可;archive.apache.org/dist/uniffle/ 保留历史版本。
安装包校验方式(官方提供 sha512 文件,需处理后交给 sha512sum 校验):
cd /opt
mkdir -p /opt/pkg && cd /opt/pkg
curl -O https://downloads.apache.org/uniffle/0.10.0/apache-uniffle-0.10.0-bin.tar.gz
curl -O https://downloads.apache.org/uniffle/0.10.0/apache-uniffle-0.10.0-bin.tar.gz.sha512
sed 's/ |.*//;s/^/ /' apache-uniffle-0.10.0-bin.tar.gz.sha512 | sha512sum -c
实测回显:
apache-uniffle-0.10.0-bin.tar.gz: OK
四、部署步骤
4.1 安装 JDK 8
apt-get update
apt-get install -y openjdk-8-jdk curl wget
java -version
实测回显:
openjdk version "1.8.0_504"
OpenJDK Runtime Environment (build 1.8.0_504-504-b01)
OpenJDK 64-Bit Server VM (build 25.504-b01, mixed mode)
JDK 安装路径为 /usr/lib/jvm/java-8-openjdk-amd64,后续 rss-env.sh 需要引用该路径。
4.2 安装 Hadoop 3.3.6(仅作 classpath 依赖)
Uniffle 0.10.0 的 coordinator 与 shuffle-server 启动脚本会执行 HADOOP_HOME/bin/hadoop classpath 命令加载 Hadoop 相关 jar,即使不使用 HDFS 存储,这一依赖也不可省略,否则启动即报 NoClassDefFoundError: org/apache/hadoop/conf/Configuration。
cd /opt/pkg
curl -O https://downloads.apache.org/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gz
tar xzf hadoop-3.3.6.tar.gz -C /opt/
mv /opt/hadoop-3.3.6 /opt/hadoop
echo "export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64" >> /opt/hadoop/etc/hadoop/hadoop-env.sh
/opt/hadoop/bin/hadoop version
首次执行 hadoop version 会报 ERROR: JAVA_HOME is not set,写入 hadoop-env.sh 后实测回显:
Hadoop 3.3.6
Source code repository https://github.com/apache/hadoop.git -r a3b9c37a397ad418b4bbe5bba979798871798798
整个过程只解压 Hadoop 二进制包,不需要启动 NameNode、DataNode 等 HDFS 服务。
4.3 解压 Uniffle 到 /opt/uniffle
cd /opt/pkg
tar xzf apache-uniffle-0.10.0-bin.tar.gz -C /opt/
mv /opt/apache-uniffle-0.10.0-hadoop2.8 /opt/uniffle
ls /opt/uniffle
实测回显(tar 解压时会打印大量 Ignoring unknown extended header keyword 'LIBARCHIVE.xattr...' 警告,属 macOS 打包属性,无害可忽略):
bin conf jars LICENSE licenses NOTICE README.md
4.4 配置 JVM 堆与环境变量(rss-env.sh)
conf/rss-env.sh 控制 JVM 堆大小与 HADOOP_HOME。修改三处关键值(JVM 堆各进程限制在 512MB):
cd /opt/uniffle/conf
sed -i 's|^# JAVA_HOME=<java_home_dir>|JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64|' rss-env.sh
sed -i 's|^# HADOOP_HOME=<hadoop_home_dir>|HADOOP_HOME=/opt/hadoop|' rss-env.sh
sed -i 's|^XMX_SIZE="8g"|XMX_SIZE="512m"|' rss-env.sh
sed -i 's|^SHUFFLE_SERVER_XMX_SIZE="80g"|SHUFFLE_SERVER_XMX_SIZE="512m"|' rss-env.sh
grep -E '^(JAVA_HOME|HADOOP_HOME|XMX_SIZE|SHUFFLE_SERVER_XMX_SIZE)' rss-env.sh
实测回显:
JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
HADOOP_HOME=/opt/hadoop
XMX_SIZE="512m"
SHUFFLE_SERVER_XMX_SIZE="512m"
说明:XMX_SIZE 对应 coordinator 堆,SHUFFLE_SERVER_XMX_SIZE 对应 shuffle-server 堆,默认值 8g 与 80g 在普通服务器上过大会直接启动失败,必须改小。HADOOP_HOME 必须在此文件中显式设置,rss-env.sh 顶部有 set -o nounset,未定义该变量时 uniffle 命令行工具会直接报 HADOOP_HOME: unbound variable。
4.5 编写 coordinator.conf
将 /opt/uniffle/conf/coordinator.conf 重写为以下内容(发行包默认值在单机部署下有两个问题:默认端口 19999 与 shuffle-server 相同,且包含指向不存在文件的 rss.coordinator.exclude.nodes.file.path 占位行):
rss.rpc.server.port 19991
rss.jetty.http.port 19990
rss.coordinator.server.heartbeat.timeout 30000
rss.coordinator.app.expired 600000
rss.coordinator.shuffle.nodes.max 1
rss.coordinator.select.partition.strategy CONTINUOUS
其中 rss.coordinator.shuffle.nodes.max 既是 coordinator 返回给计算引擎的候选节点数上限,也是 access 准入检查的默认必需节点数,单机部署必须设为 1,否则 Spark 客户端接入会被 AccessClusterLoadChecker 拒绝并静默回退到 Spark 原生 shuffle。参数含义见配置参数详解篇。
4.6 编写 server.conf
将 /opt/uniffle/conf/server.conf 重写为以下内容(存储类型用 MEMORY_LOCALFILE,无需 HDFS 也无需 test mode):
rss.rpc.server.port 19997
rss.jetty.http.port 19996
rss.storage.basePath /data/uniffle/shuffle_data
rss.storage.type MEMORY_LOCALFILE
rss.coordinator.quorum 127.0.0.1:19991
rss.server.buffer.capacity 256m
rss.server.read.buffer.capacity 128m
rss.server.flush.thread.alive 5
rss.server.flush.localfile.threadPool.size 10
rss.server.disk.capacity 10g
rss.server.single.buffer.flush.enabled true
rss.server.single.buffer.flush.threshold 64m
创建数据目录:
mkdir -p /data/uniffle/shuffle_data
注意 rss.storage.type 取值:MEMORY_LOCALFILE(内存加本地文件)开箱即用;纯 LOCALFILE(直接写本地文件)在 0.10.0 被视为测试模式专用,server 端未开 rss.test.mode.enable true 时启动即抛 IllegalArgumentException: RSS storage type about LOCALFILE and HADOOP should be used in test mode,Spark 客户端同样需要 spark.rss.test.mode.enable true,详见常见问题。
4.7 启动 coordinator 与 shuffle-server
cd /opt/uniffle/bin
./start-coordinator.sh
./start-shuffle-server.sh
实测回显(两脚本类似,打印 JVM 参数后输出 pid 文件位置):
Write pid file to /opt/uniffle/coordinator.pid
Starting coordinator
classpath: /opt/uniffle/conf:/opt/hadoop/bin/../share/hadoop/common/...:/opt/uniffle/jars/coordinator/*:/opt/uniffle/jars/common/*
启动为 nohup 后台方式,日志写入 /opt/uniffle/logs/coordinator.log 与 /opt/uniffle/logs/shuffle_server.log。
4.8 验证进程、端口与服务注册
jps -l
实测回显:
5819 org.apache.uniffle.coordinator.CoordinatorServer
6008 org.apache.uniffle.server.ShuffleServer
6102 sun.tools.jps.Jps
验证 JVM 堆限制(jps -v 打印完整 JVM 参数):
jps -v | grep -E 'CoordinatorServer|ShuffleServer'
实测回显(节选关键参数):
5819 org.apache.uniffle.coordinator.CoordinatorServer -Xms512m -Xmx512m ...
6008 org.apache.uniffle.server.ShuffleServer -Xms512m -Xmx512m ...
等待 shuffle-server 心跳注册(默认 3 秒间隔)后,通过 coordinator 的 HTTP 接口验证:
curl -s http://127.0.0.1:19990/api/server/nodes/summary
curl -s http://127.0.0.1:19990/api/server/nodes
curl -s http://127.0.0.1:19990/api/coordinator/info
实测回显:
{"code":0,"data":{"ACTIVE":1},"errMsg":"success"}
{"code":0,"data":[{"usedMemory":0,"preAllocatedMemory":0,"availableMemory":268435456,"eventSizeThreshold":3145728,"readable":true,"status":"ACTIVE","storage":[{"type":"MEMORY_LOCALFILE","basePath":"/data/uniffle/shuffle_data","capacity":10737418240,"usedPoint":0,"status":"HEALTHY"}],"tags":["GRPC_NETTY"],"id":"172.17.0.13-19997-17000","lastHeartBeatTime":1791786968347}],"errMsg":"success"}
{"code":0,"data":{"serverIp":"172.17.0.13","coordinatorId":"172.17.0.13-19991","startTime":1791786964611,"serverPort":"19991","version":"0.10.0","gitCommitId":"2df9eebe","serverWebPort":"19990"},"errMsg":"success"}
两个端点返回 success 且 ACTIVE 为 1,说明 shuffle-server 已成功注册到 coordinator。0.10.0 已移除旧版的 /api/server/list 接口,请使用上述 /api/server/nodes 系列。
4.9 Spark shuffle 链路验证(可选但强烈建议)
下载 Spark 3.5.9 并把 Uniffle 的 Spark3 客户端 jar 拷入 Spark jars 目录:
cd /opt/pkg
curl -O https://downloads.apache.org/spark/spark-3.5.9/spark-3.5.9-bin-hadoop3.tgz
tar xzf spark-3.5.9-bin-hadoop3.tgz -C /opt/
cp /opt/uniffle/jars/client/spark3/rss-client-spark3-shaded-0.10.0.jar /opt/spark-3.5.9-bin-hadoop3/jars/
cp /opt/spark-3.5.9-bin-hadoop3/conf/spark-defaults.conf.template /opt/spark-3.5.9-bin-hadoop3/conf/spark-defaults.conf
在 spark-defaults.conf 追加 Uniffle 接入参数:
spark.master local[2]
spark.shuffle.enabled true
spark.shuffle.service.enabled false
spark.shuffle.manager org.apache.spark.shuffle.DelegationRssShuffleManager
spark.rss.coordinator.quorum 127.0.0.1:19991
spark.rss.storage.type MEMORY_LOCALFILE
spark.serializer org.apache.spark.serializer.KryoSerializer
spark.sql.shuffle.partitions 16
执行带 shuffle 的聚合作业:
cd /opt/spark-3.5.9-bin-hadoop3
bin/spark-shell --driver-memory 1g
在 scala 提示符下执行:
val df = spark.range(0, 1000000).selectExpr("id", "id % 100 as k")
df.groupBy("k").count().collect().length
实测返回 res0: Long = 100,作业日志出现 Success to access cluster。随后在服务器上确认 coordinator 记录了该应用:
curl -s http://127.0.0.1:19990/api/app/total
实测回显(appTotality 由 0 变 1,应用结束后 server 端自动清理 shuffle 数据):
{"code":0,"data":{"appTotality":1,"appCurrent":0},"errMsg":"success"}
shuffle_server.log 中也能看到应用任务信息(数据实际经过 Uniffle 写入本地存储):
The app task info: ShuffleTaskInfo{appId='local-1791787414148_468443718-6', totalDataSize=3.14KiB, onLocalFileDataSize=3.14KiB, ... partitionCount=16, blockCount=32}
注意:MEMORY_LOCALFILE 模式下小数据量会驻留堆内 buffer,仅在 buffer 写满或应用提交时落盘;如需观察 /data/uniffle/shuffle_data/<appId>/ 目录下的实际文件,请在作业运行窗口内查看(实测窗口内可见 32 个文件共 204K),应用正常结束后数据会被清理,属预期行为。
五、配置说明
| 文件 | 作用 | 本文修改点 |
|---|---|---|
| /opt/uniffle/conf/rss-env.sh | JAVA_HOME、HADOOP_HOME、coordinator 与 shuffle-server 堆大小 | JAVA_HOME、HADOOP_HOME、XMX_SIZE=512m、SHUFFLE_SERVER_XMX_SIZE=512m |
| /opt/uniffle/conf/coordinator.conf | coordinator 端口、心跳超时、应用过期、候选节点数 | 端口 19991/19990、shuffle.nodes.max 1、删除 exclude nodes 占位行 |
| /opt/uniffle/conf/server.conf | shuffle-server 端口、存储类型与路径、buffer 容量 | 端口 19997/19996、MEMORY_LOCALFILE、quorum 指向本机 19991 |
| /opt/uniffle/conf/log4j2.xml | 各进程日志格式与级别 | 未修改 |
| Spark 侧 spark-defaults.conf | 计算引擎接入 Uniffle 的客户端参数 | shuffle.manager、quorum、storage.type、KryoSerializer |
全部参数的详细语义、默认值与调优建议见《Apache Uniffle 0.10.0 配置参数详解》。
六、注意事项
- 端口必须错开。0.10.0 发行包中 coordinator.conf 与 server.conf 的默认 RPC 端口都是 19999、HTTP 端口都是 19998,同机同时启动两个进程必然端口冲突,本文已改为 19991/19990 与 19997/19996。
- shuffle.nodes.max 决定客户端准入。它的默认值 13 表示接入端要求集群至少有 13 个可用节点,单机或小集群部署必须调小,否则 Spark 客户端会被 AccessClusterLoadChecker 拒绝(DelegationRssShuffleManager 仅在日志输出一行 WARN: Denied by AccessClusterLoadChecker 后回退到 Spark 原生 shuffle,作业照样成功,很难察觉 shuffle 实际没有走 Uniffle)。
- Hadoop 是硬依赖。只装 JDK 不装 Hadoop 发行包时,coordinator 启动即抛 NoClassDefFoundError: org/apache/hadoop/conf/Configuration;uniffle 命令行工具还会因 rss-env.sh 的 set -o nounset 在 HADOOP_HOME 未定义时报 HADOOP_HOME: unbound variable。
- 纯 LOCALFILE 与 HDFS 存储类型受 test mode 限制。0.10.0 明确不允许在非测试模式使用这两种存储类型,server 端需 rss.test.mode.enable true,Spark 客户端需 spark.rss.test.mode.enable true,两端缺一不可;常规生产建议使用 MEMORY_LOCALFILE 或 MEMORY_LOCALFILE_HDFS。
- dashboard 默认端口 19997 与 shuffle-server 常用 RPC 端口冲突,同机启动 dashboard 前需修改 conf/dashboard.conf 中的 rss.dashboard.http.port。
- 日志文件位于 /opt/uniffle/logs/,其中 .out 记录启动失败堆栈,_rpc_audit.log 记录 RPC 审计,gc-%t.log 为 GC 日志。排查启动失败优先看 .out 文件。
七、常见问题
Q1:coordinator 启动立即退出,coordinator.out 出现 NoClassDefFoundError: org/apache/hadoop/conf/Configuration。 发行包默认假设存在 Hadoop 环境,启动脚本需要 HADOOP_HOME/bin/hadoop classpath 提供依赖 jar。按 4.2 节安装 Hadoop 3.3.6 并在 rss-env.sh 设置 HADOOP_HOME=/opt/hadoop 后重启即可,不需要启动任何 HDFS 服务。
Q2:Spark 作业成功,但 coordinator 的 appTotality 一直是 0,shuffle 数据也没有产生。 大概率是客户端准入被拒后回退到原生 shuffle。查看 spark-shell 日志中的 WARN DelegationRssShuffleManager: Fail to access cluster... Denied by AccessClusterLoadChecker 行。单机部署把 coordinator.conf 的 rss.coordinator.shuffle.nodes.max 改为 1 并重启 coordinator,等待 shuffle-server 重新心跳注册后重试。
Q3:Spark 日志报 Can't use serialized shuffle ... JavaSerializer does not support object relocation。 Uniffle 序列化 shuffle 模式要求 Kryo。在 spark-defaults.conf 增加 spark.serializer org.apache.spark.serializer.KryoSerializer。
Q4:shuffle-server 启动失败,shuffle_server.out 抛 RSS storage type about LOCALFILE and HADOOP should be used in test mode。 0.10.0 禁止在非测试模式使用纯 LOCALFILE/HDFS 存储。方案一:存储类型改回 MEMORY_LOCALFILE(推荐);方案二:确要使用 LOCALFILE,在 server.conf 增加 rss.test.mode.enable true,并在 Spark 侧增加 spark.rss.test.mode.enable true。
Q5:如何确认两个进程真的运行在 512MB 堆上? 执行 jps -v | grep -E 'CoordinatorServer|ShuffleServer',输出中应包含 -Xms512m -Xmx512m;也可用 ps -ef | grep '[j]ava' 查看。若仍是 8g/80g,说明 rss-env.sh 的 XMX_SIZE 与 SHUFFLE_SERVER_XMX_SIZE 未生效或未修改。
八、卸载方法
- 停止服务(按 dashboard、shuffle-server、coordinator 顺序):
cd /opt/uniffle/bin
./stop-dashboard.sh
./stop-shuffle-server.sh
./stop-coordinator.sh
jps -l
jps 输出中不再出现 CoordinatorServer 与 ShuffleServer 即停止成功。
- 清理 Spark 集成(如按 4.9 节做过):
rm -f /opt/spark-3.5.9-bin-hadoop3/jars/rss-client-spark3-shaded-0.10.0.jar
rm -f /opt/spark-3.5.9-bin-hadoop3/conf/spark-defaults.conf
- 删除程序与数据目录:
rm -rf /opt/uniffle /opt/hadoop /data/uniffle /opt/pkg /opt/spark-3.5.9-bin-hadoop3
- 卸载 JDK(可选,如服务器另有用途可保留):
apt-get remove --purge -y openjdk-8-jdk openjdk-8-jre
apt-get autoremove -y
九、参考链接
- Apache Uniffle 官方下载页:https://uniffle.apache.org/download
- 官方文档(配置与部署):https://uniffle.apache.org/docs
- 项目源码仓库:https://github.com/apache/uniffle
- Hadoop 3.3.6 发行说明:https://hadoop.apache.org/release/3.3.6.html
- Spark 3.5.9 下载:https://downloads.apache.org/spark/spark-3.5.9/