设计一套系统的时候, 最初的数据库结构总是不能适应未来业务的发展变化。经常需要调整数据库的表结构以适应新的业务需求或调整逻辑结构。
为此,需要让系统能支持不停机迁移。不停机迁移,用户0感知的,完成数据库升级。要做到这点,首先要做到程序本身的热更新。
如果是 php 之类的脚本语言编写的服务器端程序,热更新实现起来倒也轻松容易。但是既然是我这个c++佬出来写文章, 一定是关注的c++编写的服务器端程序的热更新。
systemd 提供了一个热更新的新思路。就是让 systemd 持有 listen socket。然后fork出服务进程。 进程重启, listen socket 并没有销毁,因此用户依然可以在进程关闭期间发起连接。期间创建的连接,在进程启动后会被处理。 用户唯一能感知到的就是重启期间处理有一定的延迟。
支持 systemd 的 sccket activation 就实现了热更新的第一步。
接下来才是重点。使用 socket activation 的必然要求就就是重启迅速。新进程要迅速完成启动准备,并进入服务状态。连接总是被 hold 住,响应不及时,用户看来也是停机。
如果要修改数据库结构, 重启时就是修改的时机。这就要求,对数据库 schema 的修改必须要立即完成。 那么,什么样的操作能立即完成呢?
增加一个允许 NULL 字段。
删除一个字段。
重命名一个字段。
删除一个索引
创建一张新表
什么样的操作要避免呢?
增加一个非空字段
新建一个索引
并非所有的操作都要安排在程序重启期间进行。可以在重启前就执行。这就要求,对数据库的修改,必须保证旧程序代码兼容。如果不兼容,就首先热更新一个能同时兼容 旧库和(即将更新的)新库的程序。接着更改数据库。使用这种方式,可以放宽一个要求, 就是只要不(长时间)锁表的操作,都可以进行。例如,pg 的并发新建索引。
Comments