赞
踩
李鑫 架构头条 今天
作者 | 李鑫
当微服务完成开发、测试后,就可以通过发布服务将其发布到线上。如果只看一个服务节点的部署,貌似是一项非常简单的工作,但如果同时发布成百上千个服务节点,尤其是需要在不影响线上业务的前提下完成发布工作,就会变得比较复杂。
批量发布是风险度较高的事情,很大一部分线上事故都是由发布引起的。为了控制风险,需要对发布做足监控,将所有发布步骤在监控大盘上进行实时展示,如果出现发布问题,则应及时告警,并提供完善的回滚功能。
1微服务的部署
包部署模式
以应用包或服务包的方式进行的部署工作,大部分是在非容器环境的物理机或虚拟机上进行的。如图 4.18 所示,在多机房情况下,每个机房都会有发布调度服务器,同时软件版本仓库在每个机房也都会有相应的镜像服务。
图 4.18 微服务的包部署模式
服务部署包分发
当发布指令从调度中心下发后,每个机房的发布调度服务器会通知本机房内应用服务器集群中的每个服务节点到本机房的软件版本仓库下载对应的服务发布包。
这里要注意的是,如果服务节点过多,同时下载微服务的部署包可能会产生瞬时的“网络风暴”,导致网络被堵塞。因此,在下载调度上需要做一些优化,让这些服务节点分批下载,或者控制能同时下载的服务节点的数量。
服务状态检测
每个服务节点上新的服务部署包下载完成后,就要停止当前运行的服务进程,部署新版本服务。
在停止服务时,由于服务上有正在运行的请求,需要等待这些请求处理完毕,同时不让新的请求进来,这就是所谓的“优雅停机”。可以通过服务注册中心将该服务节点直接删除,或者通过调整该服务节点的路由权重为 0 来控制不再有新的请求进入该服务节点。另一方面,可以通过一些系统钩子(如 JVM 中的 shutdownhook)来实现等待所有请求处理完毕再关闭应用的功能,同时做一些资源清理工作。
新版本服务启动后,会自动到服务注册中心进行登记注册,并重新恢复路由权重。这样,新的请求会重新被路由到该服务节点。
分批发布
微服务的发布如果要做到线上业务无感,就必须控制同时进行上、下线操作的服务节点的数量。因为如果一个服务集群中过多的节点下线,则剩余的节点可能无法负担当时线上所有的请求流量,所以针对服务发布,必须能控制同时进行上、下线操作的服务节点的数量或比例。
服务发布执行
在图 4.18 中,发布调度服务器承担了“大脑”的作用,由它提供分批发布策略并向各个服务节点发出发布指令。微服务本身属于被操作的“物料”,在服务节点上还需要有发布操作的“执行人”。承担执行人角色的可以是集成在服务节点中的 Agent,这个 Agent 是一个独立的进程,在服务节点启动后同步启动运行,并不断监听发布调度服务的指令,收到具体发布指令后,由其执行具体的发布策略。
除了独立部署的 Agent,还可以采用以 Ansible 为代表的无代理的远程配置管理工具,以直接通过 SSH 协议对服务节点进行发布操作管理。使用 Ansible 的最大好处是,不需要在服务节点上部署 Agent 程序,减少了 Agent 带来的稳定性风险,降低了整体维护成本。
不论是 Agent,还是远程配置管理工具,在服务发布上基本都遵循相似的步骤。
1)检查环境:检测系统环境是否正常,相关技术栈是否完备;
2)下载部署包:参考指定软件版本下载部署物料;
3)关闭服务监控:关闭服务监控,防止部署过程中产生大量报错信息,但部署监控必须开启;
4)服务下线:服务注册中心将该服务节点直接删除,或者调整该服务节点的路由权重为 0 来控制不再有新的请求进入该服务节点;
5)停止服务:发出进程关闭信息,通过“优雅停机”的方式在所有存量请求处理完毕之后,关闭服务进程;
6)部署服务:部署新服务的部署包;
7)启动服务:启动服务进程;
8)健康检测:检测服务是否正常启动,进程是否正常,并在服务注册中心中正常注册;
9)开启服务监控:服务启动成功并正常注册后,开启服务监控。
容器化部署模式
在容器编排领域,K8S(Kubernetes)已经成了事实上的王者。本节中,就以 K8S 为例,讨论如何进行 P2P 直连模式微服务的部署。
首先了解 K8S 的两个关键概念:Pod 和 Service。
如果设定一个 Pod 的实例由基础容器 Pause 和一个业务容器组成,并且这个业务容器只运行微服务的某一个服务节点,就可以让 K8S 和微服务在“服务”这个概念上达成一致,如图 4.19 所示。
图 4.19 微服务和 K8S 在架构上的映射及融合
如图 4.19 所示,微服务中的服务对应 K8S 中的 Service,服务节点对应 Pod 中的业务容器。这样,只要将每个微服务打包成容器镜像,并在创建对应 Pod 资源的时候,将服务名称以标签的形式写入资源清单文件中,就可以利用 Label Selector 过滤出相关的服务 Pod,并通过 K8S 进行上线、下线、扩容、缩容操作。
混合部署模式
与服务化类似,大部分企业的容器化之路也不是一蹴而就的。企业内部的 IT 环境会长期处于新旧混搭的状态,基础资源层除了 K8S 提供的容器服务,可能还存在 IaaS 云平台(公有云或私有云),甚至还存在传统的物理机。整个微服务集群混部在这些不同的环境中,新增加的 K8S 容器服务平台需要能与原有的资源平台共存,如图 4.20 所示。
图 4.20 微服务集群的混部
以上架构会导致一个网络问题,Pod 的 IP 地址只在 K8S 容器集群里可见,无法和容器集群外的微服务交互,相当于 K8S 容器集群内、外形成了两个网络域。
为了解决这个问题,可以使用第三方开源的网络组件 Calico,结合物理核心交换机做策略优化,基于 BGP 协议将容器集群的内、外两个网络连接在一起,使得 K8S 集群外的主机能访问到 Pod 的 IP 地址,网络架构如图 4.21 所示。
它的原理如下。
1)Calico 将所有的 Node 主机变成了路由器,并将该 Node 主机上存在的所有网段信息都汇报给路由反射器(核心交换机),包括该主机上运行的 Pod 网络;
图 4.21 通过 BGP 网络解决 K8S 集群内、外网络访问问题
2)配置核心交换机以路由反射器(Route Reflector)的角色与其他节点建立 BGP 邻居关系;
3)K8S 集群外的主机只要能连接到核心交换机,就可以获取抵达所有 Pod 地址的路由信息。
2蓝绿发布
蓝绿发布是一种历史悠久的服务端应用发布模式,不仅适用于分布式应用或服务,而且也适用于大量的单体应用,它能有效缩短发布导致的业务中断时间,并且能够在发布版本出现问题时快速回退。
蓝绿发布的核心思想是新旧两套服务共存。新系统的发布由于不涉及旧系统,自然不需要使用蓝绿发布,所以直接发布就行了,只有存量服务的升级才需要使用蓝绿发布。所以,准确地说,蓝绿发布主要应用于服务的升级。
图 4.22 是蓝绿发布的示意图,蓝绿发布包含如下几个步骤。
1)部署开始前,线上只有旧版本(蓝集群)的服务在运行。
2)在线上部署服务的新版本(绿集群),并在线上进行充分测试。
图 4.22 蓝绿发布示意图
3)调整路由及负载均衡策略,将流量统一切换到新版本(绿集群),但旧服务(蓝集群)不下线。此时两套集群并存,只是旧集群没有流量,一旦新版本服务出现异常,通过调整路由及负载均衡策略,快速切换回旧版本(蓝集群)。
4)新版本(绿集群)线上稳定运行无异常后,将旧版本服务(蓝集群)下线,发布结束。
采用蓝绿发布模式,由于新旧两套服务集群并存,所以一旦发布过程出现异常,回滚速度会比较快,只要切流量即可。但这种发布模式在发布过程中,需要额外占用一套线上资源。
3灰度发布
灰度发布是专门针对分布式、多节点的应用或服务的发布方式,和蓝绿发布不同,它不需要额外的资源。它利用现有服务集群,通过分批替换的方式将风险控制在可接受范围内,以减少发布后的质量风险。
灰度发布目前也是互联网企业的主流发布模式。这些企业一般都构建了完善的灰度发布平台,利用该平台,运维人员可以在服务集群中设定发布批次,并同步将用户(流量)进行划分,根据功能、兼容性、并发和性能选定发布批次对应的用户(流量)范围,分批平滑发布,逐渐扩大范围,同时将选定的线上用户路由到新版本上,实时收集用户反馈来验证发布效果,以决定是继续发布还是回滚。图 4.23 就是典型的灰度发布过程,服务节点和用户流量同步进行阶梯切换。
图 4.23 典型的灰度发布过程
在灰度发布的用户选择上,除了考虑集群的负载,还可以根据实际需要灵活切分,一般会优先使用用户区域、用户级别、用户设备等属性。所有选择都通过灰度发布平台控制,灰度发布平台同时要和监控系统紧密结合,以对较长时段的发布过程进行全程监控。
金丝雀测试
在灰度发布中,第一批(或前 N 批)发布的服务节点及被切流到该节点上的用户流量具有特殊意义,它们往往扮演了“先行者”的角色,大部分异常都能在第一批发布中被发现。由于第一批(前 N 批)发布的范围非常小(一般不超过 1%),影响范围有限,因此又把第一批(前 N 批)发布单独称为“金丝雀测试”。
“金丝雀测试”的覆盖范围很小,所针对的用户群体可以限制在很小的可控范围之内。就像笔者目前所负责的在线金融业务,每当一个较大的功能上线时,一般都会先让部门内部员工承担“金丝雀”的角色,再将范围扩大到公司员工,然后基于特定规则(地区、机型、年龄等)挑选一批用户。
“金丝雀测试”无误后,就可以进行全量滚动发布了。
小贴士:
矿井工人面临的一大风险就是井下的瓦斯爆炸,后来人们发现,金丝雀对瓦斯气体非常敏感,只要空气中存在极其微量的瓦斯气体,金丝雀就会停止歌唱或死亡。因此,在采矿设备不发达的古代,矿井工人每次下井都会带上一只金丝雀,并根据金丝雀的表现来判定是否有瓦斯,以便在危险来临前及时撤离。
基于版本号的灰度发布
对服务的升级,会遇到两种情况。第一种情况是接口不变,只是代码本身进行完善。这种情况处理起来比较简单,因为提供给使用者的接口、方法都没有变,只是内部的服务实现有变化。在这种情况下,采用上述灰度发布的方式验证后全部发布即可。第二种情况是需要修改原有的接口,如果只是在接口中增加新方法,可以参考第一种情况处理。复杂的是接口方法的参数列表被修改了,这时就需要有相应的手段来区分新旧接口方法,比较通用的办法是通过增加服务接口的版本号来解决,使用老方法的系统继续调用原来版本的服务,需要使用新方法的系统则使用新版本的服务。这意味着,在服务框架中,必须通过“服务接口 + 版本号”的方式来唯一区分服务(在服务多租户的模式下,还需要加入分组 group)。基于版本号的灰度发布升级如图 4.24 所示。
在图 4.24 中,C1 代表服务调用方(消费者,Consumer),P1 代表服务提供方(提供者,Provider),V1、V2 代表版本号。总体流程是,找一个访问低谷,先将一部分服务提供方升级为新版本,接着将所有服务调用方升级成新版本,最后将剩余的服务提供方升级成新版本。这个过程涉及流量的各种调整,具体可以参考图 4.24 中的各个步骤。
图 4.24 基于版本号的灰度发布升级
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。