一个人运维五个项目的生存指南

一个人运维五个项目的生存指南

风格:阮一峰(技术科普体)


一、引言

我用 AI 辅助开发了五个个人项目:番茄钟 App(iOS + Spring Boot 后端)、ClawChat(聊天机器人)、OpenClaw(AI agent 框架)、喝水提醒、以及一套数字资产知识体系。

过去一周(3/1–3/6),其中两个项目接连出了线上事故。修完之后,我把教训整理成了六条原则。这篇文章是对它们的系统性梳理。

如果你也是一个人在做 side project,尤其是有后端服务在跑的那种,希望这些经验对你有用。


二、发生了什么

先说事实。

事故一(3/5):ClawChat 的上游服务 OpenClaw 不可达,HTTP 请求直接超时。系统没有任何回退机制,给用户返回一个固定的“暂时不可用”文案。根因是 launchd 启动时 PATH 环境变量与手动启动不同,导致调用了错误版本的二进制文件。

事故二(3/6):番茄 App 的 token 过期,触发重新登录,App 在重登时清除了本地缓存——包括 6 条尚未同步到服务器的番茄记录。与此同时,后端也出了问题:一条慢 SQL 引发锁等待,Tomcat 的 120 个线程全部阻塞,客户端重试请求不断涌入,连接池耗尽,整个服务雪崩。

两次事故的表象不同,但根因相同:只设计了正常流程(happy path),没有处理失败流程。


三、原则一:失败路径的三条底线

失败路径不可能穷举——一条正常流程对应的异常分支是指数级的。但以下三条底线成本低、收益高,值得作为硬性要求。

1. 用户数据不能静默丢失

凡是涉及用户创建的数据,失败时至少做到三件事:

  • 不删、不覆盖:未同步的数据是用户资产,不是临时缓存
  • 给用户一个可见的提示:不允许静默失败
  • 本地留一份兜底:关键数据有导出或恢复入口

反面案例:番茄 App 的 pendingSync 数据在重登时被清除,6 条记录永久丢失。

2. 上游变慢时不要把自己拖死

不需要完美的熔断体系,但至少做到:

  • 设 timeout:不要用框架默认的无限等待
  • 设 max inflight:不要让请求无限堆积
  • 客户端重试要有退避:5xx 或超时期间不做高频平推

反面案例:1 核机器用 120 线程默认值,慢 SQL + 客户端重试直接雪崩。

3. 关键路径加一个 fallback

不需要完美的降级方案,只要“不是直接给用户一个死胡同”:

  • HTTP 不可达 → 自动回退 CLI 调用
  • 主数据源失败 → 展示本地缓存 + 状态标记
  • 关键接口超时 → 返回降级响应而非空白

正面案例:ClawChat 修复后增加了 OPENCLAW_CLI_FALLBACK_ENABLED,HTTP 失败时自动回退 CLI。


四、原则二:小机器要主动校准参数

这是一个容易被忽略的盲区。框架的默认配置面向多核服务器设计,而大多数个人项目跑在 1 核 2GB 的小机器上。

以下是单核机器的关键参数速查表:

参数 框架默认值 单核建议值
Web 线程池(max-threads) 200 4–8
DB 连接池(maximum-pool-size) 10 3–5
请求超时(timeout) 无限/30s 10–30s
等待队列(accept-count) 100 16–32
连接泄漏检测(leak-detection) 关闭 10–15s

核心原则很简单:默认值不是安全值。 把运行参数从“默认没碰过”变成“我看过、我定的”,这件事十分钟就能做完,但能防住一次雪崩。

部署新服务时的检查项:

  1. 确认目标机器 CPU 核数和内存
  2. 按速查表设置线程池、连接池、超时参数
  3. 不使用框架默认值,显式写入配置文件
  4. 首次部署后观察 30 分钟 CPU 和内存水位

五、原则三:自愈优先于监控

一个人运维时,告警的价值是有限的。告警来了你可能在睡觉、开会、或者在另一个项目的深度工作里。你不可能 24 小时盯着。

所以正确的优先级是:先做自愈,再做监控。

场景 监控思路 自愈思路
进程挂了 发通知,等人来重启 systemd/launchd 自动重启
请求堆积 发通知,等人来限流 内置 max inflight,自动拒绝
上游不可达 发通知,等人来排查 自动 fallback(如 CLI 回退)
证书快过期 发通知,等人来续期 certbot 自动续期
连接池满 发通知,等人来杀连接 连接超时 + 泄漏检测自动释放

给 AI 提运维需求时,建议默认先问:这个能不能做成自愈的? 而不是先问“怎么监控”。

此外,减少运维面积本身也很重要。最有效的运维优化不是“更好地监控”,而是“少一个要监控的东西”。每上线新功能前问自己:能不能不加新服务?能不能复用已有的?


六、原则四:数据备份要设计驱动,不要事故驱动

事故之后我手写 SQL 把丢失的 6 个番茄补录回去了。补录之所以能成功,是因为三个条件碰巧满足:我还记得做了什么、数据量很小、我会写 SQL。这三个条件任意一个不满足,数据就永久消失。

盘点下来,我的数据保护是事故驱动的——出过事的就备份了,没出过事的就裸奔。

数据 有备份 能恢复
番茄记录(阿里云 MySQL)
ClawChat 对话(腾讯云 MySQL)
digital-assets 文档 ✅(Git)
OpenClaw 配置(本机)

空白格就是风险。

从“有备份”到真正安全,有三级台阶:

  1. 补齐空白:有 > 无。先把裸奔的数据备份起来
  2. 确认有效:能恢复 > 有备份。定期做恢复演练,确认备份不是坏的
  3. 自治运转:备份任务自身有健康检查,失败自动重试,无需人工干预

手动补录是最后手段,不应该是常规手段。


七、原则五:AI 说“完成了”需要分层验收

AI 给番茄后端写了一个 TimeConfig 修复,测试通过,AI 说“修复完成”。我信了,直接部署。结果发现改了一半。

问题不是 AI 能力不行,而是“修复完成”和“线上真的好了”之间缺少验收环节。

验收不是只能人来做。AI 和人应该各守不同层次:

层次 谁做 验什么
L1 代码正确性 AI 类型检查、lint、单元测试
L2 功能可用性 AI 冒烟测试:API 能响应、数据能存取
L3 线上真实性 AI 部署后自动验证,确认修复在线上生效
L4 体验判断 交互顺不顺、流程合不合理

当前的缺口在 L3。建议每个项目的部署流程最后一步,自动跑一组最小验证。例如:

  • 番茄后端:调一次 /api/current-pomodoro,确认 200 且延迟 < 500ms
  • ClawChat:发一条测试消息,确认收到回复且状态 SUCCESS

以后让 AI 做修复时,在需求最后加一句:“修完之后,写一个部署后自动验证脚本,确认修复在线上真的生效。”


八、原则六:让知识自己生长

这一周我还做了一件事:审视自己的知识沉淀体系。

3 月 1 日我建立了每日自动生成知识卡片的机制。运行一周后发现三个问题:

  1. 输入源不完整:最有价值的学习发生在 OpenClaw 对话里(故障排查、修复决策),但卡片生成流程捕捉不到
  2. 只做单日提炼:同一类问题反复出现(如 launchd PATH 差异),但系统无法跨天识别模式
  3. 知识存了不消费:卡片存到目录后没有任何流程引用它

对应的改进是建立三级进化节奏:

级别 频率 产出 目标
微进化 每日 1 张知识卡片 捕捉当天最有价值的认知点
大进化 每周 原则性文档 跨天模式识别,提炼结构性认知
超进化 每月 知识体系重构 淘汰过时认知,合并散点为专题

微进化产出原材料(卡片),大进化产出结构(原则)。没有微进化,大进化没有素材;没有大进化,微进化只是日记。

本文就是一次“大进化”的产出——它不可能从任何单张卡片中生成。


九、检查清单

最后,如果你也在一个人运维个人项目,这里是一份可以直接用的检查清单。每个项目进入“运营期”(你开始依赖它的数据,开始给它写运维文档)时,花半天过一遍:

  • 所有用户数据写入路径:失败时是否保留?是否有提示?
  • 所有外部依赖调用:是否有 timeout?是否有 max inflight?
  • 关键链路:是否有至少一个 fallback?
  • 运行参数:是否按实际机器校准过(线程池、连接池、队列)?
  • 数据备份:是否覆盖所有重要数据?是否做过恢复演练?
  • 部署流程:是否有自动化的部署后验证?
  • 进程管理:挂了能不能自动重启?

过完之后再补代码,优先级比加新功能高。


十、小结

AI 让独立开发者拥有了以前小团队才有的开发速度,但也同时制造了以前小团队才会遇到的运维问题。

开发是一次性的,运维是永久性的。每上线一个新服务,就是签了一份永久运维合同。

速度是好事,但速度之后要主动补上被跳过的东西。六条原则——失败路径底线、容量基线、自愈优先、数据安全、分层验收、知识进化——本质上都是同一件事:让你的系统有能力在你不在的时候照顾好自己。

(完)