实践者的 DevOps 之路(5. 部署策略)

部署往往是系统上线的前的最后一步,它在 DevOps 中也扮演了相当重要的角色,而它也是在技术上变化最多的步骤。本篇文章会分享在项目中的 DevOps 部署阶段的实践与经验。

部署

DevOps 让整个开发迭代的速度加快,随之而来的是更加频繁的发布与上线。这也意味着系统上线稳定性变得愈发重要。任何在线上发现的问题都能得到及时的解决。同样部署策略应该支持快速验证产品的想法,能够帮助产品经理更加准确的确定产品方向与迭代价值。

在这种情况下,DevOps 往往采用蓝绿部署,金丝雀发布(灰度发布), A/B 测试等策略来适应项目的不同需要。我们先来看看这些不同的部署策略的优点与局限性。

蓝绿部署

蓝绿部署的优点很明显,在系统升级发布的同时不会导致服务中断。而它的问题也很明显,首先是会有额外的资源消耗,即所有的环境都需要部署两套,用于两个不同版本的切换。其次如果是个以数据库为核心的应用程序,蓝绿部署的复杂度也会提升。

数据库作为核心资源,考虑到数据一致性,成本等问题,一般不会有两套生产环境。因此如果更新中有 schema 相关的升级,很可能造成前端蓝绿环境无法 100% 兼容,需要其他的特性的支持,例如 feature toggle 等。

这几年随着容器技术的普及,蓝绿部署的资源消耗问题已经得到了解决。通过使用 Kubernetes 这样的容器编排系统能够很容的实现 Rolling Update,从而达到与蓝绿部署类似的效果。

金丝雀发布(灰度发布)

金丝雀发布一般也被称为灰度发布,目的在于最小化系统升级时 bug 造成的影响。具体做法上与蓝绿部署类似,只是不需要多套环境。在生产环境的集群中划分部分机器升级系统的新版本,然后在前端流量的 LB 上将部分用户分流到新版本的系统上。这种解决方案的关键在于有较为全面的监控与预警体系。能够自动,快速的发现系统的异常,并通知开发,运维人员。

实际使用过程中的问题是那些服务不可用,或是意料之外的性能降级都比较好捕获(使用 Prometheus + Grafana 非常容易做到),但是真正造成问题的是那些业务处理上的 bug,例如费用计算错误,查询结果错误等。Testing in Production 的解决方案比较麻烦,也不是成熟,因此一般还是在几天之后由人工确认没有大问题的情况下结束金丝雀分布,完整的切换到新版本上。

A/B 测试

与前两种部署策略不同,A / B 测试的目的不是在于降低部署的风险,而是探索用户的使用习惯,从数据的角度提升产品的可用性与价值。在形式 A / B 测试与金丝雀发布非常类似,都是在一套环境中同时存在两个版本的系统,但其实它们存在着不小的差异。

首先金丝雀发布中存在的两个版本是一前一后,一新一旧的,而 A / B 测试中的两个版本在时间上应该是一致的,只是功能上有不同,类似分支的概念。其次金丝雀发布的时间较短,即两个版本共存的时间不会很长,一般持续一至三天,之后如果没有大问题就会统一升级为新版本。A / B 测试的持续时间则可能较长,会按照产品经理所需的时间而定。最长可能会持续一个月,甚至更长。

A / B 测试的难点在于测试数据的分组以及多个 A / B 测试的特征区分,在这方面 DevOps 也没有很好的解决方案,之前的项目中依然靠一些代码的数据埋点实现。

实践

为了在不同类型的系统,技术架构下能够实现上述这些部署策略,同时保证整个部署流程的自动化与稳定性,DevOps 将会面临各种不同的问题,下面是一些我在项目上的相关实践经验。

微服务的挑战

微服务作为最近几年开始流行的架构风格的确解决了不少问题,但是对于 DevOps 提出了更高的要求。微服务在降低系统耦合度的时候也会导致系统数量与复杂度的增加。因此在发布阶段需要合理的处理各个系统间的依赖关系,Rolling Update 是必需的,不能因为一个系统的发布导致某些业务流程的完全中断。

对于这种问题,基于容器的部署与 Kubernetes 这样的容器编排系统可以给予很大的帮助。由于容器本身的特性,我们可以快速,廉价的创造和销毁某个系统的示例,从而搭建大规模的,基于容器的集群。而 Kubernetes 则让 Rolling Update 变得极为方便,只需简单的命令就可以完成整个集群的升级。

流处理系统的发布

流处理系统在现有的数据处理架构下有着不可或缺的位置,如何做好一个流处理系统的发布与升级也对 DevOps 提出了挑战。与一般的系统不同,如果一个流处理系统用于实时报表,或是数据仓库的写入源,是非常忌讳有错误数据写入的。对于一般的 OLTP 系统,如果有错误数据写入(一般是数据库),直接修改数据即可。但是对于流处理系统,如果有错误的数据,就需要重新计算整个时间窗口的数据才能得到正确的结果。

如果需要不中断流处理系统的服务,又要做到在线升级,一般采取的都是基于蓝绿部署的冗余方案。在升级前就会在前端的 LB 切到一套单独的系统,然后进行升级,升级成功后再把流量回复正常。在实际项目中,我们曾经在 Kafka 上实施了整套的方案,也获得了不错的效果。

有状态的服务

包括传统的关系型数据库,或是那些 NoSQL 数据库在部署过程中往往称为最后的堵塞点,特别是关系型数据库。在多个项目中我们都遇到了线上升级中需要修改数据库 schema 的变更,对于这样的场景我们也一直没有很好的解决方案,只能将整个服务响应关闭,快速返回服务不可用,避免在部署过程中由于基础服务的不可用引起上层系统的雪崩。

随着 Kubernetes 对于有状态服务支持的更加完善,我想这个问题也会在不久的将来得到解决。而在目前的项目中,我们都会从架构层面减少对于数据库的依赖,尝试各种更加轻量级的解决方案,绕开这个限制。

小结

这次我们讨论了一些部署中不同策略,也聊了在 DevOps 的部署阶段会遇到的问题。作为个人经验,我觉得在容器化日益流行的今天,DevOps 的能力得到了极大的增强,但是仍然需要考虑老旧架构,技术债等问题为 DevOps 带来的困难。DevOps 永远是一个系统性的问题,一个良性的架构,保持学习能力的团队才是解决问题的关键,而不是一套自动化的系统。

相关阅读:

很不幸,自动化测试永远只能是必要非充分条件

面对疫情这样的复杂问题,有什么招呢?

DevOps关键能力之文化的力量——重磅新书预览《加速》

小说体敏捷/DevOps转型教科书

和实战经验分享

又到拼人品的时候,喜欢《猎豹行动》的朋友请赏个脸投票。

每人每天可以投3票,截止4月19日。谢谢。

关注公众号看其他原创作品

敏于思 捷于行 

坚持每周输出一篇高质量文章

觉得好看,点个“在看”或转发给朋友们,欢迎你留言

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章