最近每天都会做几道LeetCode Hot100题,突发奇想,使用AI做一个采集数据并展示出来的小功能,看一下哪些题目刷的人比较多(毫无疑问,two-sum一直稳居榜首),最终的页面能够实时看到在线人数前十的题目,并且能够看到每一道题最近7天的在线人数变化趋势。整个项目涉及数据采集、API 服务、存储和前端展示四个部分,分别部署在 Railway、Cloudflare Workers、Cloudflare KV/D1 和 Vercel 上。
由于使用的是cloudflare的免费额度,KV写入读取有限制,所以采集数据采取每2分钟上报一次,这样每天就只有720次写入,不超过免费额度。D1的写入读取也有相应的优化来满足要求。
整体架构
1 | ┌─────────────┐ WebSocket ┌──────────────┐ Push API ┌─────────────────────┐ |
整个数据流向:采集脚本通过 WebSocket 连接 LeetCode 获hot100在线人数数据,调用 Cloudflare Workers 的 Push 接口写入存储,前端页面从 Workers 读取数据并展示。
数据采集 — Railway
采集脚本部署在 Railway 上,通过 LeetCode 的 WebSocket 接口实时获取在线人数数据。选择 WebSocket 而不是传统的 HTTP 轮询,主要是因为可以实时拿到在线人数数据,减少不必要的请求。
Railway 作为采集服务的运行平台,优势在于:
- 支持持久运行的后台进程,适合维持 WebSocket 长连接
- 部署简单,直接关联 Git 仓库即可自动部署
- 有免费额度,对于这种轻量采集任务完全够用
采集脚本拿到数据后,通过 HTTP 请求调用 Cloudflare Workers 提供的 Push 接口上传数据。
API 服务与存储 — Cloudflare Workers + KV + D1
Cloudflare Workers 负责提供 API 服务,主要包含两个功能:
- Push 接口:接收采集脚本上传的数据,写入 KV 和 D1
- Query 接口:供前端页面查询在线人数数据
存储层采用 KV 和 D1 配合使用,各有分工:
KV(汇总数据):存储聚合后的统计信息,比如最新的100道题的在线人数。KV 的读取速度极快,非常适合这种高频读取、低频写入的汇总数据。
D1(明细数据):存储每道题目每个时刻的在线人数。D1 是 Cloudflare 的 SQLite 数据库,支持 SQL 查询,适合按条件筛选和排序题目列表。
这种分层存储的设计思路是:前端加载看板时,先从 KV 读取最新数据来渲染盘行榜,需要查看具体题目的在线人数历史数据时候再查询D1数据库。保证页面加载速度。
前端看板 — Vercel
前端使用纯 HTML/CSS/JavaScript 实现,没有引入框架,保持轻量。部署在 Vercel 上,访问地址:https://hot100-dashboard.vercel.app/
页面主要展示:
- 在线人数前十的题
- hot100的所有题目
- 每道题历史7天在线人数折线图
选择 Vercel 部署纯静态页面的原因很简单:零配置、自动 HTTPS、全球 CDN、部署速度快。
为什么选择这套架构
这套架构的核心思路是把不同职责分散到最适合的平台上:
| 组件 | 平台 | 原因 |
|---|---|---|
| 数据采集 | Railway | 需要持久运行的后台进程 |
| API + 存储 | Cloudflare | Workers 冷启动快,KV/D1 与 Workers 无缝集成 |
| 前端展示 | Vercel | 静态站点部署体验好 |
每个服务都有免费额度,整套方案的运行成本为零。同时各组件之间通过 HTTP 接口通信,耦合度低,任何一部分都可以单独替换。
小结
这个项目虽然功能不复杂,但涉及到数据采集、API 设计、存储选型、前端展示等多个环节,是一个比较完整的全栈小项目。Cloudflare Workers + KV + D1 的组合确实很适合这种轻量级 API 服务场景,开发体验不错。