# 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 仪表盘、告警规则、指标参考


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://documentation.alluxio.io/ee-ai-cn/administration/managing-job-service.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
