持续交付发布可靠软件的系统方法(交付生态圈)第十二章:数据管理
应用程序可以通过删除前一个版本,使用新版本替换旧版本的方式部署,但是大多数系统,数据无法使用这种方式进行变更,一旦某个系统发布到了生产环境中,关联的数据将不断增加。数据往往是系统中最有价值的部分。当我们需要对数据系统进行结构修改或者内容修改时,就需要相关的策略。
对数据的修改是不可避免的,关键在于将数据迁移过程自动化。目前有一些工具对数据迁移提供了较多支持,它们还允许对数据库进行版本化管理。
另一个重要部分是测试数据的管理。
数据库脚本化
任何数据库的修改都应该通过自动化过程来管理。包括数据库的初始化
,数据库所有的迁移
都需要脚本化,并将脚本提交到版本控制库中。
几乎所有的数据管理系统都支持通过自动化脚本进行数据存储的初始化工作。
- 清除原有的数据库
- 创建数据库结构、数据弯路实例以及模式等
- 向数据库加载数据
在大多数据项目中,数据库的使用要复杂得多。
增量式修改
绝大多数据系统,对数据库更新时,要保留它们的数据。由于在部署时需要保留数据库中的已有数据,所以需要有回滚策略,以便部署失败时使用。这就需要对数据库进行版本控制。
- 在数据库中创建一个数据,用来保存版本号
- 每次数据库进行修改时,需要创建两个脚本:升级脚本、回滚脚本
- 有一个配置项来设置数据库与应用版本对应关系
在很多项目中,多个程序共用一套数据库存储。虽然这种方式并不推荐,最好是让程序直接交互,但是这种情况却是常见的。这种环境下对数据库变更,就需要对程序做完全的集成测试,确保数据库变更对相关影响到的程序都能测试到。同时对哪个应用使用了数据库哪个对象做登记也是可以的。
数据库回滚和无停机发布
生产环境部署有两个需求会成为数据库回滚的约束。
- 回滚时需要保留本次升级后产生的数据
- 保持应用程序的可用状态
- 保留数据的回滚
回滚脚本要满足以下条件
- 包括模式修改,即不迁移任何数据
- 只删除新版本使用的那些数据,即使这些数据丢失了也没问题
对于以下情况
- 涉及从临时表中将数据导回来
- 删除那些旧版本系统无法接受的数据
第一种方法是将那些不想丢失的数据库事务缓存,一旦应用程序被成功地重新部署,这些事件就可以重新播放一遍。
第三种方法是使用蓝绿部署,发布时对生产数据库(蓝环境)做一个备份,将备份放在绿环境中应用,迁移数据,将用户切换到绿环境中。回滚时,将用户切回蓝环境,再把绿环境的数据库上发生的新事务回收,在下一次更新之前重新应用这些事务到蓝数据库上。
- 应用程序部署与数据库迁移解耦
第三种方法是将应用程序部署过程与数据迁移过程解耦,分别执行,这种可用于管理热部署。
开发应用程序升级的中间版本,它既与数据库上个版本兼容,也与数据库下个版本兼容。
测试数据的管理
- 为单元测试进行数据库模拟
单元测试不使用真正的数据库,通常它会使用测试替身对象来取代与数据库打交道的服务。如果做不到的话:
- 用测试替身对象来替代那些访问数据库的代码,通常使用repository模式
- 使用假的数据库,如H2/SQLite/JavaDB。单元测试运行在一个内存数据库上,让验收测试运行在平时使用的磁盘的数据库上。
- 管理测试与数据之间的耦合
以下三种方法可以用来做测试设计,便于管理好数据的状态:
- 测试的独立性[推荐],合理组织测试,让每个测试的数据只对该测试可见
- 适应性测试,运行时先对数据环境进行检查,用检查的数据作为数据基础进行测试
- 测试的顺序,按某种已知的序列运行,每次测试输入依赖于前一个输出
保持测试的独立性最简单的方法是确保在测试结束时,总是把数据库中的数据状态恢复到测试之前。
对于支持事务的数据库来说,测试开始时创建一个事务,在事务内执行所需的数据库操作与交互,测试结束后,将该事务进行回滚。
不建议创建一个连贯的“故事”进行顺序执行,这个有序的测试无法真正地代表测试的目的和内容。
数据管理和部署流水线
- 提交阶段的测试数据,避免复杂的数据准备。
- 验收测试的数据,尽可能减少测试对大型复杂数据结构的依赖。测试专属数据、测试引用数据、应用程序引用数据
- 容量测试的数据,为测试提供足够的输入数据,准备适当的引用数据支持测试中的用例
- 其他测试阶段的数据,推荐利用生产数据的一个子集或者运行一些自动化验收测试或者容量测试之后产生的数据库,为其他测试阶段提供数据。