为什么要审

数据库这东西,谁碰谁知道。线上一个 ALTER TABLE 跑歪,业务直接卡死,凌晨被拉起来回滚的事,我猜干过几年后端的人都经历过。

我所在的 Supernova 有个 DAL 小组(Database Access Layer),2021 年底正式成立,我进去之后干的第一件事就是把数据库变更审核流程跑起来。

代码出 bug 顶多是某个功能挂掉,SQL 出事是整库陪葬。这是我当时跟新来的同学反复说的一句话。听起来吓人,但确实就是这样。

审核流程长啥样

我们一开始也没搞什么高大上的平台,就是一套工单加评审会的组合拳。

1. 提工单

任何对线上库的 DDL/DML,都得提工单。工单里必须包含:

  • 变更的 SQL 语句(原始的,不能是”我口头说一下”)
  • 影响范围评估:预计影响多少行、有没有大表全扫
  • 回滚方案:万一炸了怎么救
  • 执行时间窗口:通常夜间低峰
1
2
3
4
5
6
7
8
# 工单示例(脱敏)
ticket:
db: t_xxx_orders
type: DDL
sql: "ALTER TABLE t_xxx_orders ADD COLUMN refund_status TINYINT DEFAULT 0"
affected_rows: ~
rollback: "ALTER TABLE t_xxx_orders DROP COLUMN refund_status"
window: "2021-12-10 02:00-04:00"

2. DAL 小组初审

工单提上来后,DAL 这边的人先看一遍。主要看几个点:

  • 索引是不是该加的加了
  • 字段类型选得对不对(TINYINT vs INT 这种)
  • 有没有用 LIMIT 兜底,防止误删全表

初审不过的直接打回,不用上会。

3. 评审会

过了初审的,每周固定一次评审会,把本周攒的变更过一遍。评审会不是走过场,会上经常吵起来。有人觉得这个索引没必要加,有人觉得这个 ALTER 应该走 pt-online-schema-change,都得拿出来掰扯。

评审的价值就是让第二个、第三个人看到你的 SQL。

很多时候自己写的 SQL,自己看不出问题,换个眼睛一看就发现:哎,这里少个索引;哎,这个 UPDATEWHERE 条件走的是全表扫描。

4. 执行与复核

评审通过后,由 DBA 或 DAL 小组的人执行。执行完有个复核环节,确认变更生效、业务没报错、慢查询日志没突然冒出新的怪东西。

踩过的坑

这套流程跑起来之后,其实最大的阻力不是技术,是人。

业务方嫌慢。以前想加个字段,找 DBA 说一声就上了,现在要提工单、等评审、排队。一开始确实有怨言。但坚持两三个月之后,线上事故明显减少,大家就都服了。

评审会容易形式化。如果评审的人不认真看 SQL,那就是走过场。所以我们的原则是:评审的人必须是有经验的后端或 DBA,而且必须真的去 EXPLAIN 一下,不能扫一眼就说”通过”。

还有一个坑是大表 DDL。一开始有人提了个 ALTER TABLE 加字段,表有 8000 万行,直接跑,结果把 binlog 撑爆了。后来我们规定,超过 100 万行的表,DDL 必须走 pt-online-schema-change 或者 gh-ost,不能裸跑。

1
2
3
4
5
# 大表加索引,老老实实用 pt-osc
pt-online-schema-change \
--alter "ADD INDEX idx_user_id (user_id)" \
D=t_xxx,t=orders \
--execute

效果

这套流程大概跑到 2022 年中的时候,线上因为 SQL 变更导致的事故,基本清零了。偶尔有一两个漏网的,也能靠工单里的回滚方案快速救回来。

我个人感觉,变更审核这件事,难的不是流程设计,是执行纪律。流程画在 PPT 里都好看,真正难的是每一次变更都老老实实走流程,不打折扣。

流程不是给没事的时候用的,是给出事的时候用的。

DAL 小组后来又陆续做了跨语言 SDK、慢查询治理、多租户隔离这些事,但变更审核始终是地基。地基不稳,上面盖什么都白搭。