灰度发布

背景

由于公司产品更新迭代快,每完成一部分新功能都要能及时上线给客户使用,但是上线过程中难免会出现一些问题,前期客户量不多的情况下影响不大,但到今年开始客户量剧增,只要服务一出现问题就会有各种投诉电话打到公司,于是从今年四月份开始准备调整服务发布流程为灰度发布,中间做了很多方案调整,一直到 7 月底才完成所有调整,特此简单记录下。

原有技术架构

公司服务采用前后端分离,后端使用 Java,前端使用 nodeJs,后端为 SpringBoot 微服务架构,不同功能模块相互分离,服务发现与注册使用 zookeeper,消息队列使用 Rabbitmq,服务间调用使用 RPC 协议,缓存使用 Redis,数据库采用的是 MySQL,所有服务都是部署在阿里云上,原有拓扑图如下:
记一次生产环境灰度发布调整 - 图1
客户端访问应用服务会先通过负载均衡,负载均衡将流量进行分配到各应用服务器,各应用服务器进行业务处理再将结果返回给客户端。

灰度发布调整

在进行灰度发布调整前,和开发进行讨论了多次,最后确认了方案如下:
记一次生产环境灰度发布调整 - 图2
将整体服务分为两部分,命名为 A、B区域,客户端访问还是会通过负载均衡进行流量分发,但是此时负载均衡使用的是四层转发到两套 nginx 上,A、B区域连接同一个数据库和缓存,但是 zookeeper 和 Rabbitmq 为单独两套服务。

原因

  1. 为什么使用负载均衡加 nginx
    因为我们所有服务都是部署在阿里云上,阿里云上的 api 比较完善,采用负载均衡是为了作为一个开关使用,当进行发布时可以直接通过 api 将流量直接切换到对应环境而不用修改 nginx 对应配置
  2. 为什么使用同一套缓存和数据库
    先说数据库,如果采用两套数据库会涉及到数据同步问题,这样的工作量比较大,使用一套数据库只会涉及到增加序列化问题,这个只要增加 sql 审计即可解决。
    缓存之前有讨论过使用两套,但是系统中部分功能如登陆态、认证状态都是暂存缓存中,使用两套会影响功能使用
  3. zookeeper 和 rabbitmq 使用两套
    因为服务间的调用时使用 RPC 进行的,而且服务需要注册到 zookeeper 上,如果使用一个 zookeeper 就会涉及到调用时会有可能 A 区域的服务调用到 B 区域
    使用两套 rabbitmq 因为 zookeeper 使用了两套,而服务进行消费消息时也是通过 zookeeper 进行调度的,因此也使用两套

灰度发布流程

  1. 通过 api 切换对应环境,只提供 A 环境给客户端进行访问
  2. 升级 B 环境并进行测试
  3. 通过 api 切换对应环境,只提供 B 环境给客户端进行访问
  4. 升级 A 环境
  5. 通过 api 切换对应环境,提供 A、B 环境同时提供服务

遇到的问题

  1. 测试问题
    由于域名只有一套,所以在测试时需要内部自建 DNS 解析以提供 公司内部测试时访问已升级的环境
  2. 定时任务
    由于系统定时任务时依靠 zookeeper 进行调度的,但是 zookeeper 有两套,这就会出现定时任务会重复执行两次的情况,严重影响业务如客户充值 100 元,但定时任务在入账时入了两次,导致客户账上有 200 元,这个问题是通过开发手段,修改开发配置使定时任务只连接一套 zookeeper。
  3. 高并发问题
    由于之前一直采用的是阿里云负载均衡进行流量分发,没有考虑过高并发问题,这次切换成 nginx 之后,很快就出现了并发量较大导致服务不肯用的情况,这里做的操作就是优化 nginx 配置

总结

这次调整断断续续做了三个月,期间也是出了很多问题,最后都逐个解决了,收获还是挺大的:

  1. 做大调整时需要和开发测试进行详细的沟通
  2. 要考虑到测试环境和生产环境的差异
  3. 做好失败后的挽救措施准备
  4. 多参考成熟的方案结合实际情况进行改善