# 存储引擎配置 存储引擎只支持三种:**本地磁盘 / S3 / WebDAV**,由进程级环境变量 `FCB_STORAGE_ENGINE` 选择。 引擎与引擎相关配置在启动时一次性读取(`storage.SetEngineOptions` → `NewEngine`), **运行时修改引擎 KV 需重启服务**(管理端 `GET /admin/config/get` 的 `_engine_hint` 亦有提示)。 ## 引擎选择 ```bash FCB_STORAGE_ENGINE=local # 启动默认(KV storage_engine 为空时生效) FCB_STORAGE_ENGINE=s3 FCB_STORAGE_ENGINE=webdav ``` 非法值直接启动失败:`FCB_STORAGE_ENGINE 无效值 "xxx",仅支持 local|s3|webdav`。 **26.9 运行时热切换**:管理端 `POST /admin/storage/switch`(或后台设置页「存储引擎」卡)可在不重启的情况下切换引擎—— 先构建新引擎并健康检查,通过才生效;失败 503 保持原引擎。当前引擎持久化在 settings KV `storage_engine`(空=回落启动值)。 各引擎参数(存储目录/服务地址/存储桶/密钥)同样在后台设置页运行时可改;保存后对应引擎实例缓存失效,下次切换/构建生效。 ## 文件归属引擎(26.9) 每条分享记录(`file_codes.engine`)与上传会话(`upload_chunks.engine` / `presign_upload_sessions.engine`) 在创建时戳记当时的引擎名。下载、分片合并、删除按**归属引擎**操作——切换引擎后,旧引擎里的文件仍可正常下载与删除 (空戳为历史数据,回落当前引擎)。 ## 按日期目录存储 文件落盘路径:`[storage_path/]share/data/YYYY/MM/DD//<文件名>`(如 `share/data/2026/09/04/…`)。 按日嵌套目录自然排序、无日月歧义、避免单日海量文件挤在单目录;三种引擎一致适用;历史路径记录在 `file_codes.file_path`,不受路径规则调整影响。 ## 配置键与环境变量 引擎相关配置键(DB settings KV)可由环境变量种子注入(优先级:默认 < 环境变量 < DB KV): | KV 键 | 环境变量 | 引擎 | 说明 | |---|---|---|---| | `local_storage_path` | `FCB_LOCAL_STORAGE_PATH` | local | 本地存储根目录(容器内默认 `/app/data`) | | `storage_path` | `FCB_STORAGE_PATH` | 全部 | 存储相对路径前缀(空 = `share/data/…`) | | `s3_access_key_id` | `FCB_S3_ACCESS_KEY_ID` | s3 | 访问密钥 | | `s3_secret_access_key` | `FCB_S3_SECRET_ACCESS_KEY` | s3 | 私有密钥 | | `aws_session_token` | `FCB_AWS_SESSION_TOKEN` | s3 | 可选临时会话令牌 | | `s3_bucket_name` | `FCB_S3_BUCKET_NAME` | s3 | 桶名 | | `s3_endpoint_url` | `FCB_S3_ENDPOINT_URL` | s3 | S3 兼容端点(MinIO/R2 等;AWS 原生可空) | | `s3_region_name` | `FCB_S3_REGION_NAME` | s3 | 区域(默认 `auto`) | | `s3_addressing_style` | `FCB_S3_ADDRESSING_STYLE` | s3 | `auto`/`path`/`virtual` | | `webdav_url` | `FCB_WEBDAV_URL` | webdav | WebDAV 服务地址(如 `http://webdav:5000`) | | `webdav_username` | `FCB_WEBDAV_USERNAME` | webdav | 用户名 | | `webdav_password` | `FCB_WEBDAV_PASSWORD` | webdav | 密码 | | `webdav_root_path` | `FCB_WEBDAV_ROOT_PATH` | webdav | 根目录(默认 `filebox_storage`,不存在自动逐级创建) | `FCB_STORAGE_ENGINE` 本身不落库(`GET /admin/config/get` 中的 `file_storage` 为 KV 记忆键, 进程实际引擎以 `FCB_STORAGE_ENGINE` 与 `_engine_hint.storage_backend` 为准)。 ## 各引擎要点 ### 本地引擎(local) - 原子写:临时文件 + fsync + rename,避免半写文件。 - 路径安全:`SanitizePath` + 符号链接逃逸双重防穿越。 - Range 下载基于 `SectionReader`;分片按索引有序合并 + SHA256 校验,合并后清理分片目录。 ### S3 引擎(s3) - 原生 multipart 流式合并(失败自动 Abort),分片落临时文件保证精确 Content-Length 与可重放。 - 预签名 GET/PUT 直链(预签名直传唯一 `direct` 模式引擎)。 - SDK 内置 5xx 指数退避重试;`when_required` 校验模式兼容 MinIO/R2 与纯流式转发。 ### WebDAV 引擎(webdav,重点优化) - **连接复用**:池化 Transport,连接复用(实测 25 次请求仅 1 条 TCP 连接)。 - **认证**:Basic + Digest(RFC 2617 `qop=auth`,MD5/SHA-256)自动协商,401 挑战驱动。 - **Range**:`Range` 头透传 + `206` 解析,支持分块/断点下载。 - **重试**:5xx/429/408 指数退避(封顶 2s ± 20% 抖动,尊重 `Retry-After`)。 - **流式**:下载经 `io.Pipe` 流式转发不落盘;上下文取消挂到响应体读完之后,防止提前断连。 - **目录**:按需逐级 `MKCOL` + 目录缓存,避免重复建目录。 - **超时**:可配置(`webdav_url` 同级暂无独立超时键,引擎默认值内置)。 ## 健康检查 三引擎均实现 `HealthCheck`:local 写探针、s3 `ListObjectsV2`、webdav `PROPFIND`(根目录不存在时自建)。 服务启动时预检失败仅告警不阻断;运行状态可经 `GET /api/v1/health` 的 `data.storage` 查看当前引擎名。 ## 预签名直传支持矩阵 | 引擎 | `PresignPutURL` / `PresignGetURL` | init 返回 mode | |---|---|---| | s3 | ✅ | `direct` | | local / webdav | ❌(`ErrNotSupported`) | `proxy`(走服务端代理上传) | 引擎不支持的操作经统一映射返回 501: ```json { "code": 501, "msg": "当前存储引擎不支持该操作" } ``` ## Docker Compose 冒烟编排 `deploy/docker-compose.yml` 提供可选 profile(详见 deploy/README.md): ```bash docker compose --profile minio up -d --build # MinIO(含 mc 自动建桶)+ FCB_STORAGE_ENGINE=s3 docker compose --profile webdav up -d --build # dufs WebDAV 冒烟(admin/admin123)+ FCB_STORAGE_ENGINE=webdav docker compose --profile redis up -d --build # Redis 缓存增强(非引擎) ``` ## 存储哨兵错误 → HTTP 状态 | 哨兵错误 | HTTP | 文案 | |---|---|---| | `ErrNotFound` | 404 | 文件不存在 | | `ErrInvalidPath` | 400 | 非法文件路径 | | `ErrUnavailable` | 503 | 存储服务不可用,请稍后再试 | | `ErrNotSupported` | 501 | 当前存储引擎不支持该操作 | | `ErrRangeNotSatisfiable` | 416 | 请求范围超出文件大小 | | `ErrHashMismatch` | 400 | 分片哈希校验失败,请重新上传 | 容量超限(`storageLimit`,经容量预留判定)返回 507:`存储空间已达到管理员设置的容量上限`。