专业书籍精读 · 持续交付 · 第 12 章

管理数据

Continuous Delivery · Ch 12 · Jez Humble & David Farley · 2010

EN →

这一章讲什么?

你用的每个 App 背后都有一个数据库,存着订单、聊天记录、余额。前面几章讲「怎么把新版本推上线、推错了怎么撤回来」,这一章讲那件撤不回来的事:新版本往往要改数据的存放方式,而数据不像代码,改错了没法「换回上一版」

打个比方

把数据库想成一条街的门牌号。发新版应用像给店换招牌——挂错了摘下来就行,五分钟的事。改数据库则像给整条街重新编号:快递员的地址簿、居民的身份证、外卖平台的记录,全都对着旧号码。你要是今天半夜把旧号牌一次拆光换上新号,第二天整条街的快递都会送错,而且已经按新号发出去的包裹,退不回来了

旧世界为什么难

老办法是:上线那晚,找个懂数据库的人登上去,照一张便条手工敲几条命令改结构。出了事怎么办?答案通常只有一个——拿昨晚的备份把整个数据库还原回去。听着安全,其实是把从昨晚到现在所有人的下单、付款、留言一起抹掉。于是团队宁愿不改,半年攒一次大版本,然后在某个周六凌晨提心吊胆地干一整夜。

它靠什么把这事掰直

第一,把每次数据库改动写成一张编号的施工单,和代码一起存进版本库。数据库自己记着「我已施工到第 27 号」,上线时自动比对、把 28 到 31 号依次做完。谁改的、改了什么全有记录;同一批施工单在测试环境演练过很多遍才轮到线上。

第二,施工单只添不拆。要挪走一个字段,先加新的、把数据抄过去,旧的先留着——万一要退回去,东西还在原地。

第三,也是最关键的一招:两块门牌并挂一阵子。不再有「切换的那一瞬间」,而是拆成好几小步——先挂上新号牌,让新旧两块牌子并存一段时间,等所有人的地址簿都换完了,再从容摘掉旧牌。任何一小步出问题,都能原地停下、退回上一步,而不是整条街推倒重来。

还有测试数据这件事

很多团队图省事,把线上数据库整个拷一份到测试环境。看着最真实,其实最坑:太大、跑不动,全是真人的隐私,而且谁都能改——今天有人删了一条记录,明天别人的测试就莫名其妙红了。更稳的办法是让每个测试自己造那一小撮数据,用完清掉。

这里有个躲不开的代价

「并挂两块牌子」意味着一次简单的改动要分成好几次上线,而且中间那段时间,代码得同时伺候新旧两套结构——更啰嗦、更费事,换来的是每一步都能停能退。

一句话记住

代码可以换回上一版,数据不行。所以:把每次数据库改动写成编号的、版本化的、在各环境反复演练过的脚本;只添不拆;再把一次结构变更拆成新旧并存的几小步,让每一步都可以停下、可以退回。

想看迁移脚本怎么编号、扩展-收缩六步具体怎么走、各阶段的测试数据到底该怎么造? → 切到精读版