> For the complete documentation index, see [llms.txt](https://documentation.alluxio.io/ee-ai-cn/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://documentation.alluxio.io/ee-ai-cn/administration/managing-worker.md).

# Worker 配置

本指南涵盖 Alluxio 单个 Worker 的配置：存储后端、容量规划、资源限制、JVM 调优和网络绑定。关于哈希环相关的 Worker 操作（添加、移除、重启、身份持久化），请参阅 [哈希环与 Worker 生命周期](/ee-ai-cn/administration/managing-ring.md)。关于集群级别的操作（扩展、升级、Coordinator、UFS、多租户），请参阅 [集群管理](/ee-ai-cn/administration/managing-alluxio.md)。

## 1. Worker 存储

每个 Worker 将缓存数据保存在本地的 [page store](https://documentation.alluxio.io/ee-ai-cn/administration/pages/uw7Vlrzw6022oCfnpoka#id-5.-worker-cun-chu-page-store) 中。本节介绍存储后端选型、容量规划和磁盘布局。

### 配置 Page Store 位置

{% tabs %}
{% tab title="Kubernetes (Operator)" %}
Operator 支持两种 page store 后端。

**默认（hostPath）：** Worker 将缓存写入节点文件系统的 `/mnt/alluxio/pagestore`。

```yaml
spec:
  worker:
    pagestore:
      # 默认 hostPath: /mnt/alluxio/pagestore，指向节点的本地文件系统
      size: 100Gi
      reservedSize: 10Gi
```

**PVC 方式：** 若需 Worker 缓存跨 pod 重启或重调度后仍然保留，为 page store 指定一个 PersistentVolumeClaim (PVC)。

```yaml
spec:
  worker:
    pagestore:
      type: persistentVolumeClaim
      storageClass: ""    # 默认为 "standard"；空字符串表示静态绑定
      size: 100Gi
      reservedSize: 10Gi
```

{% endtab %}

{% tab title="Docker / Bare-Metal" %}
通过 Alluxio 属性设置 page store 目录和大小。Docker 部署通过 `ALLUXIO_JAVA_OPTS` 传入，并把宿主机目录作为 volume 挂载，使缓存在容器重建后仍然保留：

```shell
docker run ... \
  -v /data/alluxio-cache:/data/alluxio-cache \
  -e ALLUXIO_JAVA_OPTS=" \
    -Dalluxio.worker.page.store.dirs=/data/alluxio-cache \
    -Dalluxio.worker.page.store.sizes=<CACHE_SIZE>" \
  alluxio/alluxio-enterprise worker
```

裸机部署在 `conf/alluxio-site.properties` 里设置同样的属性：

```properties
alluxio.worker.page.store.dirs=/data/alluxio-cache
alluxio.worker.page.store.sizes=<CACHE_SIZE>
```

{% endtab %}
{% endtabs %}

### Page Store 容量规划

* `size`：单个 Worker 的缓存容量。不得超过 Worker 节点上的可用磁盘。
* `reservedSize`：为内部操作预留的空间（临时 page 写入、元数据缓存）。设为 `size` 的 10% 左右，通常 10–100 GiB。
* 确保 `size + reservedSize ≤ 可用磁盘空间`。

云厂商宣传的磁盘大小是 GB（十进制），而 Kubernetes 的 `Gi` 是二进制 GiB。标称 "1000 GB" 的 EBS 卷实际可用约 931 GiB。将 `size` 设为实际可用空间（`df -h <page-store-path>` 查看）的 \~90%，为文件系统开销和 `reservedSize` 留出余量。`size` 过大会导致 Worker 启动失败：`quota (NNN) exceeds the total disk space`。

### 多盘配置

对于有多块数据盘的节点，将 page store 配置为跨所有磁盘——这样可以将 page I/O 分摊到多块盘，提升总吞吐。使用逗号分隔的路径和大小：

```yaml
spec:
  worker:
    pagestore:
      hostPath: /mnt/disk1/alluxio/pagestore,/mnt/disk2/alluxio/pagestore
      size: 800Gi,800Gi
      reservedSize: 100Gi
```

每个目录必须对应一块独立的物理盘——多个 page store 目录位于同一块盘上不会带来收益。

另一种方式是在操作系统层用 RAID 0 将多块盘组成一个逻辑卷，然后只配置单个 `hostPath`。这种方式 Alluxio 配置更简单，但绑定了所有磁盘的生命周期——任意一块盘坏掉整个阵列都会丢失。

### 异构 Worker

本节所述的 `workerGroups` 机制仅适用于 Kubernetes Operator。在 Docker 或裸机部署中，异构 Worker 通过为每个 Worker 单独配置 `alluxio-site.properties`（指定该节点的 page store 路径和大小）实现。

当集群中的 Worker 磁盘规格不同（例如一组有单块 1 TB 盘，另一组有两块 800 GB 盘），使用 `workerGroups` 为每组定义不同的配置。

**步骤 1：分组并标记节点：**

```shell
# 标记单盘节点
kubectl label nodes <node-name> apps.alluxio.com/disks=1
# 标记双盘节点
kubectl label nodes <node-name> apps.alluxio.com/disks=2
```

**步骤 2：定义 worker groups 并启用容量感知哈希环。**

对于异构集群，应同时将 `alluxio.user.worker.selection.policy.consistent.hash.provider.impl` 设置为 `CAPACITY`，这样存储容量更大的 Worker 会分到相应更大比例的数据。关于该属性的详细说明，参见 [针对异构 Worker 进行优化](/ee-ai-cn/administration/managing-ring.md#zhen-dui-yi-gou-worker-jin-xing-you-hua)。

```yaml
apiVersion: k8s-operator.alluxio.com/v1
kind: AlluxioCluster
spec:
  properties:
    alluxio.user.worker.selection.policy.consistent.hash.provider.impl: CAPACITY

  # 所有 worker 的通用配置
  worker:
    resources:
      limits:
        memory: 40Gi
      requests:
        memory: 36Gi
    jvmOptions: ["-Xmx20g", "-Xms20g", "-XX:MaxDirectMemorySize=16g"]

  # 为每组 worker 定义独立配置
  workerGroups:
  - worker:
      count: 10
      nodeSelector:
        apps.alluxio.com/disks: 1
      pagestore:
        hostPath: /mnt/disk1/alluxio/pagestore
        size: 1Ti
        reservedSize: 100Gi
  - worker:
      count: 12
      nodeSelector:
        apps.alluxio.com/disks: 2
      pagestore:
        hostPath: /mnt/disk1/alluxio/pagestore,/mnt/disk2/alluxio/pagestore
        size: 800Gi,800Gi
        reservedSize: 100Gi
```

{% hint style="info" %}
虽然这提供了灵活性，但确保每个 worker group 内部配置一致至关重要。配置错误可能导致意料之外的错误。
{% endhint %}

## 2. 资源与 JVM 调优

{% tabs %}
{% tab title="Kubernetes (Operator)" %}
在 `alluxio-cluster.yaml` 中按组件配置资源限制和 JVM 选项：

```yaml
apiVersion: k8s-operator.alluxio.com/v1
kind: AlluxioCluster
spec:
  worker:
    count: 2
    resources:
      # 生产环境 Worker 建议将 requests 设为与 limits 相同，使 Pod 进入
      # Guaranteed QoS 级别，在节点资源紧张时被驱逐的优先级最低。
      limits:
        cpu: "12"
        memory: "36Gi"
      requests:
        cpu: "12"
        memory: "36Gi"
    jvmOptions:
      - "-Xmx22g"
      - "-Xms22g"
      - "-XX:MaxDirectMemorySize=10g"
  coordinator:
    resources:
      # Coordinator 也建议进入 Guaranteed QoS 级别——将 requests 设为与 limits 相同。
      limits:
        cpu: "12"
        memory: "36Gi"
      requests:
        cpu: "12"
        memory: "36Gi"
    jvmOptions:
      - "-Xmx4g"
      - "-Xms1g"
```

{% endtab %}

{% tab title="Docker / Bare-Metal" %}
Docker 部署通过 `ALLUXIO_JAVA_OPTS` 设置 JVM 选项，通过 `--memory` 和 `--cpus` 设置容器资源上限：

```shell
docker run ... \
  --memory=36g \
  --cpus=12 \
  -e ALLUXIO_JAVA_OPTS=" \
    -Xmx22g -Xms22g -XX:MaxDirectMemorySize=10g" \
  alluxio/alluxio-enterprise worker
```

裸机部署在 `conf/alluxio-env.sh` 中设置 JVM 选项：

```shell
ALLUXIO_WORKER_JAVA_OPTS+=" -Xmx22g -Xms22g -XX:MaxDirectMemorySize=10g"
ALLUXIO_COORDINATOR_JAVA_OPTS+=" -Xmx4g -Xms1g"
```

{% endtab %}
{% endtabs %}

### 内存限制公式

```
memory limit ≥ -Xmx + -XX:MaxDirectMemorySize + 2–4 GiB (JVM 开销)
```

上面 worker 示例（`-Xmx22g`、`-XX:MaxDirectMemorySize=10g`）：最小内存为 22 + 10 + 2 = 34 GiB，示例中设为 36 GiB。

{% hint style="info" %}
若省略 `-XX:MaxDirectMemorySize`，JVM 默认将其设为与 `-Xmx` 相同的值，因此容器内存限制通常需要 2.5 倍 `-Xmx` 或更多。
{% endhint %}

### 诊断 OOM

若 Worker 被 OOM 杀死（退出码 137），使用下列命令确认原因。

{% tabs %}
{% tab title="Kubernetes (Operator)" %}

```shell
# 查看 pod 事件
kubectl describe pod <worker-pod-name> -n alx-ns
# 查找 "OOMKilled" 或 "Exit Code: 137"

# 查看前一次容器崩溃前的日志
kubectl logs <worker-pod-name> -n alx-ns --previous | tail -50
# 查找 "OutOfMemoryError" 或 "java.lang.OutOfMemoryError"
```

{% endtab %}

{% tab title="Docker / Bare-Metal" %}

```shell
# Docker：查看已退出容器的状态
docker inspect <container-id> --format='{{.State.OOMKilled}} {{.State.ExitCode}}'
# "true 137" 表示被 OOM 杀掉

# 查看 worker 日志中的 OutOfMemoryError
tail -100 /opt/alluxio/logs/worker.log | grep -i OutOfMemoryError
```

{% endtab %}
{% endtabs %}

| 症状                                                 | 根因                              | 修复                                       |
| -------------------------------------------------- | ------------------------------- | ---------------------------------------- |
| `Exit Code 137`，无 Java 报错                          | 容器超过内存限制——被 Linux OOM killer 杀掉 | 增大 `resources.limits.memory`             |
| `java.lang.OutOfMemoryError: Java heap space`      | `-Xmx` 偏小                       | 增大 `-Xmx` 并相应提高容器内存上限                    |
| `java.lang.OutOfMemoryError: Direct buffer memory` | `-XX:MaxDirectMemorySize` 偏小    | 增大 `-XX:MaxDirectMemorySize` 并相应提高容器内存上限 |

### 诊断卡顿

若其他节点记录到某个 worker 的 redirect 或连接超时、读请求回退到 UFS，而该 worker Pod 一直 `READY`，很可能是 worker JVM 每次停顿数秒：要么在做垃圾回收（GC），要么停在 safepoint（JVM 为执行某些内部操作而暂停所有 Java 线程的位置）。在调整网络之前先确认这一点：节点上 TCP 监听队列丢包增多是停顿的结果，而不是原因。

**1. 确认停顿。** Worker 会把每次超过 1 秒的停顿记录为 `JVM paused <N>ms`（超过 10 秒时为 WARN 级别）。下一行说明停顿期间是否发生了 GC：

```shell
# Kubernetes
kubectl logs <worker-pod-name> -n alx-ns | grep -A1 "JVM paused"
# Docker / bare-metal
grep -A1 "JVM paused" /opt/alluxio/logs/worker.log
```

`GC list:` 表示停顿期间发生了 GC；`No GCs detected` 表示 JVM 因其他原因停顿。单看 GC 指标无法区分这两种情况，因为 GC 指标不统计非 GC 的停顿。

**2. 收集 GC 和 safepoint 日志**，持续几个小时：采集时间太短可能会指向错误的原因。在 worker JVM 选项中加入该参数，下次重启后生效：

{% tabs %}
{% tab title="Kubernetes (Operator)" %}

```yaml
spec:
  worker:
    jvmOptions:
      # jvmOptions 会替换默认列表：保留已有的堆内存、直接内存等参数
      - "-Xlog:gc*,safepoint:file=/opt/alluxio/logs/gc.log:time,uptime:filecount=5,filesize=50M"
```

{% endtab %}

{% tab title="Docker / Bare-Metal" %}

```shell
# conf/alluxio-env.sh；Docker 上把该参数追加到 ALLUXIO_JAVA_OPTS
ALLUXIO_WORKER_JAVA_OPTS+=" -Xlog:gc*,safepoint:file=/opt/alluxio/logs/gc.log:time,uptime:filecount=5,filesize=50M"
```

{% endtab %}
{% endtabs %}

也可以在运行中的 worker 上直接打开同样的日志，无需重启。该设置在 worker 重启后失效。

```shell
# Kubernetes：进入 worker 容器
kubectl exec -it <worker-pod-name> -n alx-ns -- bash
# 找到 worker JVM 的进程号：以 alluxio.worker.AlluxioWorker 结尾的那一行
jcmd -l
jcmd <pid> VM.log output="file=/opt/alluxio/logs/gc.log" output_options="filecount=5,filesize=50M" what="gc*,safepoint" decorators="time,uptime"
```

在 Kubernetes 上，几个小时后用 `kubectl cp alx-ns/<worker-pod-name>:/opt/alluxio/logs/gc.log gc.log` 把日志拷出来。

**3. 根据日志找到原因。** 每次 GC 是一组 `GC(<n>)` 编号相同的行：停顿及其总耗时、各阶段耗时、线程消耗的 CPU 时间。每个 safepoint 是一行 `Safepoint`，时间单位为纳秒。卡顿时的日志类似：

```
GC(189) Pause Young (Normal) (G1 Evacuation Pause) 21G->13G(36G) 7040.519ms
GC(189)   Pre Evacuate Collection Set: 6998.1ms
GC(189)   Evacuate Collection Set: 36.2ms
GC(189) User=0.67s Sys=0.01s Real=7.04s
Safepoint "Cleanup", Time since last: 1000120313 ns, Reaching safepoint: 4812339871 ns, At safepoint: 25163042 ns, Total: 4837502913 ns
```

这里一次 7 秒的 young GC 几乎全部时间都花在 `Pre Evacuate Collection Set`，一次 `Cleanup` safepoint 用了 4.8 秒才到达。先看与第 1 步结果对应的行。

| 第 1 步显示                       | GC 和 safepoint 日志中的症状                                                                            | 根因                                                                  | 修复                                             |
| ----------------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------- | ---------------------------------------------- |
| `GC list`                     | 出现 `Pause Full` 或 `To-space exhausted`，或 `Pause Young` 很长且大部分时间在 `Evacuate Collection Set`       | 堆内存装不下存活数据                                                          | 增大 `-Xmx` 并相应提高容器内存上限                          |
| `GC list`                     | GC 停顿很长，但其中 `User` CPU 时间远小于 `Real`                                                              | 容器的 CPU 上限让 GC 线程拿不到 CPU（cgroup 的 `cpu.stat` 中 `nr_throttled` 持续增长） | 提高 CPU 上限                                      |
| `GC list` 或 `No GCs detected` | `Pause Young` 很长且大部分时间在 `Pre Evacuate Collection Set`，或 `Safepoint` 行的 `Reaching safepoint` 达到秒级 | 写 JVM mmap 文件 `/tmp/hsperfdata_<user>/<pid>` 的线程卡在容器的脏页上限上          | 在 worker JVM 选项中加入 `-XX:+PerfDisableSharedMem` |
| `No GCs detected`             | 每次抓取指标都出现数秒的 `Safepoint "FindDeadlocks"` 行                                                       | 设置了 `alluxio.metrics.jvm.deadlock.detection.enabled=true`           | 保持该属性的默认值 `false`                              |

对于 hsperfdata 这种情况，脏页上限即节点的 `vm.dirty_bytes` 或 `vm.dirty_ratio`，按各容器的 memory cgroup 等比缩小；设成绝对值的 `vm.dirty_bytes` 可能只给容器留下几 MB。要确认，查看 worker cgroup 的 `memory.stat` 中 `file_dirty` 是否一直贴近这个上限。

{% hint style="info" %}
设置 `-XX:+PerfDisableSharedMem` 后，`jps`、`jstat` 和 `jcmd -l` 将不再列出 worker JVM，但 `jcmd <pid>` 仍然可用。
{% endhint %}

## 3. Worker 网络配置

### 将 Worker 绑定到指定网卡

将 Worker 绑定到指定的本地网卡（假设网卡名为 `NIC1`），需要分别为各服务设置 bind device：

```properties
alluxio.worker.rpc.bind.device=NIC1
alluxio.worker.web.bind.device=NIC1
alluxio.worker.data.bind.device=NIC1
```
