Skip to content

自适应扩展架构

概述

本文档说明 AI OSS Rank Worker 的自适应扩展架构,该架构能够自动适应项目数量增长,无需手动调整配置。

设计理念

核心目标

  1. 自动扩展:项目从 500 增长到 1000+ 时无需修改配置
  2. 一致性:无论项目数量多少,都在 20-24 小时内完成一轮同步
  3. 资源优化:自动平衡批大小与运行频率
  4. 可靠性:避免超时,确保每次运行都能成功完成

架构特点

  • 每小时运行一次(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);
}

算法说明

  1. 目标时间:20 小时内完成一轮同步(留 4 小时缓冲)
  2. 理想批大小总项目数 ÷ 20 向上取整
  3. 安全上限:最大 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),可以考虑:

  1. 提高 cron 频率(如每 30 分钟)
  2. 增加上限到 100(需要测试)
  3. 使用 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} 小时"

故障排查

问题:批大小看起来不合理

排查步骤

  1. 检查项目总数:
curl https://jimmysong.io/data/ai-projects-manifest.json | jq '.projectCount'
  1. 手动计算批大小:
Math.ceil(totalProjects / 20)  // 应该 ≤ 80
  1. 查看日志中的批大小:
wrangler tail | grep "Batch:"

问题:同步周期过长

可能原因

  1. 项目数量超过 2400(80 × 30)
  2. 某些项目处理特别慢
  3. GitHub API 限流

解决方案

  1. 增加 cron 频率:
crons = ["0,30 * * * *"]  # 每 30 分钟
  1. 或提高批大小上限(需要测试):
const MAX_PROJECTS_PER_RUN_CAP = 100;

问题:某些批次超时

排查步骤

  1. 查看失败的批次大小:
wrangler tail --status error
  1. 如果批大小接近 80,降低上限:
const MAX_PROJECTS_PER_RUN_CAP = 60;
  1. 检查慢速项目:
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+

现在您可以放心添加新项目,系统会自动适应!🚀