每次上线前,团队里总有人问:"还有啥要检查的?"然后大家七嘴八舌——跑测试没?备份做了?压测过了?监控接了?列出来一长串,但彼此之间是散的,容易漏,也容易在出了问题之后才想起来"诶,这个当时没做"。
其实上线前要操心的事,可以收拢成五个问题,顺着问一遍就不会乱:
代码有没有问题 → 数据会不会出问题 → 扛不扛得住 → 出问题能不能发现 → 出问题能不能撤回来
你可以把上线想象成"今天要把一辆车开上高速"。下面这五个问题,就是上高速前要过的五道关。
① 代码对不对?——车能不能开
先别上高速,先看看车本身有没有问题。对应到工程上就是:
- Code Review
- 单元测试
- 集成测试
- 回归测试
核心就一句:代码写得对不对?原来的功能有没有被我改坏?
很多线上事故不是新功能写错了,而是改 A 的时候把 B 带崩了。所以"回归"这一关不能省——核心链路的旧功能要再走一遍。
第一关记一句话:代码 → 能不能正常跑。
② 数据会不会丢?——车上的东西会不会丢
假设你上线要给用户表加一个字段:
user
├── id
├── name
└── age ← 新增加
生产数据库怎么办?你不能直接说"我先改一下生产库,应该没问题"。凡是涉及表结构、数据迁移的,至少要过这几步:
- 预发环境先跑一遍,确认脚本本身没错;
- 生产库提前备份,出问题能恢复;
- 新旧代码版本要能兼容,不能一上线老请求就报错;
- 迁移脚本要保证可重复执行(幂等),重复跑不会把数据搞乱。
大白话就是:数据库动了以后,数据会不会丢?
第一关记一句话:数据 → 会不会丢。这一关出问题往往最不可逆,所以备份和回滚预案必须提前就位,而不是出问题了才想。
③ 系统扛不扛得住?——高速堵不堵车
本地测试时接口表现很好:
1 个人访问:100ms
没问题。但生产环境可能是:
1000 个人同时访问
这时候可能直接:
CPU 100%
数据库连接耗尽
接口大量超时
系统崩了
所以要压测,比如按梯度摸容量:
100 并发
500 并发
1000 并发
看看系统在哪个点开始退化,到底能扛多少。同时把这些提前配好:
- 限流(扛不住时拒绝,而不是雪崩)
- 熔断(依赖挂了就快速失败)
- 降级(非核心功能先让位)
- 连接池(数据库/HTTP 连接数上限)
- 超时(别让一个慢请求拖死整条链路)
大白话就是:人多了以后,系统扛不扛得住?
第三关记一句话:性能 → 扛不扛得住。
④ 出问题能不能发现?——坏了我能不能马上知道
这个尤其好理解。假设晚上 10 点上线,10:05 接口错误率从 0.1% 涨到 20%。但如果你没接监控,你根本不知道:
用户:"怎么打不开?"
老板:"系统是不是挂了?"
你:"???"
所以要提前把这条链路搭起来:
日志
↓
监控指标
↓
大盘
↓
告警
比如错误率超过 5% 就触发告警,推到微信 / 钉钉 / 短信,你第一时间收到。
大白话就是:出问题以后,我能不能第一时间知道?
第四关记一句话:监控 → 能不能发现。这里有个坑:告警要真的能触发,上线前最好演练一次,别等真出问题才发现告警规则配错了、或者消息压根没发出来。
⑤ 出问题能不能撤?——坏了能不能撤
这是最重要的一层。比如:
12:00 上线 V2
12:05 错误率暴涨
正确的做法不是"大家先等等,我看看代码",而是:
V2 出问题
↓
立即回滚
↓
V1 恢复
↓
服务正常
所以要提前准备好:
- 灰度发布(先放一小撮流量)
- 分批发布(一台一台来)
- 保留旧版本镜像
- 明确的回滚方案
- 回滚演练(别到出事才第一次回滚)
大白话就是:出了问题,我能不能快速退回老版本?
第五关记一句话:回滚 → 能不能撤回来。能撤,才敢放;撤不回,再小的改动都悬。
一句口诀,五关就串起来了
把五层收成一句话:
代码数据扛得住,出了问题看得见,发现以后退得回。
对应关系很直接:
代码数据扛得住
│ │ │
│ │ └── 性能
│ └────── 数据
└──────── 代码
出了问题看得见 ── 监控
发现以后退得回 ── 回滚
上线后,盯住前 15~30 分钟
发布不是点完"部署"就结束。真正的高风险窗口是刚上线那会儿,我会重点盯前 15~30 分钟,主要看这几项:
- 错误率
- 接口耗时(P95 / P99)
- QPS
- CPU、内存
- 数据库连接数
- 核心业务指标(下单量、登录成功数等)
有任何一项异常抖动,先回滚再排查,别边扛边查。
总结
上线前五问,本质是一句话:
先保证"东西没问题",再保证"数据没问题",再保证"人多也扛得住",然后保证"出问题我知道",最后保证"知道以后我能撤"。
把这五个问题贴在发布清单最上面,每次上线顺着过一遍,比背一长串零散的检查项稳得多。