部署在90秒内变绿。然后蓝色的错误率达到100%每个请求都很感人/orders归来的column orders.status_v2 does not exist。两个健康的应用堆栈没有工作回滚。蓝绿色只保护一样东西Blue-green为您提供了两份应用程序代码和一个在它们之间切换的路由器。它不会给你数据库的两个副本因为你不能廉价地派生一个具有连续写操作的Postgres集群并在以后合并这些派生。两种环境都指向相同的主机、相同的模式、相同的表。所以现在migrate完成蓝色运行新模式的新代码绿色运行相同新模式的旧代码。交换是原子性的。架构更改不是。这就是让我们倒下的迁移:ALTER TABLE orders DROP COLUMN status; ALTER TABLE orders ADD COLUMN status_v2 text NOT NULL DEFAULT pending;秩序很重要。绿色仍然可以选择status。在之间DROP一旦green停止服务每个green查询都会失败。只要路由器耗尽加上每个进行中的请求加上每次重试绿色就会一直服务。回滚计划说“翻转回蓝色。”在翻转之前蓝色已经被一次迁移打破了。回滚意味着两件不同的事情代码回滚是指针变化:翻转路由器旧的神器依然存在。只有当底层数据仍然符合时它才起作用。架构回滚不对称。的反面DROP COLUMN是ADD COLUMN价值观就没了。您不能取消删除列、取消截断表或取消运行UPDATE就地重写了行。数据库只有一种状态它向前移动并且没有指向以前的版本。还有第三种更糟糕的情况:迁移中途失败。Postgres在一个事务中运行大多数DDL所以a失败了ALTER TABLE里面的BEGIN干净利落地回滚。而是一个包含几个语句的文件一些CONCURRENTLY或者步骤之间的显式提交会留下一个既不是旧形状也不是新形状的架构。这是没有人排练过的状态。可逆模式不可逆数据我应该在部署之前就区分出来。当旧代码仍然可以在新模式下运行时模式更改是可逆的。添加一个可空的列、一个索引、一个表——都是可逆的因为旧代码忽略了它不知道的内容。当迁移重写或删除值时数据更改是不可逆的。删除列、有损类型转换、计算值的回填—新形状不是从旧形状派生出来的因此没有反向迁移会重建它。可逆的模式更改通常伴随着不可逆的数据更改。这就是陷阱。ADD COLUMN status_v2一个人很安全。ADD COLUMN加上回填加上DROP COLUMN在一个文件是一个单向的门。扩展、收缩、标记安全路径有三次释放而不是两次。释放一:展开。将新列添加为可空并在应用程序代码中重复写入。旧代码读取旧列并继续工作。新代码将两者都写入。如果您回滚没有什么会中断因为两个形状都存在。def write_order(order): db.execute( UPDATE orders SET status %s, status_v2 %s WHERE id %s, (order.legacy_status, order.status, order.id), )版本2:在部署之外用一个可以停止的查询进行批量回填。回填必须可重新开始。分块运行记录上一次处理的id然后重新运行。版本3:将读数切换到功能标志后面的新列。标志是回滚。如果读取中断翻转标志而不是部署。只有在标志开启了一个完整的流量周期之后您才会收缩——在代码不再引用它的无聊版本中删除旧列。在降落前做旗子而不是在降落后。旗帜在几秒钟内是可逆的aDROP COLUMN不是。当迁移已经被部分应用时停止部署。不要回滚应用程序也不要运行第二次迁移来“修复”第一次迁移。这两者都使得模式更难推理。找出到底是什么着陆了。在Postgres中读取真实状态而不是信任您的迁移表:SELECT column_name, data_type, is_nullable FROM information_schema.columns WHERE table_name orders ORDER BY ordinal_position;然后检查迁移是否持有锁。pg_stat_activity和pg_locks显示被阻止的ACCESS EXCLUSIVE等待长时间的读取。如果它是一个陈旧的报告查询或者是您的下一个部署死锁则终止拦截器。然后挑一个方向提交。如果旧的形状仍然存在就用标志禁用新的代码路径不去管模式——这样就可以重新发布一个了。如果旧的模式消失了唯一的道路就是前进:发布与当前模式匹配的代码修补今天失败的查询并接受您是在压力下部署的。仅当您能够承受丢失自迁移以来写入的所有数据时才从备份恢复并首先测量该窗口。我记住的教训是:数据库不是部署目标。这是一个共享的、单一状态的依赖关系每次迁移都是对生产数据的更改。使用实际的行数在副本上预演迁移并记录持有锁的时间。本文来源于铭煌网www.iissbbs.com