# Client 写回

## Client 写回概览

本文档介绍如何在 Alluxio 中启用client写回功能。 当用户写入数据时，数据会首先写入本地磁盘，然后异步上传到 UFS（底层文件系统）。 **目前，client 写回功能仅限于 Alluxio FUSE。**

<figure><img src="https://github.com/TachyonNexus/documentation/blob/AI-3.6-12.0.x/docs-ai/cn/.gitbook/assets/client-writeback.png" alt=""><figcaption></figcaption></figure>

通过 Alluxio 写入数据时，写回功能可节省网络开销和 UFS API 调用成本，从而实现：

* 在顺序写入大文件时提高吞吐量，速度接近本地磁盘速度。
* 提高小文件写入性能，可在短时间内写入大量小文件。

## 局限性和适用场景

由于写回通过本地磁盘缓存数据，其功能受限于本地磁盘：

1. 如果本地磁盘在上传过程中发生故障，**数据将丢失**。
2. **本地磁盘需要高性能的固态硬盘**；普通机械硬盘的性能不足以实现加速。

由于写回是以异步方式上传文件的，因此**在上传完成之前无法读取写入的文件**。

基于上述限制，我们建议将写回功能的使用限制在**对性能敏感但可允许小概率数据丢失的场景**，如模型检查点(checkpoint)写入场景。

## 启用 Client 写回

在 `alluxio-site.properties` 中添加以下配置：

```properties
# 开启写回功能
alluxio.user.write.back.enabled=true
# 设置开启写回功能的路径
alluxio.user.fuse.path.based.config.file.path=${ALLUXIO_HOME}/conf/pathConfig.json
# 配置写回功能可使用的本地磁盘容量，默认为0表示不限制磁盘的使用
alluxio.user.fuse.write.back.dir.quota=1TB
# 配置写回功能使用的本地目录，本地目录必须为 SSD 所在目录
alluxio.user.fuse.write.back.dir=/data/alluxio/writeback
```

文件 `pathConfig.json` 的格式如下：

```json
[
   {
     "pathRegex": "/user/ai_user1/checkpoint/.*",
     "localWriteBackEnabled": true
   },
   {
     "pathRegex": "/user/ai_user2/checkpoint/.*",
     "localWriteBackEnabled": true
   }
]
```

请注意，此处的路径是 Alluxio 路径，而不是 Alluxio FUSE 的挂载路径。 写回仅对 `pathConfig.json`中配置的路径有效； 对未配置路径的写入请求不会生效。

当目录(directory)使用量超过`alluxio.user.fuse.write.back.dir.quota`配置值时，写回功能将抛出异常。 该情况下的另一种操作行为是回退到同步写入模式。 在回退模式下，写回功能会优先将本地写入的中间文件上传到 UFS，然后再接收更多的写请求； 对于用户而言，在此状态下的写请求将会被阻止。 当上传完成后，后续的写请求将直接写入 UFS。

要启用此功能，请添加以下配置：

```properties
alluxio.user.fuse.write.back.degraded.sync.write.on.insufficient.space=true
```

## 加速小文件写入

当用户通过 FUSE 写入文件时，FUSE 会首先检查文件是否存在。 如果文件不存在，每次检查操作都会穿透到 UFS。 在写入大量小文件时，该操作行为会导致性能低下，这是因为 UFS API 调用会耗费大量时间。 写回功能支持在不请求 UFS 的情况下，使用布隆过滤器（bloom filter）快速确定是否**文件不存在**。 要启用此功能，请添加以下配置：

```properties
alluxio.user.fuse.write.back.status.bloom.filter.enabled=true
```

布隆过滤器的容量为 1 千万，每 5 分钟刷新一次。 如果在使用过程中发现布隆过滤器的误报率（可通过 `WriteBackBloomFilterFpp` 指标查看）较高，可通过以下配置修改刷新周期：

```properties
alluxio.user.fuse.write.back.status.bloom.filter.refresh.period=1min
```

默认情况下，写回会优化空文件的写入，将空文件直接同步到 UFS。 如果对加速空文件写入的需求很高，可以禁用这一优化：

```properties
alluxio.user.fuse.write.back.sync.flush.empty.file=false
```

## 处理异步上传失败的文件

如果写回操作连续三次上传失败，文件将被标记为上传失败，并移至写回目录下的 `UPLOAD_FAILED` 子目录。 请注意，为防止数据丢失，写回不会直接删除上传失败的文件。 如果检测到上传失败的文件，请及时处理。 上传失败文件的数量可通过 `UploadManagerUploadFailedFiles` 指标查看。

## 指标

| 指标                                          | 描述                                                                   |
| ------------------------------------------- | -------------------------------------------------------------------- |
| `UploadManagerBytesWriteToUfs`              | Bytes written to UFS by writeback asynchronously                     |
| `UploadManagerFailedTask`                   | Number of failed writeback asynchronous upload tasks                 |
| `UploadManagerSuccessTask`                  | Number of successful writeback asynchronous upload tasks             |
| `UploadManagerRunningTask`                  | Number of files currently being uploaded by writeback                |
| `UploadManagerSpaceCapacity`                | Maximum disk usage for writeback                                     |
| `UploadManagerSpaceUsed`                    | Disk space used by writeback                                         |
| `UploadManagerUploadFailedFiles`            | Number of files in the local `UPLOAD_FAILED` directory for writeback |
| `WriteBackBloomFilterApproximateElements`   | Number of files recorded by the bloom filter                         |
| `WriteBackBloomFilterFpp`                   | Bloom filter false positive rate                                     |
| `WriteBackBloomFilterFullLoadedDirectories` | Number of directories fully loaded by the bloom filter               |
| `WriteBackBloomFilterLoadingDirectories`    | Number of directories currently being loaded by the bloom filter     |
