CentOS 8 安装 Apache Uniffle 0.10.0 指南

CentOS 8 实测的 Apache Uniffle 0.10.0 安装教程:yum 装 OpenJDK 8、Hadoop classpath 依赖、双服务配置启动、Spark shuffle 验证与卸载清理全流程。

Apache UniffleApache Uniffle2026/10/12

CentOS 8 安装 Apache Uniffle 0.10.0 指南

一、版本与环境说明

本文所有命令与回显均来自在 CentOS Linux 8 服务器上的真实安装验证,账号为 root。

项目值
操作系统CentOS Linux 8(x86_64)
Apache Uniffle0.10.0(bin 发行包,gitCommitId 2df9eebe)
JDKOpenJDK 1.8.0_312(yum 包 java-1.8.0-openjdk-devel)
Hadoop3.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 统一命令行工具。

二、部署前置条件

  1. 以 root 账号登录服务器,具备 root 权限。
  2. 服务器可访问外网或已配置可用的 yum 源(实测 CentOS 8 环境 yum makecache 正常,无需额外处理 vault 源;若服务器 yum 源失效,需自行改用 vault.centos.org 镜像)。
  3. 硬件建议:内存 4GB 起(coordinator 与 shuffle-server 各限 512MB 堆,另需给系统与验证用 Spark 留余量);磁盘 20GB 起(安装包约 1GB,加上日志与 shuffle 数据)。
  4. 端口规划(本文实测端口,同机部署必须错开,详见注意事项):
    • 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 校验):

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

yum makecache
yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel curl wget
java -version

实测回显:

openjdk version "1.8.0_312"
OpenJDK Runtime Environment (build 1.8.0_312-b07)
OpenJDK 64-Bit Server VM (build 25.312-b07, mixed mode)

JDK 实际路径为 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.312.b07-2.el8_5.x86_64,同时系统提供软链接 /usr/lib/jvm/java,后续 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" >> /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

整个过程只解压 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|' 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
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

实测回显:

680 org.apache.uniffle.coordinator.CoordinatorServer
832 org.apache.uniffle.server.ShuffleServer
961 sun.tools.jps.Jps

验证 JVM 堆限制(jps -v 打印完整 JVM 参数):

jps -v | grep -E 'CoordinatorServer|ShuffleServer'

实测回显(节选关键参数):

680 org.apache.uniffle.coordinator.CoordinatorServer -Xms512m -Xmx512m ...
832 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/coordinator/info

实测回显:

{"code":0,"data":{"ACTIVE":1},"errMsg":"success"}
{"code":0,"data":{"serverIp":"172.17.0.14","coordinatorId":"172.17.0.14-19991","startTime":1791789075846,"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-1791789090480_468443718-1', totalDataSize=3.14KiB, onLocalFileDataSize=3.14KiB, ... partitionCount=16, blockCount=32}

注意:MEMORY_LOCALFILE 模式下小数据量会驻留堆内 buffer,仅在 buffer 写满或应用提交时落盘;如需观察 /data/uniffle/shuffle_data/<appId>/ 目录下的实际文件,请在作业运行窗口内查看,应用正常结束后数据会被清理,属预期行为。

五、配置说明

文件作用本文修改点
/opt/uniffle/conf/rss-env.shJAVA_HOME、HADOOP_HOME、coordinator 与 shuffle-server 堆大小JAVA_HOME、HADOOP_HOME、XMX_SIZE=512m、SHUFFLE_SERVER_XMX_SIZE=512m
/opt/uniffle/conf/coordinator.confcoordinator 端口、心跳超时、应用过期、候选节点数端口 19991/19990、shuffle.nodes.max 1、删除 exclude nodes 占位行
/opt/uniffle/conf/server.confshuffle-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 配置参数详解》。

六、注意事项

  1. 端口必须错开。0.10.0 发行包中 coordinator.conf 与 server.conf 的默认 RPC 端口都是 19999、HTTP 端口都是 19998,同机同时启动两个进程必然端口冲突,本文已改为 19991/19990 与 19997/19996。
  2. shuffle.nodes.max 决定客户端准入。它的默认值 13 表示接入端要求集群至少有 13 个可用节点,单机或小集群部署必须调小,否则 Spark 客户端会被 AccessClusterLoadChecker 拒绝(DelegationRssShuffleManager 仅在日志输出一行 WARN: Denied by AccessClusterLoadChecker 后回退到 Spark 原生 shuffle,作业照样成功,很难察觉 shuffle 实际没有走 Uniffle)。
  3. Hadoop 是硬依赖。只装 JDK 不装 Hadoop 发行包时,coordinator 启动即抛 NoClassDefFoundError: org/apache/hadoop/conf/Configuration;uniffle 命令行工具还会因 rss-env.sh 的 set -o nounset 在 HADOOP_HOME 未定义时报 HADOOP_HOME: unbound variable。
  4. 纯 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。
  5. dashboard 默认端口 19997 与 shuffle-server 常用 RPC 端口冲突,同机启动 dashboard 前需修改 conf/dashboard.conf 中的 rss.dashboard.http.port。
  6. 日志文件位于 /opt/uniffle/logs/,其中 .out 记录启动失败堆栈,_rpc_audit.log 记录 RPC 审计,gc-%t.log 为 GC 日志。排查启动失败优先看 .out 文件。
  7. CentOS 8 默认防火墙若为 firewalld 运行状态,放行 19990/19991/19996/19997 端口(firewall-cmd --permanent --add-port=19991/tcp 等)后需 firewall-cmd --reload,供外部 Spark 节点访问。

七、常见问题

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:yum 安装 JDK 时提示 mirrorlist 不可用。 CentOS 8 已停止维护,部分机器的默认 mirrorlist 会失效。实测环境 yum 源正常;如遇该问题,将 /etc/yum.repos.d/CentOS-*.repo 的 baseurl 改为 vault.centos.org 对应地址(把 releasever 替换为 8.5.2111)后重新 yum makecache。

Q3: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 重新心跳注册后重试。

Q4: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。

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 未生效或未修改。

八、卸载方法

  1. 停止服务(按 dashboard、shuffle-server、coordinator 顺序):
cd /opt/uniffle/bin
./stop-dashboard.sh
./stop-shuffle-server.sh
./stop-coordinator.sh
jps -l

jps 输出中不再出现 CoordinatorServer 与 ShuffleServer 即停止成功。

  1. 清理 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
  1. 删除程序与数据目录:
rm -rf /opt/uniffle /opt/hadoop /data/uniffle /opt/pkg /opt/spark-3.5.9-bin-hadoop3
  1. 卸载 JDK(可选,如服务器另有用途可保留):
yum remove -y java-1.8.0-openjdk java-1.8.0-openjdk-devel

九、参考链接