存储
Arkvory 把每个已发布的文件原样保存在服务器本地磁盘上的存储目录中,只保存一份。本页说明哪些内容占用磁盘空间、如何用配额和保留策略限制它、已删除的文件如何离开磁盘,以及磁盘写满时该怎么做。
内容所在位置
存储目录由 ARKVORY_DATA_DIR 设置。安装程序使用以下位置:
| 安装方式 | 存储 |
|---|---|
| Windows | C:\ProgramData\ProAnima\Arkvory 中的 data\ |
| Linux | /opt/proanima-arkvory 中的 data/ |
| Docker Compose | Docker 卷 proanima-arkvory_storage |
在它内部,blobs/ 保存完成的文件,staging/ 和 parts/ 保存进行中的上传,文件 storage-id 将目录与数据库绑定。包含所有名称、标签、版本和权限的目录数据存放在 PostgreSQL 中。文件与数据库属于一体。
- 使用支持硬链接的本地文件系统。不要将网络共享用于存储。
- 不要手动在目录中添加、更改或删除文件。Arkvory 会自行删除文件,如下所述。
- 已发布的文件绝不会更改。新内容是具有新 ID 的新文件。
规划磁盘
以下内容会占用存储卷上的磁盘空间:
| 内容 | 说明 |
|---|---|
| 已发布的文件 | 你保留的所有版本 |
| 进行中的上传 | 分片和暂存文件,直到上传结束 |
| 已完成上传的分片文件 | 临时分片会留在完成文件旁边,直到一次物理清理将其移除。参见物理清理 |
| 已删除的文件 | 它们会留在磁盘上,直到宽限期结束且一次清理将其移除 |
| 镜像副本 | 镜像复制文件期间 mirror-staging 中的一个分片。参见镜像 |
除存储之外,如果可能,请为 PostgreSQL 数据库、日志和备份存储规划各自的卷。参见备份。
Arkvory 在存储卷上预留一份可用空间。默认是 1 GiB(ARKVORY_STORAGE_RESERVE_BYTES)。会动用该预留的上传会被拒绝,返回 HTTP 507 和原因 storage_full。下载继续工作。在没有空间容纳新数据期间,GET /health/ready 显示 writable: false。
有两个限制独立于磁盘运行:
ARKVORY_CAPACITY_BYTES限制安装实例预留的所有内容。默认是 10 TiB。它是逻辑限制,不是对磁盘的检查。达到时,上传失败,返回 HTTP 507 和原因catalog_limit。ARKVORY_MAX_OBJECT_BYTES限制单个文件的大小。
参见环境变量。Arkvory 没有针对存储或数据库可用空间的指标。请使用操作系统工具或 node exporter 监控这些卷。
谁可以管理存储
存储设置不属于常规的读写权限。服务密钥需要对仓库具有明确的动作:
| 动作 | 允许 |
|---|---|
storage.read | 查看策略、用量和清理设置 |
storage.manage | 更改策略、配额和清理设置,并请求一次清理批次 |
artifact.delete | 预览删除、删除制品,并开启自动保留策略 |
diagnostics.read | 读取存储事件 |
带密码的账户和恢复密钥本身不具备这些权限。要在控制台中管理存储:
- 创建一个服务账户,并为该仓库配置包含这四个动作的策略。参见账户与访问。
- 为它签发并激活一个密钥。
- 在控制台中打开 使用服务密钥或自动化密钥连接,粘贴密钥并选择 连接。
- 打开 仓库,在仓库卡片上选择 存储与清理。
面板 存储与自动清理 会出现在目录上方。没有权限时,该面板保持隐藏。
已启用的保留策略与启用它的密钥绑定。每次自动运行都会再次检查该密钥是否仍然有效、未过期,并且仍具有 storage.manage 和 artifact.delete。如果你撤销该密钥或收窄其权限,删除会停止并出现事件 retention.failed。轮换密钥后,请使用新密钥再次保存该策略。
配额与警告阈值
仓库可以有配额。没有配额时,只应用全局限制。
| 设置 | 控制台字段 | 含义 | 默认值 |
|---|---|---|---|
| 配额 | 配额,GiB(留空表示不限制仓库) | 仓库可使用的最大空间。API 接受精确字节数,从 1 到 9 007 199 254 740 991,null 表示无限制 | 无限制 |
| 警告阈值 | 警告阈值(%) | 触发警告的配额占比。1–98 | 80 |
| 严重阈值 | 严重阈值(%) | 触发错误的占比。2–99,高于警告阈值 | 95 |
计入配额的用量是仓库中所有尚未从磁盘移除的文件大小:已发布的文件、未完成的上传,以及等待清理的已删除文件。因此,已删除的文件在被一次清理移除之前仍然占用配额。
- 检查。 服务器在上传开始时检查配额。会超出配额的新上传失败,返回 HTTP 507 和原因
storage_quota。使用相同幂等键的重试不会重复预留空间。 - 调低。 你可以把配额设到低于当前用量。正在运行的上传可以完成。超出限制的新上传会被拒绝。
- 不会自动释放。 配额绝不会导致删除。保留策略不会为了满足配额而移除额外的构建。
- 状态。 状态为
unlimited、normal、warning、critical或exceeded。状态变化会作为一次存储事件记录一次。 - 监控。 服务器每分钟重新检查最多 20 个仓库的状态,在自动删除关闭时也是如此。
这些数字是逻辑预留,不是可用磁盘空间。仓库可能在其配额以内,而磁盘却已满,因为磁盘还保存着暂存文件和其他仓库。
保留策略
保留策略会自动删除旧的已注册 UPack 构建并保留最近 N 个。它不会删除其他文件:按路径访问的普通文件、容器镜像、Git LFS 对象和 npm 包不在其范围内。没有策略时,不会自动删除任何内容。
设置
| 设置 | 控制台字段 | 含义 | 默认值 |
|---|---|---|---|
| 启用 | 启用自动清理 | 开启自动删除 | 关闭 |
| 分组 | 最近 N 个的计数范围 | 计数的单位:包和通道、包 或 整个仓库 | 包和渠道 |
| 最近 N 个 | 保留最近 N 个构建(默认) | 每个计数器保留多少个构建,1–100 000 | 10 |
| 渠道 | 按通道覆盖:标签=N,每行一个 | 为某个标签单独设置 N,格式为 label=N,每行一个,最多 32 个。仅与分组“包和渠道”一起使用 | test=10、staging=10、release=10 |
| 最小年龄 | 删除前的最短保留时间(小时) | 比此更年轻的构建会保留,以小时计,0–87 600 | 24 |
| 受保护标签 | 受保护的标签(以逗号分隔) | 带有其中任一标签的构建绝不会被删除,最多 32 个,以逗号分隔 | bse、release |
| 间隔 | 清理间隔(分钟) | 两次运行之间的分钟数,1–10 080 | 60 |
标签为 1 到 64 个字母、数字或字符 _ . : -。
如何选择构建
- 服务器按发布时间对每个计数器的构建排序,最新的在前。该顺序不是版本的 SemVer 顺序。
- 计数器取决于分组。使用“包和渠道”时,构建会针对它携带的每个已配置渠道标签分别计数,按包(
group/name)计算。没有已配置标签的构建会进入该包的一个共享计数器,使用默认 N。使用“包”时,每个包有一个计数器。使用整个仓库时,所有构建共享一个计数器。包名忽略大小写,标签不忽略。 - 如果构建属于其所属的任一计数器的最近 N 个,它就会被保留。
- 比最小年龄更年轻的构建会保留。
- 带有受保护标签的构建会保留。它的标签来自当前注解,或在没有注解时来自上传。受保护的构建仍然参与排序,因此保留的数量可能高于 N。
当仍有东西需要某个构建时,它绝不会被删除:
- 外部服务持有对它的引用。
- 某个文件路径(当前或来自历史记录)使用它。
- 另一个构建(现在或历史记录中)将它列为附件。
- 它被晋级到某个阶段。请先移除该阶段。
- 某个容器镜像、Git LFS 或 npm 条目使用它。
删除构建是逻辑上的:它会离开列表,新的下载会以 404 失败。字节稍后在物理清理中离开磁盘。包版本保持预留,因此同一版本无法再以其他内容发布。
安全地启用策略
先预览,再启用。预览会显示已保存的策略将删除什么,并且不会删除任何内容。
- 使用具有这四个动作的密钥连接,并打开该仓库的存储面板。
- 设置各字段,让 启用自动清理 保持关闭。选择 保存策略。
- 选择 预览已保存的策略。列表显示已保存的策略在一次批次中将删除的最多 100 个构建。如果还有更多候选,控制台会说明。
- 如果列表正确,勾选 启用自动清理 和确认项 我了解,保存已启用的策略即表示授权自动删除。,然后再次保存。这需要
artifact.delete。
说明:
- 预览显示的是某一时刻。策略运行时,它会重新排序并再次检查依赖关系。
- 策略保存时会带有修订版本。如果其他人更改了它,请重新加载并再次保存。
- 重新加载设置和用量 会重新加载设置和用量。
如何运行
负责写入的 API 进程(不是读取网关)每 60 秒检查一次,并处理最多 20 个到期的策略。一个批次最多删除 100 个构建。如果还有候选,下一个批次在一分钟后开始。否则下一次运行在间隔之后到来。计划保存在数据库中,重启后仍然存在。
你也可以通过 API 操作 runStoragePolicy 自行运行一个批次。用量、预览和事件在同一个存储 API 参考中有对应的操作。
物理清理
删除制品(由人或策略执行)只会将它从目录中移除。物理清理会在后台把它的字节从磁盘移除,不停止 API、工作进程或读取网关。它还会:
- 取消已过期但未完成的上传,并移除它们的分片。
- 移除已完成上传的临时分片。
它不选择要删除的构建。它只移除已经删除或取消的内容。
物理清理默认关闭,并且按仓库设置。 请在你使用的每个仓库中开启它。在此之前,已删除的文件、过期的上传以及已完成上传的分片都会留在磁盘上,并且配额会把已删除的文件计入。
设置
在仓库的面板中,打开 物理清理:
| 设置 | 控制台字段 | 含义 | 默认值 | 范围 |
|---|---|---|---|---|
| 启用 | 启用后台清理 | 开启后台清理 | 关闭 | |
| 宽限期 | 删除后的宽限期(小时) | 已删除文件在磁盘上保留多长时间,以小时计 | 24 | 0–8760 |
| 批次 | 每批文件数 | 一个批次处理的文件数 | 25 | 1–100 |
| 间隔 | 批次间隔(秒) | 批次之间的秒数 | 60 | 5–86 400 |
| 延迟 | 文件间延迟(毫秒) | 文件之间的暂停毫秒数 | 50 | 0–1000 |
选择 应用设置 以应用它们。更改立即生效。如果你关闭清理,它会在当前文件之后停止。请求执行一批 会请求尽快执行一个批次,它不会立即删除。选择 刷新清理状态 查看上一个批次的结果。
宽限期不是回收站。值为 0 时,文件一旦被删除且没有读取者打开它,就可以立即离开。Arkvory 无法恢复已删除的制品。
清理会做什么、会跳过什么
- 它只移除已取消或已删除且超过宽限期的文件。它会再次检查没有东西使用它们:没有引用、文件路径历史记录或附件历史记录。
- 正在进行的下载、正在写入的上传,以及正在运行的备份所需的文件,会让清理跳过该文件。下一个批次会再次尝试。上一次结果会显示它处理、跳过和失败了多少文件,以及释放了多少字节。
- 配额和逻辑容量只有在文件从磁盘移除后才会释放。
- 批次受批次大小和延迟限制,这会降低磁盘负载。它不保证严格的磁盘吞吐量,也无法承诺对其他请求的延迟零影响。
- 清理在写入端 API 中运行,每个数据库一次。写入端每 5 秒检查一个到期的仓库。没有正在运行的写入端,就不会清理任何内容。
- 只有在更新了每个 Arkvory 进程(包括网关和工作进程)之后,才启用清理。没有清理协议的旧进程会让清理推迟它的工作。
删除制品
你可以手动删除一个已发布的制品。你需要对该仓库具有 artifact.delete。
- 在 制品详情 中打开该制品,找到 删除制品。
- 选择 检查依赖项。控制台会显示仍有谁在使用该制品。如果有东西阻止删除,你必须先移除该依赖。
- 粘贴该制品的 ID 以确认,然后选择 删除此制品。
以这种方式删除不会检查受保护标签,因为对象是你自己选择的。依赖关系始终会被检查。删除之后:
- 制品会离开列表和搜索结果。新的下载以 404 失败。已经在运行的下载可以完成。
- 包版本保持预留。
- 字节会留在磁盘上,直到物理清理在宽限期后移除它们。
- 你无法在控制台或 API 中撤销它。
对于大量制品,API 提供 previewRetention 和 applyRetention。预览会列出在某个日期之前发布的候选及其阻止原因。应用只删除你传入的 ID,每次调用最多 100 个,并为每个 ID 返回结果:deleted、already_deleted、protected、changed、not_eligible 或 not_found。请检查每个结果,而不仅仅是 HTTP 状态。
存储诊断与事件
警告、错误和存储事件 部分列出仓库中发生的事件,最早的在前,每页 100 个。选择 加载后续事件 查看下一页。读取它需要 diagnostics.read。API 操作是 getStorageEvents,可按级别(info、warning、error)过滤。
| 事件 | 级别 | 含义 |
|---|---|---|
storage.policy_updated | info | 保留策略已保存 |
retention.completed | info | 一个批次删除了构建。事件包含数量 |
retention.failed | error | 自动删除停止,例如因为授权密钥被撤销 |
cleanup.configured | info | 清理设置已保存 |
cleanup.completed | info or error | 一个清理批次处理、跳过或失败于某些文件。它列出数量和释放的字节 |
capacity.normal、capacity.warning、capacity.critical、capacity.exceeded、capacity.unlimited | info、warning 或 error | 配额状态发生变化 |
| HTTP 错误码 | warning 或 error | 受管密钥对此仓库的一次请求失败。事件保留请求 ID、路由和状态 |
历史记录是有界的:每个仓库 1000 个事件,总共 20 000 个,最旧的会被丢弃。这是尽力而为的诊断,而不是保证投递的日志。请及时导出你需要的内容,并使用服务器日志作为长期证据。参见监控。
面板还会显示用量:已发布的字节、未完成的上传、等待清理的字节,以及相对于配额的总量。API 操作是 getStorageUsage。
磁盘写满时
迹象:上传失败,返回 HTTP 507 和原因 storage_full,GET /health/ready 显示 writable: false,或者操作系统报告没有可用空间。下载继续工作。在你释放空间后,客户端可以续传它们的上传。
- 找出原因。 检查存储卷、数据库卷和备份存储卷的可用空间。比较存储面板中的用量数字。较大的“等待清理”数字意味着已删除的数据仍在磁盘上。较大的“未完成上传”数字意味着被放弃的上传。
- 运行清理。 如果清理已关闭,请在每个仓库中开启它,并使用较短的宽限期,例如 0(如果你接受已删除文件立即离开)。选择 请求执行一批。它还会移除已完成上传的临时分片和过期的上传。等待各批次并读取上一次结果。清理会跳过正在使用的文件,因此请重复执行。
- 删除你不需要的内容。 应用保留策略,或删除制品。只有在清理移除字节之后,这才会释放空间。
- 增加空间。 扩展卷或磁盘。如果备份存储或其他数据与该卷共用,请把它们移出该卷。
- 检查恢复情况。 空间释放后,
writable会恢复为true,上传重新工作。
不要手动删除 blobs/、staging/ 或 parts/ 中的文件:这会破坏数据库与磁盘之间的联系。如果预留对你的日志和同一卷上的数据库来说太小,请提高 ARKVORY_STORAGE_RESERVE_BYTES。
如果上传反而以原因 storage_quota 或 catalog_limit 失败,那么问题不在磁盘。请提高配额或全局限制,或者删除数据。
限制
- 保留策略只处理已注册的 UPack 构建。它绝不会移除其他文件。
- 保留排序依据是发布时间,而不是版本号。
- 存储、配额和清理需要明确的服务密钥动作。密码账户和恢复密钥不具备它们。
- 物理清理默认关闭,并按每个仓库设置。
- 已删除的制品无法恢复。请从备份恢复数据。参见备份。
- 镜像仓库不运行存储策略。参见镜像。
- 存储必须是本地文件系统。不支持网络共享或多个存储后端。