如何升级线上服务

注意
本文最后更新于 2023-11-10,文中内容可能已过时。

如何升级线上服务

参考博客:常用项目部署方案和区别_DevOps_进击的梦清_InfoQ 写作社区

一个服务正在线上运行,而此时我们需要对其进行升级,如何保证服务不停机,或者减少停机对用户影响,如何在升级不成功的情况下快速回退到旧版本,等等,这都是我们要考虑的问题,目前市面上有以下几种线上产品升级方案,我们来一一查看一下。

单服务器组发布

什么叫单服务器组,这个概念主要是对应着传统的服务器环境,跟现在流行的云环境是两种概念,单服务器组代表的是,一组固定的服务器,无法像云服务一样动态的创建和回收,一个 Web 应用部署到一个单服务器组上,这个服务器组有几台机器,那么下次升级的时候,我们也是升级这几台机器上的 Web 应用。

如果是云环境,方式则更加灵活

蛮力发布

传统和原始的发布方式,先将所有的服务停机,下线,然后将新版本的软件包复制到服务器上,然后启动,这种方式一般主要靠手动,通过脚本也可以做到一定程度的自动化,最大的缺点是会造成服务长时间停机,对用户造成很大的影响,因此这种方式是不推荐的。

发布前:

发布后:

优势:

  • 简单成本低

不足:

  • 服务中断用户受影响,出了问题回退也慢

适用场合:

  • 开发测试环境

  • 非关键应用(用户影响面小)

  • 初创公司什么都缺,找夜深人静用户访问量小的时间干

流量模式

(单服务器组)金丝雀发布

在蛮力发布的基础上,发展出一种更加细粒度的发布策略,就是金丝雀发布。金丝雀发布,又称灰度发布,以前旷工开矿下矿洞前,先会放一只金丝雀进去探是否有有毒气体,看金丝雀能否活下来,金丝雀发布由此得名。

具体发布过程为,先将一个单服务器组中的小部分服务器(2% 或者 5%)上的服务升级为新版本的服务,然后测试,并观察用户反馈,如果发现问题很大,用户反馈不佳,则直接回退,如果问题不大,则将剩下的服务器上的应用也升级为新版本。

不过,在小部分服务器升级成功之后,升级剩下的 90% 的服务器时,仍然需要将这些服务器上的服务停机,此时,整个系统的流量压力就只有小部分服务器在扛,此时,有可能会扛不住,因此,此时是系统业务承载量最小的时刻,我们应该在系统访问量最小的时候进行金丝雀发布。

发布前:

先发一台,当金丝雀

经过测试没问题,替换剩下的

优势:

  • 用户体验影响小,金丝雀发布过程出现问题只影响少量用户

不足:

  • 跟蛮力发布一样,发布自动化程度不够,发布期间可引发服务中断

适用场合:

  • 对新版本功能或性能缺乏足够信心

  • 用户体验要求较高的网站业务场景

  • 缺乏足够的自动化发布工具研发能力,这是缺乏专业运维团队主流的发布方式

流量模式

(单服务器组)滚动式发布

微软/小米的新系统推送,好像就是这种方式

滚动式发布在金丝雀发布基础上的进一步优化改进,第一部都是一样的,用一小部分服务器(2% 或者 5%)当金丝雀进行功能测试,没问题了之后,滚动式发布不是立即将剩下的服务器全部更新到新版本,而是再在剩下的服务器中选择一部分,比如在服务器总量 10% 左右数量的服务器,进行更新发布,没问题了,再进行第三次发布,这一次就是总量的 30%,最后进行第四次发布,这一次就是总量的 50%,这样,就将所有的服务器上的应用都升级了。

也就是说,一次滚动式发布一般由若干个发布批次组成,每批的数量一般是可以配置的(可以通过发布模板定义),这就要求滚动式发布需要比较复杂的发布工具和智能 LB,支持平滑的版本替换和流量拉入拉出。

每次发布时,先将老版本 V1 流量从 LB 上摘除,然后清除老版本,发新版本 V2,再将 LB 流量接入新版本。这样可以尽量保证用户体验不受影响。

而且每个批次之间留观察间隔,通过手工验证或监控反馈确保没有问题再发下一批次 (其中金丝雀的时间一般会比后续批次更长,比如金丝雀 10 分钟,后续间隔 2 分钟)。这样,总体上,滚动式发布相比于金丝雀发布,流量的过度更加平缓,但是发布时间更长。

发布前:

先发一台,当金丝雀

下一个批次滚动发布

直到最后全部发完

优势:

  • 用户体验影响小,体验较平滑

不足:

  • 发布和回退时间比较缓慢

  • 发布工具比较复杂,学习成本高,LB 需要平滑的流量摘除和拉入能力

适用场合:

  • 用户体验不能中断的网站业务场景

  • 有一定的复杂发布工具研发能力;

流量模式

双服务器组发布

这种方式主要是适合云环境的发布,云环境中,服务器资源是可以随时申请随时回收的,因此我们可以很轻松地申请一个任意大小的服务器组中,然后将新版本的应用部署到这个服务器组中,通过修改 LB 的配置,慢慢地将老版本系统中的流量迁移到新的服务器组中。等到所有的流量都切换过来后,回收老版本服务所在的服务器组,这就是所谓的双服务器组发布方式。

(双服务器组)蓝绿发布

蓝绿发布是蛮力发布的双服务器组版本,老版本服务所在的服务器组称为蓝组,新版本服务所在的服务器组称为绿组,发布的方式很简单,绿组部署完毕之后,不经过金丝雀发布或者滚动发布,直接修改 LB 的配置,将所有的流量直接切换到绿组,如果出现问题,回退也很简单,直接修改 LB 的配置,将所有的流量直接切回蓝组即可,主打的就是一个简单粗暴。

不过,发布初步成功后,蓝组机器一般不着急回收,而是保留一段时间,等绿组运行一段时间无误之后,再回收蓝组机器。

发布前:

发布后:

优势:

  • 升级切换和回退速度非常快

不足:

  • 切换是全量的,如果新版本有问题,则对用户体验有直接影响;

  • 需要两倍机器资源;

适用场合:

  • 对用户体验有一定容忍度的场景

  • 机器资源有富余或者可以按需分配(AWS 云,或自建容器云)

  • 暂不具备复杂滚动发布工具研发能力;

流量模式

(双服务器组)金丝雀发布

对蓝绿发布的一种简单优化,先从绿组中选择一部分机器接收 LB 转发过来的流量,经过一段时间的测试和用户反馈没有问题了,再将所有的的流量都切换到绿组,如果出问题了,则不再让绿组的这些金丝雀机器接收流量即可。

发布前:

从绿组中选择一部分机器当作金丝雀

发布完成

优势:

  • 用户体验影响小,金丝雀发布过程出现问题只影响少量用户
  • 避免了单机版金丝雀发布的很多问题

不足:

  • 需要两倍机器资源;

适用场合:

  • 对新版本功能或性能缺乏足够信心

  • 用户体验要求较高的网站业务场景

流量模式

(双服务器组)滚动式发布

跟单服务器组版本的滚动发布差不多,一般会先通过 LB 拉入一定比例的绿组机器进行功能测试,功能没有问题之后,后续的批次发布的时候,拉入多少比例的绿组机器,就要移出多少比例的蓝组机器,逐步替换,最终将所有的服务器都换为绿组机器,发布一个批次的机器之后需要留出一定时间进行观察再发布下一个批次,如果有问题则通过 LB 的流量切换快速回滚,没问题了再发布下一个批次,发布完成之后,蓝组需要保留一段时间,经过这段时间的运行没有问题之后,再回收蓝组的服务器资源。

发布前

找一定比例的绿组机器当金丝雀

滚动发布

发布完成

优势:

  • 用户体验影响小;

  • 升级切换和回退(rollback)速度比单服务器组滚动发布要快,LB 切流量即可;

不足:

  • 需要两倍机器资源;

  • 发布工具比较复杂,LB 需要流量切换能力

适用场合:

  • 用户体验不能中断的网站业务场景

  • 机器资源有富余或者可以按需分配(AWS 云,或自建容器云)

  • 有一定的发布工具研发能力;

流量模式

其他方式

上述都是偏传统的发布方式,能覆盖大部分应用发布场景。针对一些关键新功能的上线发布,或者一些特定的场景,还有一些特殊的发布方式。

功能开关发布

简单而言就是在开发的时候就将多版本的功能写在一起,通过 if-else 判断隔开,if 语句判断的表达式的结果会根据系统配置的改变而改变,代码部署之后,通过动态修改应用的配置,来启动新版本的功能。

这种发布方式一般需要启动一个配置中心服务,比如 Nacos。

携程的 Apollo 配置中心,或者开源的 FF4J,这些都支持开关发布,业界还有专门的功能开关 SaaS 服务,例如 LaunchDarkly

虽然不需要复杂的发布工具和智能 LB 配合,但是增加开发负担,代码冗余。不推荐这种方式,

优势:

  • 升级切换和回退速度非常快

  • 相对于复杂的发布工具,实施比较简单,成本相对低廉

  • 研发能够灵活定制发布逻辑,支持 DevOps 自助发布

不足:

  • 切换是全量的,如果 V2 版本有问题,则对用户体验有直接影响;

  • 对代码有侵入,代码逻辑会变复杂,需要定期清理老版本逻辑,维护成本变高

适用场合:

  • 对用户体验有一定容忍度的场景

  • 已有配置中心或开关中心服务

  • 暂不具备研发复杂发布工具能力;

流量模式

A/B 发布

A/B 发布的核心在于,先针对带有特定的流量/用户进行发布,经过测试没有问题之后,再发布给所有用户。

其实现方式为基于 LB,通过某种条件做流量路由,例如通过 client ip,设备类型,浏览器类型,甚至是定制的 HTTP Header 或查询字符串将请求路由到绿组的服务器。

高级的 A/B 测试需要专门的平台支撑,wasabi 就是 intuit 开源的一个支持高级 A/B 测试的平台,这类平台可以细粒度到针对某类用户做 A/B 测试,例如针对某个地区的用户,某个年龄段的用户,公司内部用户等等。举了例子,假设一个关键业务的新功能上线,为了降低风险采用 A/B 测试,可以做到先只让公司内部员工能访问到新功能,待新功能验证过,再全量放开给外部用户使用。

举个例子:原来 PC 端和手机端都访问老版本服务(蓝组),当新版本服务(绿组)发布以后,为了验证新版本功能正确性,同时也为了避免新版本有问题时影响所有用户,先通过 LB 将手机端的流量切换到绿组,经过一段时间的 A/B 比对测试和观察(主要通过用户和监控反馈),确保新版本功能正常,则通过 LB 将全部流量切换到绿组。

优势:

  • 用户体验影响小;

  • 可以使用生产流量测试;

  • 可以做到针对某类特定目标用户进行测试;

不足:

  • 搭建复杂度相对高,有一定技术门槛

适用场合:

  • 核心关键业务,比如涉及资金的

  • 具备一定的 A/B 测试平台研发能力

流量模式

影子测试

什么叫影子测试,简而言之,就是将生产的请求在测试环境重放,如果待检测的系统的请求响应跟生产环境的一致,则表示待检测的应用跟生产上正在跑的应用是等价的。

具体做法就是,在测试环境部署两套服务,一套是生产上正在跑的服务的复制(legacy),一套是待检测的服务(experimental),这两套服务除了代码以外跟生产环境都是相同的(包括数据库数据),然后我们将生产环境的服务接收的请求收集起来,到测试环境重放,或者直接将生产环境的请求转到到测试环境,让 legacy 和 experimental 处理这些请求,并观察响应,看是否一致,如果一致,则可以认为 legacy 服务和 experimental 服务在功能逻辑上是等价的;如果有响应比对失败,则认为两者在功能逻辑上不等价,需要修复 experimental 并重新进行影子测试,直到全部比对成功。

影子测试一般适用于遗留系统的等价重构迁移,例如 .net 转 Java,或者 SQLServer 数据库升级为 MySQL 数据库。根据系统复杂度和关键性不同,比对测试时间短的可能需要几周,长的可达半年之久。

影子测试因为旁路在独立测试环境中进行,可以对生产流量完全无影响。

优势:

  • 对生产用户体验完全无影响

  • 可以使用生产真实流量进行测试(复制比对)

不足:

  • 搭建复杂度很高,技术门槛高,数据库的导出复制是难点

  • 外部依赖不能太多,否则测试部署成本很高,且比对测试更加复杂和不稳定

适用场合:

  • 核心关键业务,比如涉及资金的

  • 具备一定影子测试平台研发能力,包括流量复制、数据库导出复制和分发比对系统。

流量模式

对比总结

下面是对发布策略的一些选型建议,供不同阶段公司参考:

  1. 蛮力发布一般是不建议采用的,除非是开发测试环境,用户体验不敏感的非关键应用,或者是创业期什么都缺时候的无奈之举。

  2. 如果暂时还不具备研发较复杂的滚动发布工具和配套智能 LB,则功能开关是一种不错的轻量级发布技术,投入相对较小的成本,可以让研发人员灵活定制发布逻辑。

  3. 金丝雀发布通过少量新版本服务器接收生产流量的方式去验证新版本,可以显著降低风险。金丝雀发布适用于大部分场景,一般成长型公司就可以采用。

  4. 对于达到一定业务体量的公司,考虑到用户体验对业务的关键性,则需要投入研发资源开发支持滚动式发布的工具和配套的智能 LB,实现自动化和零停机的发布。滚动式发布一般和金丝雀发布配合,先发一台金丝雀去验证流量,再按批次增量发布。

  5. 随着轻量级虚拟化(例如容器)的普及,双服务器组发布方式具有更快的发布和回退速度,是值得投入的高级发布技术。蓝绿部署仅适用于双服务器组,滚动式发布既可以在单服务器组上实现,也可以在双服务器组上实现。

  6. 对于涉及关键核心业务的新功能上线,采用 A/B 测试,可以显著降低发布风险,A/B 测试是唯一一种支持针对特定用户组进行生产测试的高级发布技术。当然 A/B 测试的投入不低,建议有一定研发能力的组织采用。

  7. 对于关键核心业务的迁移重构,为确保万无一失,最后的一个大招是影子测试,影子测试对生产流量和用户完全无影响。当然这个大招的投入成本和门槛都高,建议有足够业务体量和研发能力的组织投入。

上述的各种发布策略并不是非此即彼的,一个公司常常会综合采用多种发布技术作为互补,实现灵活的发布能力。例如主流的发布手段是金丝雀 + 滚动式发布,某些业务线可能根据业务场景需要采用功能开关发布,还有一些业务线则可能采用高级的 A/B 测试发布手段。

流行的应用发布工具

  • Jenkins:Jenkins 是一个流行的持续集成和交付工具,可以用于自动化构建、测试和部署应用程序。它支持滚动发布,可以根据需要逐步更新应用的不同版本。

  • Kubernetes:Kubernetes 是一个开源的容器编排平台,可以管理和调度应用程序的容器化部署。它提供了滚动更新的功能,可以逐步将新版本的应用部署到集群中的不同节点,实现无缝的应用更新。

  • KubeVela:KubeVela 是一个现代化的软件交付平台,它可以让你的应用交付在当今流行的混合、多云环境中变得更加简单、高效、可靠。

  • GitLab CI/CD:GitLab CI/CD是一个集成在GitLab版本控制系统中的持续集成和交付工具。它提供了滚动发布的功能,可以根据自定义的策略逐步更新应用程序的不同版本。

0%