# FUSE 写入优化

{% hint style="warning" %}
此功能自 AI-3.8.15.1.4 起为实验性功能。
{% endhint %}

本指南介绍如何通过 FUSE POSIX 接口使用[写缓存](/ee-ai-cn/ai-3.8-15.1.x-cn/performance/s3-write-cache.md)后端，通过标准文件系统调用（`write()`、`open()`、`close()`）实现低延迟写入。在阅读本指南前，请确保写缓存已完成部署。

## 与 S3-API 写缓存的关系

写缓存后端（FoundationDB 元数据 + NVMe 数据 + 异步 UFS 持久化）由两种访问接口**共享**：

|                  | [S3-API 写入优化](/ee-ai-cn/ai-3.8-15.1.x-cn/performance/s3-write-cache.md) | FUSE 写入优化（本指南）                                                          |
| ---------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| **接口**           | S3 兼容 API（`PUT`、`GET`）                                                  | POSIX 文件系统调用（`write`、`read`）                                            |
| **客户端**          | AWS CLI、boto3、s3fs、任意 S3 客户端                                            | 任意 POSIX 应用、ML 框架、Shell 工具                                              |
| **写入策略**         | `WRITE_THROUGH`、`WRITE_BACK`、`TRANSIENT`                                | 相同                                                                      |
| **FoundationDB** | 必需                                                                      | 必需（同一 FDB 集群）                                                           |
| **额外限制**         | 无（仅 S3 语义限制）                                                            | 参见[写缓存模式下的 POSIX 兼容性](#xie-huan-cun-mo-shi-xia-de-posix-jian-rong-xing) |

## 开始之前

* [ ] **写缓存已部署** — FDB 须处于运行状态，且 `alluxio.write.cache.enabled: "true"`。验证：

  ```shell
  kubectl exec -n <NAMESPACE> <CLUSTER_NAME>-coordinator-0 -- \
    alluxio conf get alluxio.write.cache.enabled
  ```

  预期输出：`true`。若非如此，请先完成 [S3-API 写入优化](/ee-ai-cn/ai-3.8-15.1.x-cn/performance/s3-write-cache.md)的部署。
* [ ] **FDB Pod 运行正常**：

  ```shell
  kubectl get pods -n <NAMESPACE> | grep fdb
  ```

  预期输出：FDB controller、log 和 storage Pod 均为 `Running`。
* [ ] **FUSE PVC 已存在**：

  ```shell
  kubectl get pvc -n <NAMESPACE> <CLUSTER_NAME>-fuse
  ```

  预期输出：PVC 存在（Pod 挂载前状态为 `Pending` 属正常现象）。

## 推荐集群配置

启用 FUSE 写缓存时，未持久化的写入数据会占用更大比例的 NVMe 容量。建议将 `alluxio-cluster.yaml` 中的 Pinned 空间比例从默认的 `0.3` 提高至 `0.5`：

```yaml
spec:
  properties:
    alluxio.write.cache.enabled: "true"
    # 从默认 0.3 提高至 0.5，以应对 FUSE 写入密集型工作负载
    alluxio.worker.page.store.pinned.file.capacity.limit.ratio: "0.5"
  fdb:
    enabled: true
```

应用配置：

```shell
# 幂等操作，可重复执行
kubectl apply -f alluxio-cluster.yaml
```

> 请合理规划 Worker 的 NVMe 容量：在比例为 `0.5`、总缓存为 `1 TiB` 的情况下，最多 500 GiB 的空间可能被未持久化的写入数据占用。若写入吞吐持续超过持久化吞吐，空间将耗尽，Alluxio 会返回 `out-of-space` 错误。参见 [S3-API 写入优化](/ee-ai-cn/ai-3.8-15.1.x-cn/performance/s3-write-cache.md) 中的缓存空间管理章节。

## 部署 FUSE 客户端 Pod

Operator 在集群安装期间会创建名为 `<CLUSTER_NAME>-fuse` 的 PVC。使用 `mountPropagation: HostToContainer` 挂载，以便 FUSE 进程重启时自动恢复。

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: fuse-test-0
  namespace: <NAMESPACE>
spec:
  containers:
    - image: ubuntu:22.04
      name: fuse-test
      command: ["sleep", "infinity"]
      volumeMounts:
        - mountPath: /data
          name: alluxio-pvc
          mountPropagation: HostToContainer
  volumes:
    - name: alluxio-pvc
      persistentVolumeClaim:
        claimName: <CLUSTER_NAME>-fuse
```

```shell
# 幂等操作，可重复执行
kubectl apply -f fuse-pod.yaml
kubectl -n <NAMESPACE> get pod fuse-test-0
```

预期输出：`STATUS = Running`，`READY = 1/1`。

更多 FUSE 部署选项（DaemonSet、Docker / 裸机），参见 [POSIX API](/ee-ai-cn/ai-3.8-15.1.x-cn/data-access/fuse-based-posix-api.md)。

## 配置写回路径

写入策略按路径配置，与 [S3-API 写入优化](/ee-ai-cn/ai-3.8-15.1.x-cn/performance/s3-write-cache.md) 中的路径级配置相同。路径指 Alluxio 命名空间（如 `/s3/checkpoints`），而非 FUSE 挂载路径（`/data/s3/checkpoints`）。

非交互式配置（适用于脚本）：

```shell
kubectl exec -i -n <NAMESPACE> <CLUSTER_NAME>-coordinator-0 -- \
  bash -c 'EDITOR="cp /dev/stdin" alluxio pathconfig edit' << 'EOF'
{
  "apiVersion": "v1.0",
  "defaultRule": {
    "description": "Global default",
    "policyMode": "WRITE_THROUGH"
  },
  "pathRules": [
    {
      "alluxioPath": "/s3/checkpoints/**",
      "description": "Low-latency checkpoint writes",
      "policyMode": "WRITE_BACK",
      "properties": { "writeReplicas": 1 }
    }
  ]
}
EOF
```

预期输出：`Update successful!`

验证指定路径是否解析为预期策略：

```shell
kubectl exec -n <NAMESPACE> <CLUSTER_NAME>-coordinator-0 -- \
  alluxio pathconfig test --path /s3/checkpoints/epoch-1/model.pt
```

预期输出：包含 `"policyMode": "WRITE_BACK"`。

## 验证 FUSE 写回

通过 FUSE 写入文件，并确认其最终持久化至 UFS：

```shell
# 通过 FUSE 写入
kubectl exec -i -n <NAMESPACE> fuse-test-0 -- \
  bash -c 'echo "hello from fuse write cache" > /data/s3/checkpoints/test.txt'

# 确认在 Alluxio 命名空间中可见
kubectl exec -i -n <NAMESPACE> <CLUSTER_NAME>-coordinator-0 -- \
  alluxio fs ls /s3/checkpoints/test.txt
```

等待异步持久化完成（最长 `alluxio.write.cache.async.file.check.period`，默认 `10min`）：

```shell
# 轮询至 PERSISTED（8 次 × 15s = 2 分钟）
for i in $(seq 1 8); do
  echo "--- Check $i/8 ---"
  NOT_PERSISTED=$(kubectl exec -i -n <NAMESPACE> <CLUSTER_NAME>-coordinator-0 -- \
    alluxio fs ls /s3/checkpoints/ 2>&1 | grep -c "NOT_PERSISTED" || true)
  if [ "${NOT_PERSISTED}" = "0" ]; then
    echo "All files PERSISTED."
    break
  fi
  echo "${NOT_PERSISTED} file(s) still pending. Waiting 15s..."
  sleep 15
done
```

预期输出：2 分钟内出现 `All files PERSISTED.`

***

## 写缓存模式下的 POSIX 兼容性

{% hint style="warning" %}
FUSE 写缓存与 S3-API 写缓存共用同一后端。因此，写缓存 FUSE 挂载在标准 FUSE 语义之上还有额外的 POSIX 限制，且对**所有写缓存策略**（`WRITE_THROUGH`、`WRITE_BACK`、`TRANSIENT`）均生效。在将工作负载迁移至写缓存 FUSE 挂载前，请务必了解以下限制。
{% endhint %}

### rename() 返回 EIO

在任意写缓存策略生效期间，所有 `rename()` 操作都会失败并返回 `EIO`，无论文件是否已持久化至 UFS。受影响的操作包括：

* Shell 的 `mv` 和 `rename`
* Python 的 `os.rename()`、`pathlib.Path.rename()`
* 写后重命名模式（先写入 `.tmp`，再重命名）

**解决方案 — silly rename 拦截器（需手动开启）：** 当应用对已打开的文件执行 `rm` 时，Linux 内部会向 `.fuse_hidden*` 发起 `rename()`。启用拦截器可透明处理这一情况：

```yaml
spec:
  properties:
    # CLIENT 级别：在 FUSE 客户端属性中设置
    alluxio.fuse.silly.rename.interceptor.enabled: "true"
```

启用后，Alluxio 会拦截 `.fuse_hidden*` 重命名操作，无需触发 S3 的 `CopyObject + DeleteObject`。默认值为 `false`。

### 文件关闭后不可再写

文件一旦关闭，将无法再次打开进行写入、追加或截断：

| 操作                                                    | errno    |
| ----------------------------------------------------- | -------- |
| `open(path, O_CREAT \| O_EXCL)` — 文件已存在               | `EEXIST` |
| `open(path, O_WRONLY)` 或 `open(path, O_RDWR)` — 文件已存在 | `EACCES` |

**影响：** 原地更新文件的应用（数据库、日志轮转、配置重写器）无法通过写缓存 FUSE 挂载正常工作。写缓存 FUSE 挂载最适合一次性写入的工作负载：模型检查点、训练数据集、ETL 阶段输出。

### 不支持硬链接

`link()` 返回 `EOPNOTSUPP`。依赖硬链接的工具（`rsync --hard-links`、部分包管理器）无法通过该挂载正常工作。

### 删除时的缓存页回收（15.1.3+ 行为）

通过 FUSE `rm` 或 `rm -rf` 删除文件时，缓存页将在持有该文件副本的**所有** Worker 上回收，而不仅限于哈希环所有者 Worker。15.1.3 之前的版本中，仅所有者 Worker 回收缓存页；其他 Worker 上的孤儿页将保留至下一轮驱逐周期。

***

## 监控异步持久化

两条 CLI 命令（15.1.3+ 可用）可用于检查持久化操作的实时状态，无需等待 `alluxio fs ls`：

```shell
# 列出指定 Worker 上所有待处理或进行中的文件
kubectl exec -i -n <NAMESPACE> <CLUSTER_NAME>-worker-0 -- \
  alluxio async-persist list

# 按 Worker ID 过滤
kubectl exec -i -n <NAMESPACE> <CLUSTER_NAME>-worker-0 -- \
  alluxio async-persist list --worker <WORKER_ID>

# 查询指定路径的持久化状态和重试次数
kubectl exec -i -n <NAMESPACE> <CLUSTER_NAME>-coordinator-0 -- \
  alluxio async-persist stat --path /s3/checkpoints/epoch-1/model.pt
```

当 `alluxio fs ls` 显示文件长期处于 `NOT_PERSISTED` 状态时，可使用 `async-persist stat` 判断问题出在队列还是上传阶段。

## 关键配置

| 配置项                                                          | 默认值     | 描述                                                      |
| ------------------------------------------------------------ | ------- | ------------------------------------------------------- |
| `alluxio.write.cache.enabled`                                | `false` | 启用写缓存（与 S3 API 共享）。                                     |
| `alluxio.worker.page.store.pinned.file.capacity.limit.ratio` | `0.3`   | NVMe 容量中用于未持久化写入数据的最大比例。FUSE 写入密集型工作负载建议提高至 `0.5`。      |
| `alluxio.write.cache.async.file.check.period`                | `10min` | 孤儿检测扫描周期。设置过短会增加 FDB 负载。                                |
| `alluxio.write.cache.async.check.orphan.timeout`             | `1h`    | 超过此时间仍未提交的写入将被视为已放弃并清理。                                 |
| `alluxio.fuse.silly.rename.interceptor.enabled`              | `false` | CLIENT 级别。拦截 `.fuse_hidden*` 重命名/删除操作，透明处理已打开文件的 `rm`。  |
| `alluxio.worker.mark.writing.files.duration`                 | `10min` | 若文件处于写入状态但在该时长内未收到新数据，Worker 将其视为悬空写入并纳入清理。每次写入都会重置计时器。 |

## 故障排查

### 目录删除返回 DEADLINE\_EXCEEDED

对 `WRITE_BACK` 路径执行 `alluxio fs rm -R` 或 `rm -rf` 时可能出现：

```
io.grpc.StatusRuntimeException: DEADLINE_EXCEEDED: CallOptions deadline exceeded after ~5s
```

{% hint style="danger" %}
尽管出现该错误，底层文件**可能已在超时前从 UFS 删除**。请勿假设数据仍然存在。
{% endhint %}

**恢复步骤：**

1. 直接验证 UFS 状态：

   ```shell
   aws s3 ls s3://<BUCKET>/<path>/ --recursive | head -20
   ```
2. 若 S3 中文件已不存在，则数据层删除已成功。重新执行 `alluxio fs rm -R` 将确认并返回 `Path does not exist`。
3. Pagestore 磁盘空间不会立即收缩 — 孤儿页将在下一轮驱逐周期中被回收。

***

### 文件长期处于 NOT\_PERSISTED

```shell
kubectl exec -i -n <NAMESPACE> <CLUSTER_NAME>-coordinator-0 -- \
  alluxio fs ls /s3/checkpoints/
```

若文件在 `alluxio.write.cache.async.file.check.period` 后仍处于 `NOT_PERSISTED` 状态：

1. 检查异步持久化队列：

   ```shell
   kubectl exec -i -n <NAMESPACE> <CLUSTER_NAME>-worker-0 -- \
     alluxio async-persist list
   ```
2. 检查指定文件状态：

   ```shell
   kubectl exec -i -n <NAMESPACE> <CLUSTER_NAME>-coordinator-0 -- \
     alluxio async-persist stat --path /s3/checkpoints/<filename>
   ```
3. 检查 Worker 日志中的上传错误：

   ```shell
   kubectl logs -n <NAMESPACE> <CLUSTER_NAME>-worker-0 --tail=100 | \
     grep -i "persist\|upload\|flush"
   ```
4. 若 UFS 不可达，重试将进入指数退避（最长 `alluxio.worker.write.cache.async.persist.retry.max.interval`，默认 `1h`）。请从 Worker Pod 验证 UFS 连通性。

***

### rename() 意外返回 EIO

在任意写缓存策略生效时，此为预期行为（参见 [rename() 返回 EIO](#rename-fan-hui-eio)）。若应用依赖 rename：

* 将受影响路径切换为 `NO_CACHE` 策略，完全绕过该路径的写缓存。
* 若 rename 由已打开文件的 `rm` 触发，启用 `alluxio.fuse.silly.rename.interceptor.enabled: "true"`。

***

### FUSE Pod OOM 或挂载断开

这些问题与写缓存无关。参见 [FUSE 故障排除](/ee-ai-cn/ai-3.8-15.1.x-cn/data-access/fuse-based-posix-api.md)。

## 参考资源

* [S3-API 写入优化](/ee-ai-cn/ai-3.8-15.1.x-cn/performance/s3-write-cache.md) — 通过 S3 API 使用写缓存；部署写缓存请先完成此步骤
* [POSIX API](/ee-ai-cn/ai-3.8-15.1.x-cn/data-access/fuse-based-posix-api.md) — FUSE 部署详情、挂载选项、读缓存模式
* [S3 API 基准测试](/ee-ai-cn/ai-3.8-15.1.x-cn/benchmark/s3-api.md) — S3 侧写入吞吐基线
* [POSIX 性能基准测试](/ee-ai-cn/ai-3.8-15.1.x-cn/benchmark/benchmarking-posix-performance.md) — FUSE 侧吞吐基线


---

# 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/ai-3.8-15.1.x-cn/performance/fuse-write-cache.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.
