考验你的时候到了

周末发版

周六上线, 大版本的升级。虽说不是太大波动但也是一波三折。做个记录吧。可以改进的地方当然还是很多的。
昨天还想着总结一下的。但是昨天其他部门折腾到晚上 22:00 多。回到家都 11:30 了, 当时没来得及仔细回顾。洗洗睡了。
今天来回顾一下都用了哪些上线操作技巧。

就位

8:30 我就已经就位了。基本上进入上线的节奏了。但是同时上线的其他部门的四个部门还没有准备好。我需要等其中一个部门的人将与本次需求相关的大概几十万数据发过来, 进行初始化。
于是写好上线文档,重新梳理一遍本次开发的源码逻辑,流程。确认顺利走了一遍。将后端单元测试 go test 走一遍。确认开发环境和测试环境下没有问题的。

准备

9:00 开始细化前一天(周五)与架构师讨论修改之后的文档, 包括数据初始化的改动。本来周五下午我准备封闭将要上线的 dev-feature 功能分支的。但是架构师过了一遍之后。认为我初始化的数据有点问题。主要是初始化不够彻底,留有少许残余的没初始化到。于是我重新修改了两版方案。其中初始化行业和地址字典部分,我改为原先从上传文件走脚本修改,改为导入临时表, 然后使用联表查询,依据不同条件进行批量更新。
等初始化的数据,一直催他们,还是没有给到正式线的初始化数据。
所以在 15:30 拿到初始化数据之前。我依次做了这几件事情:

  1. 无关的代码注释,多余的 log 打印去掉。
  2. 合并前端代码,提交版本库。 因为需要拉 node_module 目录,所以提前准备好前端代码镜像。
  3. 合并后端go代码,提交版本库待发布分支。

    1
    2
    3
    4
    5
    6
    git checkout master 
    git fetch
    git checkout dev-feature
    git rebase master -i
    # 然后保留一个功能点的 commint ,其他的 commit 修改为 squash
    # 这样可以保证主干分支 master 的干净, 相当于本次 100 个 commit 汇成了一个 commit
  4. 再次细化上线文档。

    • 将数据库表变更操作每条将要执行的 sql 按照执行顺序, 按照四个功能块列出来。细化到每一条 sql, 包含变更前的查询和变更后的确认 sql 全补上。
    • 初始将修改的功能点 1-7 罗列出来。上线前给架构师再过一遍。架构师确认无误。
    • 加上接入监控部分详细描述。
    • 确认要部署的 docker 集群 ip。
  5. 提前配置好配置服务器的相关域名,开放端口,各项敏感参数,签名。
  6. 配置线上开放的 API . 发布,申请审核通过之后,进行对应的业务线授权。

初始化

开始所有的数据库操作之前,都先备份。

1
mysqldump -uroot -p dbname table_name > table_xxx_20181201.sql

16:00 千呼万唤始出来,终于等来了初始化数据。我依次按照我的文档。执行了初始化。一开始收到初始化文件时,想着用 rsync 去上传文件的。但是行不通。改为 rz 同步初始化数据文件到服务器。然后打算从终端直接导入。

1
mysqldump -uroot -p db_name < change.sql

结果不行。又改登陆数据库先进去, 然后

1
source /dirpath/change.sql

这下导入了。之后开始加字段,

1
2
3
4
5
ALTER TABLE X ADD COLUMN xxx VARCHAR(50) NOT NULL COMMENT 'XXX';
UPDATE TABLE ...
ALTER TABLE ADD INDEX (`YYY`);
...
# 还有一顿的操作, 按流程文档走。

初始化历时 30 分钟左右。
此时已经 16:30 左右了! 根据上线次序,必须其他三个部门全部上线完,我才能上线。但是其中的一个部门还在初始化。
然后继续等。结果,等到了晚上快 20:00 点,才等来了消息: 其他部门初始化完成了,这下我才可上线。在这中间,我又把本次接入的出入的接口加上监控项目。这样,代码一上线,我就可以开始变看日志,边看监控发现存在的问题了。

上线

于是我用了 7 秒就把后端所有的镜像部署上去了。为啥?因为我在等待其他部门操作期间,把所有的镜像都准备好了。万事俱备,只欠灭霸的一个响指了。哦,好像哪里不对啊。
紧接着又上线前端的容器。
看日志,发现有一个错误级别的。反馈是数据库有一个字段找不到!这个字段是第八版本中修改的!赶紧加上。这回后续时间内那个错误级别日志消失了。
然后联合线上回归。又发现几个问题。马上跟进!
原来其中有一个问题是我这边的,有一个表的有关时间字段设置的 int(11) 没有 UNSIGNED ! 长度不够。所以我改了一下这个字段长度。

1
ALTER TABLE table_name CHANGE `x_column` `x_column` int(11)  UNSIGNED  NOT NULL DEFAULT 0 COMMENT '过期时间';

然后再验,还是不够。原来另一个接口返回的时间戳是精确到毫秒级的时间戳, 从 2147483647 扩大到 4294967295还是不够。所以我改为 bigint 之后才行。
其他问题,协助他们验证的线上的 bug 进行日志跟进。依次都化解了。

验证完,都已经 22:00 了。
然后就坐地铁回家了!

小结

  1. 永远准备好应对任何来自生产环境的异常问题。生产环境和测试环境不可能完全一致, 只能无限逼近。
  2. 单元测试能多写就多些,必要的加上压测。
  3. 操作流程要清晰。
  4. 要有全局观。
  5. 响应要一直保持足够快。