gitbook/持续交付36讲/docs/14050.md
2022-09-03 22:05:03 +08:00

105 lines
9.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 23 | 业务及系统架构对发布的影响
在分享[《发布系统一定要注意用户体验》](https://time.geekbang.org/column/article/13552)和[《发布系统的核心架构和功能设计》](https://time.geekbang.org/column/article/13905)这两大主题时,我分别从用户体验和架构设计两个方面,和你分享了携程灰度发布系统的一些经验和实践。但是,要做出一个出色的发布系统,仅仅考虑这两方面还不够。
因为发布系统最终要服务的对象是业务应用,而业务应用又和业务、企业的系统架构有紧密的联系,所以要做好一套发布系统,我们还要考虑其要服务的业务及系统架构的需要,并且要善于利用系统架构的优势为发布系统服务。
那么接下来,我们就一起来看看,业务、企业整体的系统架构会给发布系统带来什么影响,发布系统又可以借用它们的哪些架构能力。
## 单机单应用还是单机多应用?
众所周知,.NET应用采用的基本都是Windows + IIS 的部署模式这是一种典型的单机、单Web容器、多应用的部署模式。
在这种模式下,单机多应用的问题主要体现在两个方面:
* 一方面应用划分的颗粒度可以做到非常细小往往一个单机上可以部署20~30个应用甚至更多而且应用与应用间的隔离性较差
* 另一方面由于IIS的设计问题不同虚拟目录之间可能存在共用应用程序池的情况即多个应用运行在同一个进程下导致任何一个应用的发布都可能对其他的关联应用造成影响。
所以,对发布系统而言,.NET应用的这种架构简直就是噩梦发布系统需要重新定义发布单元的含义并维护每个虚拟目录和对应的发布单元与应用之间的关系。
**在携程,我们为了解决这个问题采用的方案是,去除根目录的被继承作用,默认每个虚拟目录就是一个应用,并且每个虚拟目录的应用程序池独立。而每个虚拟目录以应用的名称命名,保证单机上不会发生冲突。**
这样,应用与应用之间就解耦了,发布系统的设计也会变得简单很多。
除了上面这种.NET的单机多应用情况无法改变外其他所有Linux下的应用都可以做到单机单应用。其实这也正是虚拟化思想最初的设计理念。为什么呢因为与单机多应用相比单机单应用更简单直接更易于理解和维护。
比如单机单应用不需要考虑分配服务端口的问题所有的Web应用都可以使用同一个统一端口比如8080端口对外服务。但是单机多应用的情况下就要考虑端口分配的问题这算不算是徒增烦恼呢
另外,单机单应用在故障排除、配置管理等方面同样具有很多优势。一言以蔽之,简单的才是最好的。
当然,**简单直接,也正是发布系统所希望看到的情况**。
## 增量发布还是全量发布?
增量发布还是全量发布,其实是个挺有意思的问题。
在过去网络带宽是瓶颈的年代里,或者面对体量巨大的单体应用时,增量发布可以节省很多计算资源,确实是一个很好的解决方案。甚至现在的移动客户端发布,也还会选择增量发布的技术来快速发布静态资源。
但是,互联网应用的场景下,更多的发布需求来自于发布频率非常高的后台服务。在这样的情况下,增量发布反而会造成不必要的麻烦。
比如,增量发布对回滚非常不友好,你很难确定增量发布前的具体内容是什么。如果你真的要确定这些具体内容的话,就要做全版本的差异记录,获取每个版本和其他版本间的差异,这是一个巨大的笛卡尔积,需要耗费大量的计算资源,简直就是得不偿失。很显然,这是一个不可接受的方案。
反之,全量发布就简单多了,每个代码包只针对一个版本,清晰明了,回滚也非常简单。所以,**我的建议是,全量发布是互联网应用发布的最好方式。**
## 如何控制服务的 Markup 和 Markdown
首先你需要明确一件事儿除了发布系统外还有其他角色会对服务进行Markup和Markdown操作。比如运维人员在进行机器检修时人为的Markdown操作。因此我们需要从发布系统上能够清晰地知晓服务的当前状态和最后进行的操作。
另外这里还引入了一个全新的问题当一个服务被执行Markdown操作后什么系统还能继续处理这个服务而什么系统则不能继续处理这个服务
比如发布系统如果发现服务最后进行的操作是Markdown那么还能不能继续发布呢如果发布那发布之后需不需要执行Markup操作呢有些情况下用户希望利用发布来修复服务因此需要在发布之后执行Markup而有些情况下用户发布后不能执行Markup很可能运维人员正在维护网络。
为了解决这个问题,**携程在设计系统时用不同的标志位来标识发布系统、运维操作、健康检测以及服务负责人对服务的Markup和Markdown状态。4个标志位的任何一个为Markdown都代表暂停服务只有所有标志位都是Markup时服务中心才会向外暴露这个服务实例。**
这样做的好处是将4种角色对服务的操作完全解耦他们只需要关心自己的业务逻辑既不会发生冲突也不会影响事务完整性更无需采用其他复杂的锁和Token机制进行排他操作。
## 检查、预热和点火机制
我在分享从用户体验和核心架构的角度设计发布系统时提到过发布过程中必然会有Verify的过程。
如果这个过程依赖手工操作的话,一来难以保证发现问题的速度,二来也很难保证落实力度。但如果这个过程能够做到自动化的话,则可以大幅减少因发布而引发的生产故障,同时还可以保证一些服务启动依赖检测。
在携程我们借助于VIValidate Internal框架中间件实现了Verify过程的自动化我们把这个过程形象地叫作“点火”。所有使用这个中间件的应用启动后发布系统执行的第一个操作就是这个VI接口所提供的检查方法当然用户完全可以根据业务自定义应用的检查方法。这也就保证了发布过程中一定会执行到Verify过程而不会因为各种原因而被遗漏。
Verify是一个异步过程可能耗时较长但是程序员们很快就发现这个VI组件不但可以做检查还可以在检查时进行一些预热、预加载这样的任务。
携程通过这样一个中间件组件,很高效地解决了发布过程中的两个问题:
1. 如何对各个应用做个性化的自动化检查;
2. 如何在发布过程中解决应用预加载这类的需求。
## 如何保证堡垒流量?
我在[《发布是持续交付的最后一公里》](https://time.geekbang.org/column/article/13380)这篇文章中介绍金丝雀发布时,说到了携程选择的是综合使用滚动发布和金丝雀发布的方案,使用堡垒机的方式来预发和测试新的版本。
但是采用这个方案我们需要考虑分布式服务架构带来的影响即如何保证堡垒机的流量一定会分发到对应下游服务的堡垒机上。就好比发布一个包含Web和Service两个应用的新功能我需要保证Web堡垒的流量只发送给Service的堡垒否则就会出问题。
我们解决这个问题的思路是软负载系统通过发布系统获得堡垒机的IP在堡垒机发出的请求的header中附加堡垒标识这样软负载在判断出有堡垒标识时则只会将请求发向下游的堡垒机。当然是否加注这个标识完全由发布系统在发布堡垒时控制。
这样,我们就解决堡垒流量控制的问题。
## 总结
因为发布系统最终服务的对象是业务应用,所以发布系统的设计除了考虑用户体验、核心架构外,还要注意业务、系统架构对发布系统的影响,并且要合理利用业务、系统架构的能力,去完善发布系统的设计。
业务、系统架构对发布系统的影响,主要体现在是选择单机单应用还是单机多应用、选择增量发布还是全量发布这两大方面。在这里,我的建议是简单的才是最好的,即采用单机单应用的部署架构;对于后台应用,以及发布非常频繁的应用来说,全量发布更直接,更容易达成版本控制,并做到快速回滚。
除此之外,我们还要利用系统架构使发布系统具有更优的发布能力,这主要包括三个方面:
1. 利用软负载或者服务通讯中间件的多个状态位简单直接地解决多角色对服务Markup和Markdown的冲突问题
2. 利用中间件的能力使得Verify过程不会被遗忘同时还可以完成自动化检查和预热达到高效可控的目的
3. 通过软负载和通讯中间件,解决堡垒机与堡垒机间的流量分发问题,保证堡垒机的流量只在上下游服务的堡垒机中流转。
因此,有效运用系统架构的能力,会为你带来意想不到的收益。
## 思考题
在你的实际工作中,发布系统有没有受到架构设计的影响?是积极影响还是消极影响呢?消极影响的话,你有想过如何改变吗?
感谢收听,欢迎你给我留言。