升级部署
服务通过滚动更新升级:新节点在旧节点旁边启动,分区移到它们上面,然后旧节点停止。有一段时间,两个版本同时运行,面对同一个数据库和同样的主题。本页说明是什么让这件事保持安全,无论是升级 Wow 还是升级你自己的代码。
两个版本并行
在同一主版本内,Wow 相邻的次版本可以在一个服务内、也可以跨服务并行运行。它们的内部协议(集群通道、等待信号、线上形式)以及存储格式保持兼容:
- 存储格式按结构而不是按行做版本:每张日志、快照和定时器表都在
wow_format中记录它的格式。在同一主版本内格式不变;同一格式内新增的列,会在下次检查时加到已有的表上,读者忽略它们不认识的东西。 - 线上形式(Kafka 信封、命令、回执、等待信号)也带着它们的格式。新的可选字段先由一个次版本开始读取,下一个次版本才开始写入。
- 不兼容的改变要等下一个主版本,由它的迁移来处理。
所以一次只升一个次版本,并让每次发布完成之后再开始下一次。
你的代码:事件
事件的类在你服务的两个版本之间可能改变,而发布期间两个版本都会读取日志:
- 新增一个带默认值的可选字段,什么都不需要。
- 其他任何改变都要提高事件的修订号,并提供一个从旧修订号开始的升级函数(演进事件)。先部署读取的一方:每个节点都能读修订号
n + 1之后,再部署写入它的代码。否则旧节点可能读到一条它没有升级函数的记录。 - 另一个服务中的消费者,在它的 api 升级之前,会把新修订号读成
PublishedEvent,也不会为它调用接收这个事件类的处理函数(发布与消费事件流)。
你的代码:状态
状态结构的改变要提高 @AggregateRoot(stateRevision = n)。发布期间,新节点以新修订号声明快照表并原地重建它,而旧节点继续以旧修订号写入;存储会阻止旧节点覆盖已重建的快照。回滚时,只有在不再剩下任何更高修订号的节点之后,才会把声明降回去(重建与重放)。
数仓的展平视图遵循同样的规则:写入者只会用更新的定义替换它,所以重启的旧节点不会撤销新节点的视图(ClickHouse)。
你的代码:契约
服务暴露的命令、事件、状态和错误,是它与客户端和对端之间的契约。Gradle 插件把每次构建的 Manifest 与提交的基线比较,在基线的主版本内,会让破坏客户端的改变失败:删除命令或事件、新增必填字段、删除字段或改变字段类型。用 updateManifestBaseline 记录有意的改变,并与代码一起评审(测试服务)。破坏性改变需要服务契约的新主版本,或者在旧命令旁边新增一条命令。
发布期间的订阅
分区连同它的检查点移到新节点上,新节点的订阅从那里继续。新版本中新增的处理函数按它的种类开始:投影从日志的开头,反应器或 Saga 从末尾。改了名的处理函数是一个新订阅:它按种类开始,就像新的一样。
不能改变的设置
wow.log.partitions 在日志有了条目之后就固定了,一个服务的节点共用它们的存储布局和集群令牌(配置服务)。集群令牌分三次发布轮换:先把新令牌加在第二位,再把它移到第一位,最后删除旧令牌。
主版本
新的主版本可能改变格式和协议。它的节点不会与上一个主版本的节点并行运行:它附带一次迁移,在切换之前或切换期间运行,就像 V10 从 9.x 迁移那样(从 9.x 迁移)。