# POSIX API

Alluxio 的 POSIX API 允许您将 Alluxio 命名空间挂载为大多数类 Unix 操作系统上的标准文件系统。此功能通常称为"Alluxio FUSE"，让您可以使用标准命令行工具（`ls`、`cat`、`mkdir`）和现有应用程序与 Alluxio 中的数据进行交互，而无需任何代码更改。

与 S3FS 等特定的文件系统包装器不同，Alluxio FUSE 作为 Alluxio 支持的许多存储系统的通用缓存和数据编排层，非常适合在 AI/ML 模型训练和服务等工作负载中加速 I/O。

基于[用户空间文件系统 (FUSE)](https://en.wikipedia.org/wiki/Filesystem_in_Userspace)项目，挂载的文件系统提供了大多数基本操作，但由于 Alluxio 的分布式特性，它并非完全符合 POSIX 标准。有关详细信息，请参阅[POSIX 兼容性](#posix-jian-rong-xing)部分。

## 何时使用 FUSE

FUSE 接口对于传统应用程序和现代 AI/ML 工作负载尤其强大。常见用例包括：

* **AI/ML 模型训练**：在使用 PyTorch 或 TensorFlow 等框架训练模型时，您可以直接从挂载的 FUSE 路径读取数据集。这简化了数据访问，并利用 Alluxio 的缓存来显著加快训练作业。有关性能调优，请参阅[模型加载](https://documentation.alluxio.io/ee-ai-cn/performance/model-loading)。
* **模型服务**：对于需要快速加载模型的推理服务器，FUSE 提供了对存储在 Alluxio 中的模型的低延迟访问。
* **遗留应用程序**：期望标准文件系统的应用程序可以指向 FUSE 挂载点，以从 Alluxio 读取和写入数据，而无需修改。
* **交互式数据探索**：数据科学家和工程师可以使用 shell 命令（`ls`、`cat`、`head`）来探索和与 Alluxio 中的数据进行交互，就像本地文件系统一样。

## 在 Kubernetes 上开始使用 FUSE

部署 Alluxio FUSE 的最常见方法是在 Kubernetes 集群上与您的应用程序一起部署。

### 先决条件

在设置 FUSE 之前，请验证以下内容：

* [ ] **Alluxio 集群正在运行**：

  ```shell
  kubectl -n alx-ns get alluxiocluster
  ```

  预期结果：`CLUSTERPHASE` = `Ready`。如果不是，请参阅[在 Kubernetes 上安装](https://documentation.alluxio.io/ee-ai-cn/start/installing-on-kubernetes)。
* [ ] **CSI 驱动已部署**（CSI 方法需要）。Alluxio Operator 默认部署 CSI 驱动。验证方法：

  ```shell
  kubectl -n alluxio-operator get pod -l app=alluxio-csi-nodeplugin
  ```

  预期结果：每个节点上的 CSI nodeplugin pod 状态为 `Running`。如果在 Operator 安装时禁用了 CSI（`alluxio-csi.enabled: false`），请改用 [DaemonSet 方法](#fang-fa-2-shi-yong-daemonset)。
* [ ] **FUSE PVC 存在**（CSI 方法需要）：

  ```shell
  kubectl -n alx-ns get pvc alluxio-cluster-fuse
  ```

  预期结果：PVC 存在（在 pod 使用之前它将处于 `Pending` 状态——这是正常的）。

### 方法 1：使用 CSI（推荐）

[容器存储接口 (CSI)](https://github.com/container-storage-interface/spec/blob/master/spec.md) 是在 Kubernetes 中使用 Alluxio FUSE 的标准推荐方法。Alluxio Operator 在安装集群时会自动配置一个名为 `alluxio-cluster-fuse` 的 PersistentVolumeClaim (PVC)。

要使用它，请将此 PVC 挂载到您的应用程序 pod 中。Operator 将处理底层 PersistentVolume (PV) 的创建和绑定。

**示例 Pod 配置：**

将以下配置保存到名为 `fuse-pod.yaml` 的文件中：

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: fuse-test-0
  namespace: alx-ns
  labels:
    app: alluxio
spec:
  containers:
    - image: ubuntu:22.04
      imagePullPolicy: IfNotPresent
      name: fuse-test
      command: ["sleep", "infinity"]
      volumeMounts:
        - mountPath: /data
          name: alluxio-pvc
          mountPropagation: HostToContainer
  volumes:
    - name: alluxio-pvc
      persistentVolumeClaim:
        claimName: alluxio-cluster-fuse
```

创建 pod：

```shell
# Idempotent
kubectl apply -f fuse-pod.yaml
```

验证 pod 正在运行且 FUSE 挂载可访问：

```shell
kubectl -n alx-ns get pod fuse-test-0
```

预期结果：`STATUS` = `Running`，`READY` = `1/1`。

关键细节：

* **共享 FUSE 进程**：同一 Kubernetes 节点上的多个 pod 可以使用相同的 PVC，并将共享一个 Alluxio FUSE 进程以提高效率。
* **`mountPropagation: HostToContainer`**：此设置至关重要。它确保如果 FUSE 进程崩溃，挂载点可以自动恢复并重新传播到您的容器。

挂载后，您可以像与 Alluxio 命名空间的根目录一样与 `/data` 目录进行交互。

**示例用法：**

```shell
kubectl -n alx-ns exec -it fuse-test-0 -- ls /data/
```

```console
s3
```

```shell
kubectl -n alx-ns exec -it fuse-test-0 -- bash -c 'echo "hello, world!" > /data/s3/message.txt'
kubectl -n alx-ns exec -it fuse-test-0 -- cat /data/s3/message.txt
```

```console
hello, world!
```

从 Coordinator 验证文件在 Alluxio 中存在：

```shell
kubectl -n alx-ns exec -i alluxio-cluster-coordinator-0 -- alluxio fs ls /s3/message.txt
```

```console
             14                 06-27-2024 07:54:40:000 FILE /message.txt
```

### 方法 2：使用 DaemonSet

如果您的 Kubernetes 版本或环境不支持 CSI，您可以使用 DaemonSet 部署 FUSE。此方法在每个节点（或您选择的节点子集）上运行一个 FUSE pod。

1. **配置 DaemonSet：** 在部署 Alluxio 集群之前，修改您的 `alluxio-cluster.yaml` 以使用 `daemonSet` 类型并为挂载指定一个主机路径。

   ```yaml
   apiVersion: k8s-operator.alluxio.com/v1
   kind: AlluxioCluster
   spec:
     fuse:
       type: daemonSet
       hostPathForMount: /mnt/alluxio/fuse # 如果未指定，将使用 /mnt/alluxio/fuse
       nodeSelector:
         alluxio.com/selected-for-fuse: true
   ```

   这将在所有带有标签 `alluxio.com/selected-for-fuse: true` 的节点上部署 FUSE pod。首先标记节点：

   ```shell
   kubectl label nodes <node-name> alluxio.com/selected-for-fuse=true
   ```
2. **在您的应用程序 Pod 中挂载：** 在您的应用程序 pod 中，挂载 FUSE DaemonSet 公开文件系统的主机路径。

   ```yaml
   apiVersion: v1
   kind: Pod
   metadata:
     name: fuse-test-0
     namespace: alx-ns
     labels:
       app: alluxio
   spec:
     containers:
       - image: ubuntu:22.04
         imagePullPolicy: IfNotPresent
         name: fuse-test
         command: ["sleep", "infinity"]
         volumeMounts:
           - mountPath: /mnt/alluxio
             name: alluxio-fuse-mount
             mountPropagation: HostToContainer
     volumes:
       - name: alluxio-fuse-mount
         hostPath:
           path: /mnt/alluxio
           type: Directory
   ```

   与 CSI 方法类似，`mountPropagation` 对于自动恢复至关重要。
3. **验证：** 部署后，确认 DaemonSet pod 正在运行且挂载可访问：

   ```shell
   kubectl -n alx-ns get pod -l app=alluxio-fuse
   ```

   预期结果：每个标记节点上的 FUSE pod 状态为 `Running`。

## 高级配置

### 启用追加和随机写入

要启用**追加和随机写入**操作，请在您的 Alluxio 配置（`alluxio-site.properties` 或通过 Helm chart 值）中设置以下属性：

```properties
alluxio.user.fuse.random.access.file.stream.enabled=true
```

这允许应用程序修改现有文件，适用于日志记录或数据库等工作负载，但可能会对性能产生影响。

### 启用符号链接

默认情况下，符号链接 (symlinks) 处于禁用状态。要启用它们，请在您的 Alluxio 配置（`alluxio-site.properties` 或通过 Helm chart 值）中设置以下属性：

```properties
alluxio.user.fuse.symlink.enabled=true
```

### 启用并行 `getattr` 操作

默认情况下，FUSE 内核模块会串行处理同一目录下的 `lookup` 和 `readdir` 操作。为了提高需要高并发元数据操作的工作负载（例如对同一目录下的许多文件进行 `getattr`）的性能，您可以启用并行目录操作。

要启用此功能，请在您的 Alluxio 配置（`alluxio-site.properties`）中设置以下属性：

```properties
alluxio.fuse.parallel.dirops.enabled=true
```

> **注意**：该功能目前建议仅用于**只读**工作负载。

### 隔离数据访问

默认情况下，FUSE 挂载提供对整个 Alluxio 命名空间的访问。对于多租户环境，您可能希望将用户的访问限制在特定的子目录中。

#### 使用 `subPath`（仅限 CSI）

您可以使用 `subPath` 字段将 Alluxio 命名空间中的特定子目录挂载到您的 pod 中。这是数据隔离的最简单方法。

```yaml
# ... pod spec ...
      volumeMounts:
        - mountPath: /data
          name: alluxio-pvc
          mountPropagation: HostToContainer
          subPath: s3/path/to/files
# ...
```

在此示例中，容器内的 `/data` 目录直接映射到 Alluxio 中的 `/s3/path/to/files`。

> **注意**：不建议将 `subPath` 与 DaemonSet 方法一起使用，因为它会破坏自动恢复机制。

#### 使用单独的 PVC（仅限 CSI）

为了在无法控制用户 pod 规范的情况下实现更强大的隔离，您可以创建一个专用的 `StorageClass` 和 `PersistentVolumeClaim`，并将其预先绑定到特定的 Alluxio 路径。

1. **创建自定义 `StorageClass` 和 `PVC`：** 将以下内容保存到名为 `custom-sc-pvc.yaml` 的文件中：

   ```yaml
   apiVersion: storage.k8s.io/v1
   kind: StorageClass
   metadata:
     name: default-alluxio-s3
     namespace: alx-ns
   parameters:
     alluxioClusterName: alluxio-cluster
     alluxioClusterNamespace: alx-ns
     mountPath: /s3/path/to/files
   provisioner: alluxio
   volumeBindingMode: WaitForFirstConsumer
   ---
   apiVersion: v1
   kind: PersistentVolumeClaim
   metadata:
     name: alluxio-csi-s3
     namespace: alx-ns
   spec:
     accessModes:
     - ReadWriteOnce
     resources:
       requests:
         storage: 1Mi
     storageClassName: default-alluxio-s3
   ```

   应用配置：

   ```shell
   # Idempotent
   kubectl apply -f custom-sc-pvc.yaml
   ```

   验证：

   ```shell
   kubectl -n alx-ns get pvc alluxio-csi-s3
   ```

   预期结果：PVC 存在（在 pod 使用之前将处于 `Pending` 状态）。
2. **挂载新的 PVC：** 用户现在可以挂载 `alluxio-csi-s3` PVC，他们的访问将自动限定在 `/s3/path/to/files`。

### 从另一个命名空间访问 FUSE

如果您的应用程序在与 Alluxio 集群不同的命名空间中运行，您必须在应用程序的命名空间中创建相应的 PVC。

1. **在您的命名空间中创建 PVC：** `storageClassName` 必须指向由 Operator 在 Alluxio 命名空间中创建的 FUSE StorageClass（例如，`alx-ns-alluxio-cluster-fuse`）。将以下内容保存到名为 `csi-pvc.yaml` 的文件中：

   ```yaml
   apiVersion: v1
   kind: PersistentVolumeClaim
   metadata:
     name: alluxio-fuse
   spec:
     accessModes:
     - ReadWriteOnce
     resources:
       requests:
         storage: 1Mi
     storageClassName: alx-ns-alluxio-cluster-fuse
   ```
2. **应用 PVC：**

   ```shell
   kubectl create -f csi-pvc.yaml -n <my-namespace>
   ```

   验证：

   ```shell
   kubectl -n <my-namespace> get pvc alluxio-fuse
   ```

   预期结果：PVC 存在。

### 自定义 FUSE 挂载选项

您可以通过在 `AlluxioCluster` YAML 中提供挂载选项来调整 FUSE 性能。这些选项直接传递给底层的 FUSE 驱动程序。有关完整列表，请参阅 [FUSE 文档](http://man7.org/linux/man-pages/man8/mount.fuse3.8.html)。

**示例配置：**

```yaml
fuse:
  mountOptions:
    - allow_other
    - kernel_cache
    - entry_timeout=60
    - attr_timeout=60
    - max_idle_threads=128
    - max_background=128
```

**常用调整选项：**

| 挂载选项                 | FUSE 内核默认值 | Alluxio Operator 默认值 | 描述                                                                                 |
| -------------------- | ---------- | -------------------- | ---------------------------------------------------------------------------------- |
| `kernel_cache`       | 禁用         | 启用                   | 允许内核缓存文件数据，可显著提高读取性能。仅当底层文件不会在 Alluxio 之外被修改时使用。                                   |
| `auto_cache`         | 禁用         | 禁用                   | 类似于 `kernel_cache`，但当文件修改时间或大小发生变化时缓存自动失效。对于有可变数据的裸机部署，建议优先使用此选项而非 `kernel_cache`。 |
| `attr_timeout=N`     | 1.0        | 60                   | 内核缓存文件和目录属性（权限、大小）的秒数。增加此值可减少重复 `stat` 调用的元数据开销。                                   |
| `entry_timeout=N`    | 1.0        | 60                   | 缓存文件名查找的秒数。增加此值可加快频繁重复打开文件的工作负载的路径解析速度。                                            |
| `max_background=N`   | 12         | 128                  | FUSE 内核驱动程序允许排队的最大后台请求数。对于高 I/O 并发工作负载，建议增大此值。                                     |
| `max_idle_threads=N` | 10         | 128                  | FUSE 守护进程的最大空闲线程数。增加此值可防止在高并发负载下频繁创建/销毁线程带来的性能开销。                                  |

> 对于读取密集型 AI/ML 工作负载，请参阅[文件读取优化](https://documentation.alluxio.io/ee-ai-cn/performance/file-reading)，了解超出 FUSE 挂载选项的 Alluxio 级别调优。

### 自定义资源限制

您可以调整分配给 FUSE pod 及其 JVM 的 CPU 和内存资源。

```yaml
apiVersion: k8s-operator.alluxio.com/v1
kind: AlluxioCluster
spec:
  fuse:
    resources:
      limits:
        cpu: "12"
        memory: "36Gi"
      requests:
        cpu: "1"
        memory: "32Gi"
    jvmOptions:
      - "-Xmx22g"
      - "-Xms22g"
      - "-XX:MaxDirectMemorySize=10g"
```

**内存限制公式：**

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

对于上述配置（`-Xmx22g`，`-XX:MaxDirectMemorySize=10g`）：最小限制为 22 + 10 + 2 = 34 GiB，示例中设置为 36 GiB。

> 如果省略了 `-XX:MaxDirectMemorySize`，JVM 会将其默认为与 `-Xmx` 相同的值，因此容器限制通常需要设置为 `-Xmx` 的 2.5 倍或更多。

## 故障排除

### FUSE 挂载显示 "Transport endpoint is not connected"

**症状**：访问挂载路径返回 `Transport endpoint is not connected`。

**原因**：FUSE 进程崩溃或被重新启动，且挂载未恢复。

**解决方案**：

1. 验证应用程序 pod 规范中设置了 `mountPropagation: HostToContainer`。没有它，自动恢复无法工作。
2. 检查 FUSE pod 是否正在运行：

   ```shell
   kubectl -n alx-ns get pod -l app=alluxio-fuse
   ```
3. 如果 FUSE pod 正在运行但挂载已过期，请删除并重新创建应用程序 pod：

   ```shell
   kubectl -n alx-ns delete pod fuse-test-0
   kubectl apply -f fuse-pod.yaml
   ```

### FUSE pod 处于 CrashLoopBackOff 或 OOMKilled 状态

**症状**：FUSE pod 反复崩溃，显示 `Exit Code 137` 或 `OOMKilled`。

**原因**：容器内存限制对于配置的 JVM 堆和直接内存来说太低。

**解决方案**：增加 FUSE 容器内存限制。确保满足内存公式：

```
memory limit ≥ -Xmx + -XX:MaxDirectMemorySize + 2–4 GiB
```

查看崩溃前的 FUSE pod 日志：

```shell
kubectl -n alx-ns logs <fuse-pod-name> --previous | tail -50
```

查找 `OutOfMemoryError` 以确定是增加 `-Xmx` 还是 `-XX:MaxDirectMemorySize`。请参阅[自定义资源限制](#zi-ding-yi-zi-yuan-xian-zhi)。

### 应用程序 pod 卡在 ContainerCreating 状态

**症状**：应用程序 pod 在请求 FUSE PVC 后仍处于 `ContainerCreating` 状态。

**原因**：CSI 驱动未安装，或 FUSE PVC 不存在。

**解决方案**：

1. 检查 pod 上的事件：

   ```shell
   kubectl -n alx-ns describe pod <pod-name>
   ```
2. 如果事件提到 PVC 未找到，请验证 PVC 是否存在：

   ```shell
   kubectl -n alx-ns get pvc alluxio-cluster-fuse
   ```
3. 如果缺少 CSI nodeplugin，请验证 Operator 是否在启用 CSI 的情况下安装（默认启用）。如果需要，请在不使用 `alluxio-csi.enabled: false` 的情况下重新安装 Operator。

### FUSE 挂载上出现权限被拒绝

**症状**：访问挂载时出现 `ls: cannot access '/data': Permission denied`。

**原因**：FUSE 挂载未包含 `allow_other` 选项，该选项将访问限制为挂载它的用户。

**解决方案**：在 `alluxio-cluster.yaml` 的 FUSE 挂载选项中添加 `allow_other`：

```yaml
fuse:
  mountOptions:
    - allow_other
```

然后重新创建 Alluxio 集群以使更改生效。

有关细粒度的访问控制，请参阅[为 FUSE 启用授权](https://github.com/TachyonNexus/documentation/blob/AI-3.8-15.1.x/docs-ai/cn/administration/security/enabling-authorization-fuse.md)。

### 读取性能缓慢

**症状**：通过 FUSE 读取文件明显慢于预期。

**诊断**：

1. 检查数据是否已缓存在 Alluxio 中：

   ```shell
   kubectl -n alx-ns exec -i alluxio-cluster-coordinator-0 -- alluxio fs ls /s3/path/to/file
   ```

   如果文件显示 0% 缓存，首次读取将会较慢，因为它需要从底层存储获取数据。
2. 检查 FUSE 挂载选项——确保设置了 `kernel_cache` 或 `auto_cache` 以及增大的 `attr_timeout`/`entry_timeout` 值。请参阅[自定义 FUSE 挂载选项](#zi-ding-yi-fuse-gua-zai-xuan-xiang)。
3. 对于 AI/ML 训练工作负载，在开始训练前预加载数据：

   ```shell
   kubectl -n alx-ns exec -i alluxio-cluster-coordinator-0 -- alluxio job load --path /s3/path/to/dataset --submit
   ```

有关全面的读取性能调优，请参阅[文件读取优化](https://documentation.alluxio.io/ee-ai-cn/performance/file-reading)。有关基准测试，请参阅[基准测试 POSIX 性能](https://documentation.alluxio.io/ee-ai-cn/benchmark/benchmarking-posix-performance)。

## 清理

要删除设置过程中创建的测试 pod 和任何自定义 PVC：

```shell
# 删除测试 pod
kubectl -n alx-ns delete pod fuse-test-0

# 删除自定义 PVC（如果已创建）
kubectl -n alx-ns delete -f custom-sc-pvc.yaml

# 删除跨命名空间 PVC（如果已创建）
kubectl -n <my-namespace> delete -f csi-pvc.yaml
```

> `alluxio-cluster-fuse` PVC 由 Alluxio Operator 管理，在删除集群时会自动清理。请勿手动删除它。

## POSIX 兼容性

虽然支持大多数标准文件系统操作，但 Alluxio FUSE 不提供完全的 POSIX 兼容性。以下是支持和不支持的操作的摘要。

### 文件操作

| 支持                                                                                                                                                                    | 不支持                                                                                                                                                                                                                                              |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| <ul><li>创建和删除文件</li><li>重命名文件</li><li>顺序、随机和并发读取</li><li>顺序、追加、随机和并发写入</li><li>截断或覆盖文件</li><li>符号链接 (<code>ln -s</code>)</li><li>获取文件状态 (<code>stat</code>)</li></ul> | <ul><li>硬链接 (<code>ln</code>)</li><li>文件锁定 (<code>flock</code>)</li><li>更改所有权 (<code>chown</code>) 或权限 (<code>chmod</code>)</li><li>更改访问/修改时间 (<code>utimens</code>)</li><li>扩展属性 (<code>chattr</code>、粘滞位、xattr)</li><li>对同一文件的原子并发写入</li></ul> |

> **注意**：某些功能（如高级写入和符号链接）支持但默认禁用。有关如何启用它们的说明，请参阅以下部分：
>
> * [启用追加和随机写入](#qi-yong-zhui-jia-he-sui-ji-xie-ru)
> * [启用符号链接](#qi-yong-fu-hao-lian-jie)

### 目录操作

| 支持                                                                                                          | 不支持         |
| ----------------------------------------------------------------------------------------------------------- | ----------- |
| <ul><li>创建和删除目录</li><li>重命名目录</li><li>列出目录内容 (<code>ls</code>)</li><li>获取目录状态 (<code>stat</code>)</li></ul> | 没有主要的不支持操作。 |

### 其他限制

* **特殊文件**：不支持设备文件、管道和 FIFO。
* **路径名**：避免在文件或目录名中使用特殊字符（`?`、`\`）或模式（`./`、`../`）。
