> 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-job-service.md).

# Job Service

如果您已经使用过 `job load` 或 `job free`，就已经在与 Job Service 交互了——它是驱动这些操作的分布式调度引擎。本文档介绍其内部工作原理、如何监控进行中的作业，以及如何为高可用和生产规模进行配置。

各操作的具体命令，请参阅：

* [`job load`](/ee-ai-cn/cache/loading-data-into-the-cache.md) — 将数据预加载到缓存
* [`job free`](/ee-ai-cn/cache/removing-data-from-the-cache.md) — 释放已缓存的数据

## 1. 架构

**作业（Job）** 是提交给 Alluxio 的一个有名称、可持久化的分布式操作——例如将数据集加载到缓存，或在所有 Worker 上释放空间。每个作业遵循同样的生命周期：

**WAITING** → **RUNNING** → **SUCCEEDED** / **FAILED** / **STOPPED**

作业提交后先进入等待队列并写入 Job Store，然后才会被调度。该状态能否在 Coordinator 失联时幸存，取决于 Job Store 后端类型——详见[第 3 节](#3-故障恢复)。调度器随后认领作业、将其拆分为各 Worker 的任务并跟踪完成情况。完整的状态说明见[第 2 节](#2-列出并监控作业)。

Job Service 由三个组件驱动这一生命周期：

* **Coordinator** — 无状态调度器，负责轮询作业队列、原子地认领作业、将其拆分为文件批次任务，并将任务分发给可用的 Worker。多个 Coordinator 可同时运行；任意实例都可以处理任意作业。
* **Job Store** — 作业状态的持久化存储。默认为 Coordinator 节点上的本地 RocksDB 实例；HA 模式下所有 Coordinator 共享同一个 etcd 集群。
* **Workers** — 执行 Coordinator 分发的任务：从 UFS 读取数据写入本地缓存（`load`），或驱逐已缓存的数据块（`free`）。

{% hint style="warning" %}
Coordinator **不同于**开源版 Alluxio 中的 Master 组件。Alluxio 企业版已用 Coordinator 取代了 Master——Coordinator 是一个专为无状态设计的调度器，企业版中不再有 Master 组件。详见[关键组件](https://documentation.alluxio.io/ee-ai-cn/administration/pages/uw7Vlrzw6022oCfnpoka#关键组件)。
{% endhint %}

## 2. 列出并监控作业

### 作业标识

作业的默认寻址方式是 **(type, path)** 二元组——CLI 全程使用此方式（`--path`、`--type`）。此外，每个作业在内部还有一个 UUID（可在 `job list` 输出中查看），部分 REST 接口直接接受该 UUID。

### 列出作业

查看集群中所有作业：

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

```shell
kubectl exec -n <NAMESPACE> alluxio-cluster-coordinator-0 -- \
  alluxio job list --job-type ALL --job-state ALL
```

{% endtab %}

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

```shell
bin/alluxio job list --job-type ALL --job-state ALL
```

{% endtab %}
{% endtabs %}

使用 `--job-state` 按状态筛选，使用 `--job-type` 按类型筛选（`LOAD`、`FREE`、`COPY`、`MOVE`）。HA 模式下，`--coordinator <address>` 仅列出指定 Coordinator 所属的作业。输出中每条记录包含作业的 `(type, path)`——使用这两个值即可查询进度或停止作业。

### 查询指定作业

从 `job list` 获取 `(type, path)` 后，可用于查询进度或控制该作业：

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

```shell
# 查询进度（load 作业）
kubectl exec -n <NAMESPACE> alluxio-cluster-coordinator-0 -- \
  alluxio job load --path <path> --progress

# 停止运行中的作业
kubectl exec -n <NAMESPACE> alluxio-cluster-coordinator-0 -- \
  alluxio job load --path <path> --stop
```

{% endtab %}

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

```shell
# 查询进度（load 作业）
bin/alluxio job load --path <path> --progress

# 停止运行中的作业
bin/alluxio job load --path <path> --stop
```

{% endtab %}
{% endtabs %}

其他类型的作业遵循同样的模式：例如 `alluxio job free --path <path> --progress` 等。

### 作业状态

| 状态            | 说明                                                 |
| ------------- | -------------------------------------------------- |
| **WAITING**   | 已进入 Job Store 队列，尚未被 Coordinator 认领。               |
| **RUNNING**   | Coordinator 正在向 Worker 分发任务，可通过 `--progress` 监控。   |
| **VERIFYING** | 所有任务已完成，Coordinator 正在执行验证（需指定 `--verify`）。        |
| **SUCCEEDED** | 所有任务成功完成。                                          |
| **FAILED**    | 超出错误阈值。使用 `--progress --file-status FAILURE` 查看详情。 |
| **STOPPED**   | 已通过 `--stop` 手动停止。                                 |

状态转换是原子的且最多执行一次，即使多个 Coordinator 同时活动也能保证一致性。

## 3. 故障恢复

故障恢复行为取决于 Job Store 后端类型：

* **RocksDB（单 Coordinator，默认）：** 作业状态写入 Coordinator 本地文件系统的 RocksDB。若 RocksDB 目录位于持久化存储（例如 Kubernetes 上的 PVC——参阅 [生产部署配置](https://documentation.alluxio.io/ee-ai-cn/administration/pages/cuG1KYD7QZM6zV5EoHQ1#id-1.-sheng-chan-bu-shu-pei-zhi)），则进程崩溃和 Pod 挂载相同存储卷重启后状态均可保留。若 Coordinator 节点永久丢失，或 metastore 使用非持久化存储，则队列和进行中的作业状态会随之丢失。
* **etcd（HA 模式）：** 作业状态存储在 etcd 中，独立于任何单个 Coordinator。即使某个 Coordinator 永久下线，其他实例仍可从共享队列继续处理作业。

### 自动恢复（HA 模式）

HA 模式下，崩溃 Coordinator 正在管理的作业会由其他实例自动恢复：

* **检测：** 活动的 Coordinator 检测到处于 **RUNNING** 状态的"陈旧"作业——这些作业所属的实例已不再发送心跳。
* **重新排队：** 这些孤立作业被恢复为 **WAITING** 状态，以便另一个健康的 Coordinator 接管。

单 Coordinator 模式（RocksDB）下没有其他实例执行检测——恢复发生在 Coordinator 进程自身重启并重新读取本地 RocksDB 时。

### Worker 故障

Worker 重启时，其线程池中正在执行的任务会全部丢失。Coordinator 检测到任务失联后，会对失败的任务进行重试。若重试次数耗尽，该任务被标记为失败，当失败数量超出容忍阈值时，整个作业将转换为 **FAILED**。

### 手动恢复（`job rerun`）

{% hint style="warning" %}
`job rerun` 需要 **etcd HA 模式**（`alluxio.coordinator.job.meta.store.type=ETCD`）。在单 Coordinator RocksDB 模式下执行会报 `UnavailableException: Job ETCD is not enabled`。RocksDB 部署下，Coordinator 进程重启后会自动从本地 RocksDB 恢复作业。
{% endhint %}

在由于复杂故障（例如网络分区或集群整体重启）导致作业卡住的情况下，管理员可以手动将其重新入队：

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

```shell
# 重新运行可能卡住的特定 load 作业
kubectl exec -n <NAMESPACE> alluxio-cluster-coordinator-0 -- \
  alluxio job rerun --path /data/my-dataset --type load

# 重新运行分配给特定（已失败）Coordinator 的所有作业
kubectl exec -n <NAMESPACE> alluxio-cluster-coordinator-0 -- \
  alluxio job rerun --coordinator <failed_coordinator_host>
```

{% endtab %}

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

```shell
# 重新运行可能卡住的特定 load 作业
bin/alluxio job rerun --path /data/my-dataset --type load

# 重新运行分配给特定（已失败）Coordinator 的所有作业
bin/alluxio job rerun --coordinator <failed_coordinator_host>
```

{% endtab %}
{% endtabs %}

## 4. 高可用

尽管 Coordinator 不在 I/O 关键路径上，使用本地 RocksDB 的单节点 Coordinator 仍可能成为单点故障。例如，在 Coordinator 节点进行硬件更换或软件升级期间，`load`、`free` 等作业无法提交或推进，直到节点恢复上线。

要消除这一风险，可以部署多个 Coordinator 实例。多个调度器共享同一个作业队列时，需要一个分布式状态存储——这就是引入 **etcd** 的原因。所有 Coordinator 指向同一个 etcd 集群，任意实例都可以从共享队列中获取并处理作业。

* **无状态 Coordinator：** 由于 Coordinator 不持有本地状态，任意实例都可以处理任意作业——调度功能本身没有"Leader"选举。
* **容错性：** 某个 Coordinator 故障后，其他实例无中断地继续处理共享队列。
* **故障转移：** 故障 Coordinator 的进行中作业会被其余实例检测为"陈旧"并在数秒内重新入队。
* **负载均衡：** 所有 Coordinator 从同一个全局共享队列消费——任务自然分布到各实例。轮询间隔包含随机抖动，防止惊群式突发。

### 配置 HA

核心要求是在所有 Coordinator 节点上设置 `alluxio.coordinator.job.meta.store.type=ETCD`，将作业状态存储从本地 RocksDB 切换到共享集群。

{% tabs %}
{% tab title="Kubernetes (Operator)" %}
设置 `coordinator.count` 以部署多副本 Coordinator。Operator 自动管理 etcd。

```yaml
spec:
  coordinator:
    count: 3
  properties:
    alluxio.coordinator.job.meta.store.type: "ETCD"
```

```shell
kubectl apply -f alluxio-cluster.yaml
```

{% endtab %}

{% tab title="Docker / Bare-Metal" %}
在**每个** Coordinator 节点的 `alluxio-site.properties` 中添加以下配置，然后启动各 Coordinator 进程：

```properties
alluxio.coordinator.job.meta.store.type=ETCD
```

```shell
bin/alluxio process start coordinator
```

{% endtab %}
{% endtabs %}

#### 可选：为作业调度使用独立 etcd 集群

默认情况下，Coordinator 把作业元数据存储在主 Alluxio etcd 集群（`alluxio.etcd.endpoints`）中。如果作业提交流量较大，可以把作业元数据引流到**独立的** etcd 集群，与服务发现流量隔离：

```properties
# 未设置时默认为 alluxio.etcd.endpoints
alluxio.coordinator.scheduler.load.job.etcd.endpoints=http://job-etcd1:2379,http://job-etcd2:2379
```

该配置对 Kubernetes 和 Docker / Bare-Metal 两种部署都适用。Kubernetes 部署请把该属性放在 AlluxioCluster CR 的 `spec.properties` 下；Docker / Bare-Metal 部署请把该属性加入每个 Coordinator 节点的 `alluxio-site.properties`。

### 验证 HA 是否生效

Coordinator 启动完成后，确认它们真的在共享 etcd 作业队列。

**1. 所有 Coordinator 副本处于运行状态。**

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

```shell
kubectl -n <NAMESPACE> get pods -l app.kubernetes.io/component=coordinator
```

预期：`coordinator.count` 个 Pod 全部 `Running`，`READY 1/1`。
{% endtab %}

{% tab title="Docker / Bare-Metal" %}
在每台 Coordinator 主机上：

```shell
docker ps --filter name=alluxio-coordinator
```

预期：每台主机上容器都是 `Up` 状态。
{% endtab %}
{% endtabs %}

**2. Coordinator 共享同一个作业队列。** 从一个 Coordinator 提交作业，从另一个 Coordinator 查询——HA 模式下两者都会从同一个 etcd 队列返回结果。

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

```shell
# 在 coordinator-0 上提交
kubectl exec -n <NAMESPACE> alluxio-cluster-coordinator-0 -- \
  alluxio job load --path /<mount>/<path> --submit

# 在 coordinator-1 上查询
kubectl exec -n <NAMESPACE> alluxio-cluster-coordinator-1 -- \
  alluxio job load --path /<mount>/<path> --progress
```

{% endtab %}

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

```shell
# 在 coordinator-1 主机上
bin/alluxio job load --path /<mount>/<path> --submit

# 在 coordinator-2 主机上
bin/alluxio job load --path /<mount>/<path> --progress
```

{% endtab %}
{% endtabs %}

预期：两条命令返回相同的作业状态。单 Coordinator（RocksDB）模式下，第二条查询会报作业不存在。

**3. 故障切换测试**（可选）。停掉当前正在驱动长作业的 Coordinator；其他 Coordinator 会在 `alluxio.coordinator.failure.detection.timeout`（默认 15 秒）内接管。从存活的 Coordinator 再次 `alluxio job load --path ... --progress`，确认作业越过故障点继续推进、最终到达 `SUCCEEDED`。

## 5. 配置和调优

您可以根据特定的工作负载和 etcd 容量微调 Job Service 的行为。

| 属性                                                     | 默认值              | 描述                                                                               |
| ------------------------------------------------------ | ---------------- | -------------------------------------------------------------------------------- |
| `alluxio.coordinator.failure.detection.timeout`        | `15s`            | 判定 Coordinator 静默失联并由对等节点回收其作业的超时时间。                                             |
| `alluxio.coordinator.scheduler.etcd.max.retries`       | `2`              | etcd 操作放弃前的最大重试次数。                                                               |
| `alluxio.coordinator.scheduler.etcd.read.timeout`      | `10s`            | 从 etcd 读取的超时时间。                                                                  |
| `alluxio.coordinator.scheduler.etcd.write.timeout`     | `15s`            | 写入 etcd 的超时时间。                                                                   |
| `alluxio.coordinator.scheduler.interval.time`          | `2s`             | 调度间隔。较短的间隔可以更快地调度小型作业，但会增加 CPU 开销。                                               |
| `alluxio.coordinator.scheduler.job.etcd.path`          | `/alluxio/jobs/` | etcd 中用于存储作业元数据的前缀目录。                                                            |
| `alluxio.coordinator.scheduler.job.etcd.poll.interval` | `1s`             | Coordinator 检查新等待作业的频率。较低的值响应更快，但 etcd 负载更高。                                     |
| `alluxio.coordinator.scheduler.max.tasks.per.worker`   | `3`              | 每个 Coordinator 能够在同一个 Worker 上同时调度的最大任务数。增大该值可提高并发，但可能导致 Worker 任务积压。            |
| `alluxio.coordinator.scheduler.running.job.capacity`   | `100`            | 调度器可同时运行的最大作业数。超出此限制的作业将保留在等待队列中。                                                |
| `alluxio.coordinator.scheduler.waiting.job.capacity`   | `300000`         | 调度器等待队列的最大容量。超出此限制的提交请求将被拒绝。                                                     |
| `alluxio.job.batch.size`                               | `200`            | 每次分发给 Worker 的文件批次大小。较大的值可提高 Worker 并发性，但可能超出线程池限制。可通过 CLI（`--batch-size`）按作业覆盖。 |
| `alluxio.job.cleanup.interval`                         | `1H`             | 周期性清理作业存储中已完成作业的时间间隔。                                                            |
| `alluxio.job.retention.time`                           | `7d`             | 作业历史记录保留时间。                                                                      |
| `alluxio.worker.job.load.executor.threads.max`         | `2048`           | Worker 作业执行线程池中用于并行 UFS 数据加载的最大线程数。                                              |
| `alluxio.worker.load.file.partition.size`              | `256MiB`         | 用于在加载过程中分割大型文件的分片大小。较小的分片可以提高并发性，但可能会增加开销。                                       |

### 小文件加载优化

加载包含大量小文件（每个 < 1 MB）的数据集时，默认 batch size 200 往往使 Worker 线程处于空闲状态——每个任务完成太快，Coordinator 必须在 Worker 线程池充分饱和之前分发下一个批次。

增大 batch size 让 Worker 持续保持忙碌：

```properties
# 适用于小文件数据集——从默认 200 增大（在 alluxio-site.properties 中设置）
alluxio.job.batch.size=2000
```

或在不重启集群的情况下按作业覆盖：

```shell
bin/alluxio job load --path s3://bucket/small-files/ --submit --batch-size 2000
```

实际上，小文件加载的吞吐量通常受限于 **S3 请求速率（IOPS）** 而非 Alluxio 内部并发。一旦到达 S3 IOPS 上限，继续增大 `alluxio.worker.job.load.executor.threads.max`（默认 2048）或增加 Worker 数量都不会提升吞吐量——瓶颈已转移至对象存储端。

对于大文件（> 100 MB），保持 batch size 在 200 或更低。大文件在内部已按 `alluxio.worker.load.file.partition.size`（256 MiB）拆分为分片，每个任务会生成多个并发子任务——过大的 batch size 会对 Worker 造成过度内存压力。

## 6. 指标

{% hint style="info" %}
这些指标是内部调度器操作的低级指标。关于集群的一般健康状况和作业进度，请参考默认的 Grafana 仪表板。
{% endhint %}

| 指标                                  | 描述                                              |
| ----------------------------------- | ----------------------------------------------- |
| `alluxio_scheduler_etcd_poll`       | etcd 轮询操作的计数器。                                  |
| `alluxio_scheduler_etcd_claim`      | 从队列中成功认领的作业计数器。                                 |
| `alluxio_scheduler_etcd_reclaim`    | 从失败的 Coordinator 中回收/恢复的作业计数器。                  |
| `alluxio_scheduler_etcd_latency_ms` | 调度器执行的 etcd 操作的延迟分布。                            |
| `alluxio_scheduler_job_access_etcd` | 对 etcd 的各种作业相关访问类型（list, get, transaction）的计数器。 |

## 另请参阅

* [缓存加载](/ee-ai-cn/cache/loading-data-into-the-cache.md) — 作业提交、监控以及 free 操作
* [Kubernetes 安装](/ee-ai-cn/start/installing-on-kubernetes.md) — ETCD 配置与多副本 Coordinator 部署
* [集群管理](/ee-ai-cn/administration/managing-alluxio.md) — 资源调优、节点绑定、持久化元数据存储
* [监控](/ee-ai-cn/administration/monitoring-alluxio.md) — Grafana 仪表盘、告警规则、指标参考
