系统设置
自动清理
自动清理
作为一个处理大量请求的 AI API 代理平台,Claude Code Hub 会产生大量的日志数据、临时文件和缓存信息。如果没有适当的清理机制,这些数据会无限累积,导致存储耗尽、性能下降和运营成本增加。
自动清理系统为跨多种数据类型的管理数据保留提供了一个全面的、生产级的解决方案。它通过可配置的策略和自动化调度处理消息请求日志、端点探测日志、临时文件和内存缓存。
为什么自动清理很重要
如果没有自动化清理,您的部署将面临几个风险:
存储耗尽。message_request 表存储了每个 API 请求的详细记录。在高流量环境中,该表每天可能增长数百万行,最终消耗所有可用的数据库存储。
性能下降。大表会减慢查询速度,增加备份时间,并使数据库维护操作更具破坏性。随着表大小的增长,索引的效率会降低。
成本膨胀。云存储成本随数据量线性增加。保留日志的时间超过必要长度会直接影响您的基础设施预算。
合规风险。许多数据隐私法规要求在特定的保留期后删除个人数据。保留日志超过必要期限可能违反这些要求。
自动清理系统通过多种互补机制协同工作,解决这些问题,确保您的部署保持精简和高效。
清理机制概览
Claude Code Hub 实现了四种不同的清理机制,每种机制针对特定类型的数据:
| 机制 | 目标数据 | 调度 | 配置 |
|---|---|---|---|
| 消息请求清理 | message_request 表中的 API 请求日志 | 基于 Cron,通过 Bull 队列 | 数据库设置 |
| 端点探测日志清理 | 健康检查日志 | 24 小时间隔 | 环境变量 |
| 临时文件清理 | 数据库备份/恢复临时文件 | 1 小时间隔 | 硬编码默认值 |
| 缓存清理 | 内存会话和供应商缓存 | 60 秒间隔 | 硬编码默认值 |
每种机制独立运行,允许您根据特定要求调整保留策略。
消息请求日志清理
主要的清理机制针对 message_request 表,该表存储了系统处理的每个 API 请求的详细记录。这是数据密集程度最高的组件,需要仔细配置。
运作原理
消息请求清理使用 Bull(一个基于 Redis 的队列系统)进行可靠的任务调度和执行。当您启用自动清理并配置调度计划时,系统会创建一个以指定间隔执行的可重复任务。
清理过程遵循以下步骤:
任务调度。系统从数据库读取您的配置,并创建一个带有 cron 表达式的 Bull 任务,定义清理运行的时间。
条件构建。根据您的保留设置,系统计算一个截止日期。早于此日期的数据记录将被视为可删除。
批量删除。系统使用 PostgreSQL 的公共表表达式 (CTE) 配合
FOR UPDATE SKIP LOCKED以可配置的批次删除记录,以避免阻塞并发操作。进度记录。每次批量删除都会被记录,允许您监控清理进度和性能。
配置选项
通过管理仪表盘中的系统设置或通过 API 配置消息请求清理:
启用自动清理。激活或停用整个清理机制的主开关。禁用时,所有计划的清理任务都将从队列中移除。
保留天数。定义消息请求记录的保留时长。超过此天数的记录将被删除。有效范围为 1 到 365 天。默认值为 30 天。
清理计划 (Cleanup schedule)。定义清理任务执行时间的 cron 表达式。默认值为 0 2 * * *(每天凌晨 2:00)。常见的备选项包括:
| 计划 | Cron 表达式 | 使用场景 |
|---|---|---|
| 每天凌晨 2 点 | 0 2 * * * | 默认,低流量时段 |
| 每天午夜 | 0 0 * * * | 替代低流量时段 |
| 每周日凌晨 3 点 | 0 3 * * 0 | 较小规模部署的每周清理 |
| 每 6 小时 | 0 */6 * * * | 高流量系统的激进清理 |
| 每小时 | 0 * * * * | 紧急清理模式 |
批次大小 (Batch size)。每次批量操作删除的记录数。较大的批次完成速度更快,但持有锁的时间更长。有效范围为 1,000 到 100,000。默认值为 10,000。
批量删除策略
清理服务使用先进的 PostgreSQL 特性来实现高效、非阻塞的删除:
WITH ids_to_delete AS (
SELECT id FROM message_request
WHERE created_at < $cutoff_date
ORDER BY created_at ASC
LIMIT $batch_size
FOR UPDATE SKIP LOCKED
)
DELETE FROM message_request
WHERE id IN (SELECT id FROM ids_to_delete)
这种方法提供了几个好处:
- 原子操作。CTE 在单个查询中选择并删除记录,避免了竞态条件。
- 非阻塞。
FOR UPDATE SKIP LOCKED允许清理操作跳过被其他事务锁定的行,防止阻塞并发插入。 - 有序删除。
ORDER BY created_at ASC首先删除最早的记录,这对于 B 树索引更有效。 - 可配置的吞吐量。批次大小平衡了删除速度与锁定持续时间。
在批次之间,系统会暂停 100 毫秒,以减少锁竞争并给其他操作进行的机会。
端点探测日志清理
供应商端点健康检查生成的探测日志存储在 provider_endpoint_probe_logs 中。这些日志记录了针对每个配置的端点执行的定期健康检查结果。
与消息请求清理的主要区别
端点探测日志清理与消息请求清理在以下几个方面有所不同:
- 基于环境的配置。通过环境变量而非数据库设置进行控制。
- 分布式锁。使用基于 Redis 的领导者锁 (leader locks),以确保在多实例部署中只有一个实例运行清理任务。
- 固定间隔。每 24 小时运行一次,而不是基于可配置的 cron 计划。
配置
在您的部署中设置以下环境变量:
# 探测日志保留天数(默认:1)
ENDPOINT_PROBE_LOG_RETENTION_DAYS=7
# 每批删除的记录数(默认:10000)
ENDPOINT_PROBE_LOG_CLEANUP_BATCH_SIZE=5000
清理任务在 CI 环境中 (CI=true) 会自动跳过,以避免干扰测试运行。
领导者锁模式 (Leader lock pattern)
在具有多个 Claude Code Hub 实例的分布式部署中,领导者锁模式确保只有一个实例执行清理:
- 每个实例尝试获取一个带有 5 分钟 TTL(生存时间)的 Redis 锁。
- 只有成功获取锁的实例才会继续执行清理。
- 清理完成(或失败)后,锁将被释放。
- 如果持锁者崩溃,TTL 确保锁最终过期,允许另一个实例接管。
这种模式防止了重复的清理工作并减轻了数据库负载。
临时文件清理
数据库备份和恢复操作会生成需要清理的临时文件。临时文件管理器提供三重保护策略:
- 正常清理。操作成功完成后立即删除文件。
- 异常清理。操作期间发生错误时删除文件。
- 定期清理。计划任务会移除前两种机制未清理掉的陈旧文件。
运作原理
系统维护一个内存中的 Map,跟踪所有活动的临时文件。创建文件时,会记录其创建时间戳和用途(导入或导出)。操作完成或失败时,文件将被清理并从跟踪中移除。
定期清理任务默认每小时运行一次,移除超过 6 小时的文件。这作为由于崩溃或意外错误而导致的孤立文件的安全网。
缓存清理
会话和供应商的内存缓存使用基于 TTL 的过期机制。过期条目在被访问时会自动移除,但定期清理任务可确保即使是永远不再被访问的条目也能回收内存。
缓存清理每 60 秒运行一次,扫描并移除以下各项中的过期条目:
- 活跃会话缓存
- 会话详细信息缓存
- 供应商缓存
这可以防止具有高会话流动率的长运行部署中出现内存泄漏。
手动清理 API
管理员可以通过 REST API 触发手动清理,适用于需要立即删除数据或根据特定条件进行定向删除的情况。
端点
POST /api/admin/log-cleanup/manual
请求体
{
"beforeDate": "2024-01-01T00:00:00Z",
"afterDate": "2023-01-01T00:00:00Z",
"userIds": [1, 2, 3],
"providerIds": [1, 2],
"statusCodes": [500, 502, 503],
"statusCodeRange": { "min": 400, "max": 499 },
"onlyBlocked": false,
"dryRun": true
}
参数
| 参数 | 类型 | 描述 |
|---|---|---|
beforeDate | string (ISO 8601) | 删除此日期之前创建的记录 |
afterDate | string (ISO 8601) | 删除此日期之后创建的记录 |
userIds | number[] | 仅删除特定用户的记录 |
providerIds | number[] | 仅删除特定供应商的记录 |
statusCodes | number[] | 仅删除具有特定 HTTP 状态码的记录 |
statusCodeRange | object | 删除状态码在范围(最小值,最大值)内的记录 |
onlyBlocked | boolean | 仅删除被阻止/拦截的请求 |
dryRun | boolean | 预览模式:仅统计匹配的记录而不执行删除 |
必须指定至少一个条件。尝试在没有任何条件的情况下运行清理将返回错误,以防止意外删除所有记录。
响应
{
"success": true,
"totalDeleted": 15000,
"batchCount": 2,
"durationMs": 1250
}
授权
手动清理需要管理员权限。非管理员用户的请求将收到 401 Unauthorized 响应。
监控与可观测性
清理系统为监控和调试提供了全面的日志记录。所有清理事件都通过结构化数据记录,包括操作标识符、记录计数和耗时信息。
关键日志操作
| 操作 | 描述 |
|---|---|
cleanup_queue_initialized | 清理队列成功初始化 |
auto_cleanup_scheduled | 根据配置调度了新的清理任务 |
cleanup_job_start | 清理任务开始执行 |
cleanup_job_complete | 清理任务成功完成 |
cleanup_job_failed | 清理任务在重试后失败 |
log_cleanup_batch | 批量删除完成 |
log_cleanup_dry_run | 预览模式完成,显示预估计数 |
Bull Board 监控
清理队列与 Bull Board 集成,提供了一个用于监控任务状态的 Web 界面。访问 Bull Board 端点 /admin/queues 可以:
- 查看排队中、活动中、已完成和已失败的任务
- 检查任务详情和错误堆栈跟踪
- 手动触发或重试任务
- 监控任务执行历史
需监控的指标
对于生产部署,请跟踪以下指标:
清理任务持续时间。突然增加可能表明表膨胀或锁竞争。正常的持续时间随删除的记录数而变化。
每个任务删除的记录数。跟踪数据保留模式并帮助估算存储增长。
失败任务计数。非零值表示配置问题、数据库问题或 Redis 连接问题。
临时文件清理计数。意外增加可能表明备份/恢复操作中存在文件泄露。
最佳实践
推荐的生产配置
对于大多数生产部署:
# 环境变量
ENDPOINT_PROBE_LOG_RETENTION_DAYS=7
ENDPOINT_PROBE_LOG_CLEANUP_BATCH_SIZE=5000
数据库设置(通过管理 UI):
- 启用自动清理:
true - 保留天数:
30(根据合规要求调整) - 计划计划:
0 2 * * *(每天凌晨 2 点) - 批次大小:
10000(对于高流量系统可降至5000)
选择保留期
在设置保留期时平衡以下因素:
合规要求。某些法规强制要求某些类型数据的最小或最大保留期限。
调试需求。较长的保留期有助于调查不会立即显现的问题。建议为生产环境调试保留至少 30 天。
存储成本。计算每天保留的成本并相应设置期限。
查询性能。即使有适当的索引,具有数亿行的表也可能会经历较慢的查询。
处理高流量场景
对于每天处理数百万个请求的部署:
减小批次大小。较小的批次持有锁的时间更论,减少了对并发操作的影响。
在低流量时段调度。使用 cron 计划在请求量最低时运行清理。
考虑更频繁的清理。与其每天清理 30 天的数据,不如考虑每小时清理 1-2 天的数据以分散负载。
监控表膨胀。PostgreSQL 的 MVCC 可能会因大量删除而导致表膨胀。确保正确配置了自动清理 (autovacuum) 或安排定期的
VACUUM操作。
故障排除
清理任务因超时错误失败
症状:任务因数据库超时错误失败,或完成时间越来越长。
解决方案:
- 减小
cleanupBatchSize以缩短锁定持续时间 - 检查表膨胀情况,必要时运行
VACUUM - 验证数据库连接池未耗尽
- 检查是否存在可能与清理锁冲突的长运行查询
清理任务未运行
症状:日志或 Bull Board 中未出现清理任务。
检查项:
- 验证系统设置中的
enableAutoCleanup是否设置为true - 确认设置了
REDIS_URL环境变量且 Redis 可访问 - 查看日志中的
schedule_auto_cleanup_error消息 - 检查
/admin/queues处的 Bull Board 以获取队列状态
清理后磁盘空间仍在增长
症状:即使清理报告成功,数据库存储使用量仍在增加。
检查项:
- 验证 PostgreSQL 的
VACUUM是否正在运行(自动或手动) - 检查表膨胀情况:
SELECT * FROM pg_stat_user_tables WHERE relname = 'message_request' - 如果膨胀严重,在维护窗口期间运行
VACUUM FULL(需要表级锁) - 检查其他表(如
provider_endpoint_probe_logs)是否在增长
多个实例同时运行清理
症状:日志显示清理任务在多个实例上同时运行,或出现重复的删除计数。
检查项:
- 验证所有实例都连接到同一个 Redis 服务器
- 检查所有实例的 Redis 连接性
- 查看日志中关于领导者锁获取失败的记录
- 确保所有实例的
REDIS_URL保持一致
数据库迁移问题
症状:清理任务失败,并报错缺少列或表。
解决方案:
- 运行数据库迁移以确保架构是最新的
- 系统通过回退默认值优雅地处理某些迁移场景,但完整功能需要完整的架构
边界情况与安全特性
防止意外的全量删除
清理服务要求至少指定一个条件。如果您尝试在没有任何过滤器(无日期范围、无用户 ID、无状态码)的情况下运行清理,系统将返回错误:
Error: 未指定任何清理条件 (No cleanup conditions specified)
这可以防止意外删除所有记录。
故障不中断设计 (Fail-open design)
如果清理调度程序在应用程序启动期间初始化失败,错误会被记录,但不会阻止应用程序启动。这种“故障不中断”设计确保了清理配置错误不会导致服务中断。
但是,如果在首次访问清理队列时 Redis 不可用,则会抛出错误,因为没有 Redis 队列无法工作。
优雅降级
系统优雅地处理各种错误情况:
- 缺少 system_settings 表。返回回退的默认设置。
- system_settings 中缺少列。使用最小字段集并记录警告。
- Redis 领导者锁获取失败。跳过该实例的清理。
- 批量删除期间的清理错误。记录错误并停止当前清理任务。
软删除与硬删除
Claude Code Hub 对大多数实体(包括 message_request)实施软删除。记录具有 deleted_at 时间戳,并从查询中过滤掉。然而,清理过程执行的是硬删除,会从数据库中永久移除记录。
这种两阶段方法允许用户在 UI 中“删除”日志以立即保护隐私,同时管理员配置保留策略以进行存储管理。
总结
Claude Code Hub 中的自动清理系统提供了:
- 多层级方法。涵盖数据库日志、探测日志、临时文件和缓存。
- 灵活配置。主要清理采用数据库设置,探测日志采用环境变量。
- 弹性运营。故障不中断设计、错误处理、优雅降级。
- 分布式安全。领导者锁防止多实例部署中的冲突。
- 性能意识。配合
SKIP LOCKED的批量删除,可配置的批次大小。 - 全方位可观测性。全面的日志记录和 Bull Board 集成。
- 安全特性。预览模式、验证、防止意外删除。
配置平衡了合规要求、调试需求和存储限制的清理策略,以维持健康、高效的部署。
