一个周末的意外

一通改变轨迹的电话

那是一个平常的周六下午,我正在家里打游戏。

手机响了,是我大学室友老张。

「兄弟,有没有兴趣来我公司帮忙?我们消息通知系统崩了,CTO 说再搞不好就要砍掉这个功能。」

「什么情况这么严重?」

「我们做了个社交 App,用户增长很快,但是通知系统跟不上。用户抱怨收不到消息,或者同一消息重复推送 5 次,还有半夜被通知轰炸投诉的……」

他顿了顿,「我们后端就两个人,都不太懂推送,你之前不是做过类似的项目吗?」

我犹豫了一下。当时我在一家大厂做业务开发,每天写 CRUD,技术成长有限。而老张的创业公司虽然小,但用户增长很快,正好能接触核心技术。

「待遇怎么样?」

「比你现在高 30%,还有期权。」

「我周一去面试。」

面试那天

周一,我来到老张的公司。技术负责人老王介绍了情况:

  • App 叫「圈内」,主打兴趣社交,50 万用户,日活 8 万。
  • 通知系统是离职同事写的,只留了几个文档。
  • 现在问题越来越多:推送延迟、重复推送、半夜打扰、没有偏好设置。

他列出的问题:

  1. 推送延迟:用户发消息后,接收方要等 5-10 秒才能收到。
  2. 重复推送:同一条消息有时推送 3-5 次。
  3. 半夜打扰:凌晨 3 点还推送促销消息。
  4. 没有偏好设置:用户无法关闭不想收的通知类型。

旧系统的真相

「现在的通知系统是什么架构?」我问。

老王苦笑:「其实就是一个 PHP 脚本,每分钟轮询数据库,把未发送的消息通过极光推送发出去。」

「每分钟轮询?那延迟应该在 1 分钟以内,怎么会 5-10 秒?」

问题出在数据库:notifications 表存了所有待发送通知,脚本每次查 1000 条,发送后标记已发送。但表里有 200 万条数据、索引设计得很烂,每次查询要 8-9 秒,更新状态又是一次慢查询。

旧系统的轮询链路

crontab 每分钟触发 PHP 脚本

全表扫描查询待发送通知

步骤 1 · 动作200 万条,8-9 秒

通过极光推送发送

步骤 2 · 动作外部服务,可能慢

标记为已发送

步骤 3 · 动作又是一次慢查询

超时则并发重复

步骤 4 · 判断crontab 再次触发
延迟高、重复推送、不可扩展

这哪是通知系统,这是定时炸弹。

一句话

一门课从一个真实的故事开始:一家创业公司因通知系统「将死」而急需重构。这个故事里的每个问题——延迟、重复、打扰、无偏好——都会在后面的章节被逐一解决。

发现内容有问题?

告诉我们哪里需要改进。