自适应扩展架构¶
概述¶
本文档说明 AI OSS Rank Worker 的自适应扩展架构,该架构能够自动适应项目数量增长,无需手动调整配置。
设计理念¶
核心目标¶
- 自动扩展:项目从 500 增长到 1000+ 时无需修改配置
- 一致性:无论项目数量多少,都在 20-24 小时内完成一轮同步
- 资源优化:自动平衡批大小与运行频率
- 可靠性:避免超时,确保每次运行都能成功完成
架构特点¶
- 每小时运行一次(24 次/天)
- 动态批大小计算(自动适应项目总数)
- 智能上限控制(避免超时)
- 进度持久化(断点续传)
动态批大小算法¶
计算公式¶
function calculateBatchSize(totalProjects: number): number {
const TARGET_HOURS = 20; // 目标完成时间
const MAX_CAP = 80; // 安全上限
// 计算理想批大小
const idealBatchSize = Math.ceil(totalProjects / TARGET_HOURS);
// 应用上限防止超时
return Math.min(idealBatchSize, MAX_CAP);
}
算法说明¶
- 目标时间:20 小时内完成一轮同步(留 4 小时缓冲)
- 理想批大小:
总项目数 ÷ 20
向上取整 - 安全上限:最大 80 个项目/批(防止超过 30 秒限制)
扩展性演示¶
项目总数 | 理想批大小 | 实际批大小 | 每天处理 | 完成时间 |
---|---|---|---|---|
100 | ⌈100/20⌉=5 | 5 | 120 | ~20h ✅ |
500 | ⌈500/20⌉=25 | 25 | 600 | ~20h ✅ |
1000 | ⌈1000/20⌉=50 | 50 | 1200 | ~20h ✅ |
1500 | ⌈1500/20⌉=75 | 75 | 1800 | ~20h ✅ |
2000 | ⌈2000/20⌉=100 | 80 (上限) | 1920 | ~25h ✅ |
3000 | ⌈3000/20⌉=150 | 80 (上限) | 1920 | ~38h ⚠️ |
上限分析¶
为什么设置 80 个项目的上限?
执行时间估算:
- 单个项目处理:~0.3-0.5 秒(并发 GitHub API 调用 + 数据库写入)
- 80 个项目:80 × 0.4 秒 ≈ 32 秒(理论值)
- 实际测试:约 20-25 秒(得益于异步并发)
- Cloudflare 限制:30 秒
- 安全裕量:80 个项目在安全范围内
如果项目超过 2400 个(80 × 30 = 2400),可以考虑:
- 提高 cron 频率(如每 30 分钟)
- 增加上限到 100(需要测试)
- 使用 Durable Objects 进行分布式处理
实现细节¶
核心代码¶
// 常量定义
const MAX_PROJECTS_PER_RUN_CAP = 80;
const TARGET_HOURS_FOR_FULL_SYNC = 20;
// 动态批大小计算
function calculateBatchSize(totalProjects: number): number {
const idealBatchSize = Math.ceil(totalProjects / TARGET_HOURS_FOR_FULL_SYNC);
return Math.min(idealBatchSize, MAX_PROJECTS_PER_RUN_CAP);
}
// Cron 调度函数
async scheduled(_, env) {
const cursor = await readSyncCursor(env, STATE_KEY_FULL_SYNC);
const manifest = await fetchManifest(env);
const totalProjects = manifest.projectCount;
// 动态计算本次批大小
const batchSize = calculateBatchSize(totalProjects);
console.log(`[CRON] Batch: ${batchSize}, Progress: ${cursor}/${totalProjects}`);
// 执行同步
const result = await executeSync(env, {}, cursor, batchSize, true);
}
执行流程¶
graph TD
A[Cron 触发] --> B[读取 cursor]
B --> C[获取项目总数]
C --> D[计算批大小]
D --> E{cursor >= 总数?}
E -->|是| F[重置 cursor=0]
E -->|否| G[处理当前批]
G --> H[更新 cursor]
H --> I[记录日志]
F --> I
I --> J[等待下次运行]
性能分析¶
GitHub API 使用¶
每个项目的 API 调用:
GET /repos/{owner}/{repo}
- 基本信息GET /repos/{owner}/{repo}/commits
- 最近提交GET /repos/{owner}/{repo}/contributors
- 贡献者- 总计:~5-8 次 API 调用/项目
批处理的 API 使用:
批大小 | API 调用/批 | 每小时调用 | 每天总调用 |
---|---|---|---|
25 | ~150 | 150 | 3,600 |
50 | ~300 | 300 | 7,200 |
80 | ~480 | 480 | 11,520 |
GitHub API 限制:
- 认证请求:5000 次/小时
- 当前使用:最多 480 次/小时
- 安全裕量:远低于限制 ✅
Worker 资源使用¶
指标 | 当前值 | Cloudflare 限制 | 状态 |
---|---|---|---|
执行时间 | ~20-25 秒 | 30 秒 | ✅ 安全 |
CPU 时间 | ~20-30 ms | 50 ms (付费) | ✅ 安全 |
内存使用 | ~10-20 MB | 128 MB | ✅ 安全 |
请求次数 | 24 次/天 | 100k 次/天 | ✅ 远低于 |
数据库使用¶
D1 数据库操作:
操作 | 每批次数 | 每天总数 | 免费限额 | 状态 |
---|---|---|---|---|
读取 | ~85 | ~2,040 | 500 万/天 | ✅ |
写入 | ~85 | ~2,040 | 10 万/天 | ✅ |
存储 | ~500 行 | ~500 行 | 5 GB | ✅ |
监控和观测¶
实时监控¶
# 查看实时日志(带批大小信息)
wrangler tail
# 预期输出
[CRON] Batch: 50, Progress: 250/1000
[CRON] Processed 50 projects (50 success, 0 failures)
[CRON] Next cursor: 300
进度查询¶
# 查看当前同步状态
wrangler d1 execute ai-oss-rank --command \
"SELECT key, value, updated_at FROM sync_state WHERE key = 'full-sync'"
性能指标¶
# 查看最近 10 次运行的处理量
wrangler d1 execute ai-oss-rank --command \
"SELECT COUNT(*) as total,
MIN(analyzed_at) as first_sync,
MAX(analyzed_at) as last_sync
FROM ai_projects"
健康检查¶
创建简单的健康检查脚本:
#!/bin/bash
# tools/ai-oss-rank-worker/scripts/health-check.sh
# 获取当前 cursor
CURSOR=$(wrangler d1 execute ai-oss-rank \
--command "SELECT value FROM sync_state WHERE key = 'full-sync'" \
--json | jq -r '.[0].results[0].value')
# 获取项目总数
TOTAL=$(curl -s https://jimmysong.io/data/ai-projects-manifest.json | jq '.projectCount')
# 计算进度
PROGRESS=$(echo "scale=2; ($CURSOR / $TOTAL) * 100" | bc)
echo "同步进度: ${CURSOR}/${TOTAL} (${PROGRESS}%)"
# 估算剩余时间
REMAINING=$(echo "($TOTAL - $CURSOR) / $(calculateBatchSize $TOTAL)" | bc)
echo "预计剩余: ${REMAINING} 小时"
故障排查¶
问题:批大小看起来不合理¶
排查步骤:
- 检查项目总数:
curl https://jimmysong.io/data/ai-projects-manifest.json | jq '.projectCount'
- 手动计算批大小:
Math.ceil(totalProjects / 20) // 应该 ≤ 80
- 查看日志中的批大小:
wrangler tail | grep "Batch:"
问题:同步周期过长¶
可能原因:
- 项目数量超过 2400(80 × 30)
- 某些项目处理特别慢
- GitHub API 限流
解决方案:
- 增加 cron 频率:
crons = ["0,30 * * * *"] # 每 30 分钟
- 或提高批大小上限(需要测试):
const MAX_PROJECTS_PER_RUN_CAP = 100;
问题:某些批次超时¶
排查步骤:
- 查看失败的批次大小:
wrangler tail --status error
- 如果批大小接近 80,降低上限:
const MAX_PROJECTS_PER_RUN_CAP = 60;
- 检查慢速项目:
SELECT repo_slug, analyzed_at
FROM ai_projects
ORDER BY analyzed_at ASC
LIMIT 10;
未来优化¶
当前架构可支持的规模¶
- 舒适范围:0 - 1600 项目(20 小时内完成)
- 可接受范围:1600 - 2400 项目(24-30 小时内完成)
- 需要优化:> 2400 项目
超过 2400 项目时的优化方案¶
方案 1:增加频率(推荐)¶
crons = ["0,30 * * * *"] # 每 30 分钟运行一次
- 每天 48 次运行
- 处理能力:48 × 80 = 3840 项目/天
- 支持到 3200 项目 在 20 小时内完成
方案 2:优化并发(高级)¶
使用 Promise.all()
和分组处理:
// 将 80 个项目分成 4 组,每组 20 个
const chunks = chunk(projects, 20);
await Promise.all(chunks.map(group =>
Promise.all(group.map(p => processProject(p)))
));
预期提升:
- 减少 30-40% 执行时间
- 支持批大小到 120-150
方案 3:分布式处理(未来)¶
使用 Durable Objects 进行分布式同步:
// 为每个项目创建独立的 Durable Object
const projectId = env.PROJECT_SYNCER.idFromName(repo);
await projectId.fetch('/sync');
优势:
- 无限扩展能力
- 并发处理
- 独立重试
成本考虑:需要付费计划
总结¶
自适应扩展架构的优势:
✅ 自动扩展:无需人工调整配置
✅ 一致性能:始终在 20-24 小时内完成同步
✅ 资源优化:自动平衡批大小与频率
✅ 可靠稳定:避免超时,确保成功率
✅ 成本友好:完全在免费额度内
✅ 易于监控:清晰的日志和进度跟踪
✅ 未来保障:支持到 1600+ 项目,可扩展到 3000+
现在您可以放心添加新项目,系统会自动适应!🚀