数据库改个字段而已,为什么总能把线上系统搞崩?

简介: 数据库改个字段而已,为什么总能把线上系统搞崩?

数据库改个字段而已,为什么总能把线上系统搞崩?

数据库 Schema 变更,真正难的从来不是“怎么改”,而是“怎么在业务不停机的情况下改”。

大家好,我是 Echo_Wish。

做运维久了,你会发现一个特别有意思的现象:

代码上线,大家已经越来越习惯灰度、回滚、监控、限流。

但一说到数据库变更,很多团队还是:

“改个字段嘛,停一下服务不就行了?”

然后凌晨两点,业务群突然开始疯狂弹消息:

“数据库连接超时了。”

“接口怎么全部 500 了?”

“谁在执行 ALTER TABLE?”

最后发现,罪魁祸首就是一条看起来平平无奇的 SQL:

ALTER TABLE user_info
ADD COLUMN phone VARCHAR(20);

这篇文章就聊一个非常现实的话题:

数据库运维自动化,到底应该怎么做 Schema 在线变更,以及如何保证新旧代码兼容?


一、Schema 变更最大的坑,不是 SQL 写错

很多人理解数据库变更,思路特别简单:

修改表结构
    ↓
发布代码
    ↓
完成

但在线业务真正面对的是:

旧代码 ───────┐
              ├──→ 数据库
新代码 ───────┘

也就是说,在发布过程中,数据库面对的可能不是一套代码,而是两套甚至多套代码同时运行。

比如原来的表:

CREATE TABLE user_info (
    id BIGINT PRIMARY KEY,
    name VARCHAR(50)
);

现在产品要求增加手机号。

最直接的方案:

ALTER TABLE user_info
ADD COLUMN phone VARCHAR(20) NOT NULL;

看起来没问题。

但如果线上还有旧版本代码,它执行:

INSERT INTO user_info(id, name)
VALUES (1001, '张三');

数据库就可能直接报错。

问题来了:

明明只是增加一个字段,为什么旧代码也挂了?

因为数据库 Schema 本质上也是一个 API。

这一点,我认为很多团队都低估了。

代码接口有兼容性要求:

API v1
API v2

数据库同样应该有:

Schema v1
Schema v2

而且数据库往往比 HTTP API 更难改。


二、真正靠谱的方案:扩展,而不是破坏

在线 Schema 变更有一个非常重要的思想:

先扩展,再迁移,最后收缩。

也就是我们经常说的:

Expand → Migrate → Contract

这个思想看起来简单,但它几乎可以解决大量数据库发布事故。


三、第一阶段:Expand,先把新结构加进去

比如我们准备增加:

phone

第一步不要急着:

ALTER TABLE user_info
ADD phone VARCHAR(20) NOT NULL;

而应该优先:

ALTER TABLE user_info
ADD phone VARCHAR(20) NULL;

为什么允许 NULL?

因为:

旧代码根本不知道这个字段存在。

旧代码继续:

INSERT INTO user_info(id, name)
VALUES (1001, '张三');

依然可以工作。

与此同时,新代码已经可以开始使用:

SELECT id, name, phone
FROM user_info;

这就形成了一个非常重要的状态:

数据库:
┌────────────────────┐
│ id                 │
│ name               │
│ phone              │ ← 新字段
└────────────────────┘

旧代码 → 只认识 id/name
新代码 → 认识 id/name/phone

数据库已经升级,但旧代码仍然能够正常运行。

这就是兼容性的核心。


四、第二阶段:Migrate,把历史数据慢慢迁过去

字段加好了,并不意味着工作结束。

假设之前已经有:

1000 万用户

现在新增 phone 字段。

你如果直接:

UPDATE user_info
SET phone = 'xxx';

那线上数据库可能直接开始“喘气”。

尤其是大表。

所以数据迁移也必须在线化。

例如:

UPDATE user_info
SET phone = ...
WHERE id > 100000
  AND id <= 110000;

然后循环执行:

10万
10万
10万
10万
...

而不是一次性:

UPDATE user_info
SET phone = ...;

五、为什么数据库自动化不能只自动执行 SQL?

这是我比较想强调的一点。

很多所谓的“数据库自动化平台”,本质上就是:

输入 SQL
↓
执行 SQL
↓
返回结果

这其实不叫数据库运维自动化。

最多只能叫:

SQL 自动执行器。

真正的数据库自动化应该知道:

这张表有多大?
当前 QPS 多高?
有没有长事务?
有没有锁等待?
当前连接数多少?
这个 SQL 会不会锁表?
执行预计影响多少行?
当前是不是业务高峰?
失败以后怎么回滚?

比如我们提交:

ALTER TABLE orders
ADD COLUMN delivery_address VARCHAR(500);

系统至少应该自动检查:

表名:orders
数据量:1.2 亿

当前 QPS:8600

活跃事务:37

长事务:2

数据库负载:72%

DDL 风险:中

建议:
❌ 当前不建议执行

这才叫真正意义上的:

数据库运维自动化。


六、第三阶段:新旧代码双写

这是 Schema 兼容里面非常经典的一招。

例如原来只有:

username

现在准备改成:

user_name

千万不要直接:

ALTER TABLE user_info
CHANGE username user_name VARCHAR(50);

因为旧代码还在使用:

SELECT username
FROM user_info;

直接改名:

旧代码瞬间报错。

更稳妥的方式是:

ALTER TABLE user_info
ADD COLUMN user_name VARCHAR(50);

然后新代码开始:

写 username
写 user_name

也就是双写:

user.setUsername(username);
user.setUserName(username);

读取的时候,新代码优先读取:

String name = user.getUserName();

if (name == null) {
   
    name = user.getUsername();
}

经过一段时间以后:

旧代码
    ↓
username

新代码
    ↓
user_name

数据逐渐完成迁移

最终才删除旧字段。


七、这就是“Expand → Migrate → Contract”

把整个过程串起来,其实特别清晰。

第一步:Expand

ALTER TABLE user_info
ADD COLUMN user_name VARCHAR(50);

第二步:双写

username
   ↓
┌───────────────┐
│ username      │
│ user_name     │
└───────────────┘

第三步:历史数据迁移

UPDATE user_info
SET user_name = username
WHERE user_name IS NULL
LIMIT 10000;

循环执行。

第四步:新代码完全切换

读取 user_name
写入 user_name

第五步:停止旧字段写入

username ← 不再使用

第六步:Contract

最后才:

ALTER TABLE user_info
DROP COLUMN username;

这时候,旧代码已经彻底退出。

删除字段才是最后一步,而不是第一步。


八、再说一个更容易踩坑的问题:字段删除

很多开发喜欢这样操作:

ALTER TABLE user_info
DROP COLUMN old_field;

然后代码:

user.getOldField();

线上直接:

Unknown column 'old_field'

所以数据库 Schema 变更里面有一个特别重要的原则:

新增字段通常容易兼容,删除字段通常最危险。

因为:

ADD

属于扩展。

而:

DROP
RENAME
TYPE CHANGE

往往属于破坏性变更。

因此数据库自动化平台最好能够自动识别:

ADD COLUMN       → 低风险
ADD INDEX        → 中风险
MODIFY COLUMN    → 高风险
DROP COLUMN      → 极高风险
RENAME COLUMN    → 极高风险

然后采用不同审批策略。


九、索引变更,同样不能想当然

很多线上事故不是因为字段,而是:

加索引。

开发发现:

SELECT *
FROM orders
WHERE user_id = 10001;

很慢。

于是:

CREATE INDEX idx_user_id
ON orders(user_id);

然后:

线上开始抖。

因为在某些数据库和版本、表规模、执行方式下,创建索引可能产生明显的 I/O、CPU 或锁竞争。

所以自动化系统不能只判断:

SQL 是 CREATE INDEX
↓
执行

而应该:

CREATE INDEX
↓
检查数据库类型
↓
检查版本
↓
检查表规模
↓
检查当前负载
↓
判断是否支持 Online DDL
↓
生成执行计划
↓
执行
↓
监控

例如 MySQL 环境下,可以结合具体版本和存储引擎评估:

ALTER TABLE orders
ADD INDEX idx_user_id(user_id),
ALGORITHM=INPLACE,
LOCK=NONE;

但这里也不要形成一个误区:

看到 LOCK=NONE 就认为绝对不会阻塞。

数据库的实际行为还受到具体版本、操作类型、存储引擎、并发事务等因素影响。

所以:

Online DDL ≠ 零风险 DDL。


十、自动化平台最应该做的,其实是“刹车”

我一直觉得:

数据库自动化最重要的能力,不是油门,而是刹车。

比如有人提交:

ALTER TABLE big_table
MODIFY COLUMN amount DECIMAL(10,2);

平台发现:

表数据量:8.7 亿

当前 QPS:12000

数据库 CPU:82%

存在长事务:3

DDL 类型:字段类型修改

风险等级:高

这时候最好的自动化结果不是:

正在执行……

而应该:

❌ 拒绝自动执行

原因:
1. 超大表
2. 高峰期
3. 字段类型发生变化
4. 存在长事务

建议:
低峰期执行
或采用在线 Schema 变更工具

能够拒绝危险操作,本身就是自动化能力。


十一、把 Schema 变更真正纳入 CI/CD

如果团队规模再大一点,我建议直接把数据库变更纳入发布流水线。

例如:

Git
 │
 ├── application
 │
 └── migrations
        │
        ↓
   Schema Analyzer
        │
        ↓
   Compatibility Check
        │
        ↓
   Risk Assessment
        │
        ├── LOW ─────→ 自动执行
        │
        ├── MEDIUM ──→ 人工审批
        │
        └── HIGH ────→ 禁止自动执行
                         │
                         ↓
                       DBA

数据库变更文件也可以进入 Git:

db/
├── V001__create_user.sql
├── V002__add_phone.sql
├── V003__add_user_name.sql
└── V004__create_user_index.sql

这样数据库就不再是:

“谁在生产库上手工改了什么?”

而变成:

“Git 里记录了这次 Schema 演进。”

这才是真正可审计、可追踪的数据库运维。


十二、我最推荐的一套线上 Schema 变更原则

如果让我给团队制定规则,我会简单粗暴地定下面几条。

规则 1:禁止直接修改生产 Schema

不要:

开发人员
    ↓
Navicat
    ↓
生产数据库

而应该:

Git
 ↓
Review
 ↓
自动检查
 ↓
审批
 ↓
执行

规则 2:新增优先,删除滞后

优先:

ADD COLUMN

谨慎:

MODIFY COLUMN

最后:

DROP COLUMN

规则 3:代码必须兼容两个 Schema 版本

发布过程中:

旧代码 + 新 Schema

必须能够运行。

同时:

新代码 + 旧 Schema

最好也能够运行,至少要通过明确设计避免发布窗口中的不兼容。


规则 4:大表禁止“一把梭”

不要:

UPDATE 1亿条数据;

应该:

分批
 ↓
限速
 ↓
监控
 ↓
异常暂停
 ↓
继续

规则 5:自动化必须有“风险等级”

例如:

LOW
 └── ADD NULL COLUMN

MEDIUM
 └── ADD INDEX

HIGH
 ├── MODIFY COLUMN
 ├── RENAME COLUMN
 └── 大表 DDL

CRITICAL
 └── DROP COLUMN

不同等级使用不同审批机制。


十三、最后聊聊我的一个感受

数据库运维发展到现在,真正高级的能力已经不是:

“我会写 SQL。”

而是:

“我能让数据库在业务不停机的情况下安全地演进。”

这两句话,看起来差不多,实际上差得非常远。

以前我们习惯:

数据库是基础设施
代码依赖数据库
数据库由 DBA 管

现在越来越应该把数据库 Schema 当成:

代码的一部分

它需要:

版本管理
自动检测
兼容性分析
灰度发布
风险控制
审计
监控
回滚策略

尤其是微服务、Kubernetes、DevOps 体系越来越成熟以后,应用可以秒级发布,数据库却不能再靠人工凌晨两点改表。

所以我认为未来真正成熟的数据库运维平台,不应该只是帮你“执行 SQL”。

它应该在你提交 SQL 的时候告诉你:

这条 SQL 能不能执行。

在执行之前告诉你:

现在是不是执行的好时机。

执行过程中告诉你:

数据库有没有出现异常。

执行完成以后告诉你:

Schema、代码和数据是不是已经完成迁移。

甚至在你准备删除字段的时候直接拦住:

“等等,还有 3 个服务正在使用这个字段。”

这才是我理解的:

数据库运维自动化。

说到底,Schema 变更不是一次 SQL 操作,而是一次线上系统的“渐进式升级”。

真正靠谱的团队,不是从来不改数据库。

而是:

数据库天天改,业务照样跑;代码持续发布,线上依然稳。

这才是数据库运维自动化真正应该追求的终点。


Echo_Wish|专注云原生、DevOps、数据库与 AI 运维实践

别把数据库当成“存数据的地方”。
它其实是整个业务系统最不能随便动的核心基础设施。

目录
相关文章
|
2月前
|
弹性计算 缓存 运维
阿里云服务器贵不贵?一文看懂阿里云服务器多少钱:配置价格表、优惠福利、计费选型避坑指南
很多个人开发者、学生、中小企业在上云初期,都会关心云服务器的实际采购成本。阿里云服务器主要分为轻量应用服务器与云服务器ECS两大产品线,覆盖个人入门学习、开发者测试、中小型企业生产、高性能计算等不同层级业务场景。整体价格跨度很大,入门档位低价即可入手,高性能实例则可达数万元每年,整体呈现“入门普惠、中阶稳定、高阶弹性”的特征。新用户拥有力度可观的折扣,部分实例支持老用户续费同价,长期使用成本可控。本文将从产品定位、配置价格明细、性价比分析、各类人群优惠政策、三种计费模式、命令行实操、省钱技巧、常见避坑点多维度完整讲解,附带可直接复制的CLI命令,帮助使用者合理选型,规避多花冤枉钱的问题。
336 0
|
2月前
|
机器学习/深度学习 人工智能 监控
支付风控的"AlphaGo时刻 ——Data Agent驱动的三层AI风控架构
上海富友支付技术负责人分享风控升级实践:面对400条规则失效、新人难上手等困境,放弃自建AI模型,选用阿里云Data Agent重构风控体系。通过“数据洞察—机器学习—大模型解释”三层架构,分析效率从2周缩至1天,覆盖率提升至90%,实现风控知识沉淀与可持续演进。
264 0
|
7月前
|
运维 Kubernetes 监控
谁的锅谁来背:团队边界 vs 平台边界,别再互相甩锅了
谁的锅谁来背:团队边界 vs 平台边界,别再互相甩锅了
320 7
谁的锅谁来背:团队边界 vs 平台边界,别再互相甩锅了
|
2月前
|
人工智能 弹性计算 API
阿里云服务器新手选购全解:轻量、ECS、GPU、AI云产品选型与性能实测
在云计算落地的过程里,开发者、小微企业以及AI从业者,总会遇到算力选型的难题。市面上有轻量应用服务器、ECS弹性云服务器、GPU加速实例以及各类AI云产品,产品形态繁多,定位差异巨大。不少使用者因为分不清产品边界,盲目选购高规格实例,造成预算白白消耗;也有人为了节约成本选择过低配置,业务上线之后频繁卡顿、推理超时,直接影响项目正常运行。
265 0
阿里云服务器新手选购全解:轻量、ECS、GPU、AI云产品选型与性能实测
|
2月前
|
人工智能 监控 搜索推荐
瓴羊AgentOne实战复盘:四大AI员工如何驱动企业核心业务指标增长
2026年,瓴羊AgentOne推出四大AI员工(销售、客服、运营、营销),推动企业AI从“能聊”迈向“能干”。依托Data×Agent×FDE三角能力体系,深度嵌入业务流程,直击GMV、解决率、ROI等核心指标,实现端到端价值交付。
|
2月前
|
人工智能 自然语言处理 大数据
绘蛙图片 API|阿里自研电商 AI 生图接口:商品图、卖点图、创意生图按量计费
绘蛙是阿里巴巴自研电商大模型,专注AI内容智能生成:支持主图、商详页、口播视频等多类型素材一键产出,覆盖服饰、美妆、食品等全品类。已助服装品牌年省200万拍摄成本,显著提升曝光与销量。阿里云官方活动:https://t.aliyun.com/U/OTnSAH
|
4月前
|
JSON 缓存 安全
多 Agent 协作听起来很酷,但现实中两个 Agent 一起干活会不会互相捣乱?
本文揭示多智能体(Multi-Agent)系统在生产落地中的真实困境:CrewAI、AutoGen、LangGraph等框架常因指令竞态、状态幻觉、无限辩论等问题导致故障率倍增。核心症结在于LLM缺乏原生状态管理与协作治理能力,“协作税”显著抬高复杂度与风险。文中剖析典型故障场景,提出通信范式选择、仲裁机制、协调层设计及工程实践等系统性解法,并强调——**是否真需多Agent,应以“分工收益>协作成本”为唯一标尺。
466 3
|
6月前
|
缓存 监控 Java
【分布式】分布式核心组件——分布式熔断降级:熔断器状态机、熔断策略、降级方案、Resilience4j/Sentinel实现
本文系统化梳理分布式熔断降级完整知识体系,涵盖核心定位、状态机模型、熔断策略(慢调用/异常比例/数)、降级方案、Resilience4j与Sentinel深度对比、生产落地实践及云原生进阶扩展,助力学习、开发与面试一站式掌握。
|
7月前
|
存储 数据采集 人工智能
什么是数据湖?一文搞懂数据湖、数据仓库、湖仓一体
本文用通俗语言解析数据湖、数据仓库与湖仓一体三大核心概念:数仓专注结构化、高性能分析;数据湖支持多源原始数据低成本存储;湖仓一体则融合二者优势,实现统一存储、灵活探索与可靠分析。附实战方案与工具推荐。

热门文章

最新文章