赞
踩
微服务体系架构中,服务之间的依赖关系错综复杂,有时某个功能发版依赖多个服务同时升级上线。我们希望可以对这些服务的新版本同时进行小流量灰度验证,这就是微服务架构中特有的全链路灰度场景,通过构建从网关到整个后端服务的环境隔离来对多个不同版本的服务进行灰度验证。
在发布过程中,我们只需部署服务的灰度版本,流量在调用链路上流转时,由流经的网关、各个中间件以及各个微服务来识别灰度流量,并动态转发至对应服务的灰度版本。如下图:
上图可以很好展示这种方案的效果,我们用不同的颜色来表示不同版本的灰度流量,可以看出无论是微服务网关还是微服务本身都需要识别流量,根据治理规则做出动态决策。当服务版本发生变化时,这个调用链路的转发也会实时改变。相比于利用机器搭建的灰度环境,这种方案不仅可以节省大量的机器成本和运维人力,而且可以帮助开发者实时快速的对线上流量进行精细化的全链路控制。
那么全链路灰度具体是如何实现呢?通过上面的讨论,我们需要解决以下问题:
1.链路上各个组件和服务能够根据请求流量特征进行动态路由
2.需要对服务下的所有节点进行分组,能够区分版本
3.需要对流量进行灰度标识、版本标识
4.需要识别出不同版本的灰度流量
下面将借着介绍 OpenSergo 对于流量路由所定义的 v1alpha1 标准,来告诉大家实现全链路灰度所需的技术细节。
Q:OpenSergo 是什么?
A:OpenSergo 是一套开放、通用的、面向分布式服务架构、覆盖全链路异构化生态的服务治理标准,基于业界服务治理场景与实践形成服务治理通用标准。OpenSergo 的最大特点就是以统一的一套配置/DSL/协议定义服务治理规则,面向多语言异构化架构,做到全链路生态覆盖。无论微服务的语言是 Java, Go, Node.js 还是其它语言,无论是标准微服务或 Mesh 接入,从网关到微服务,从数据库到缓存,从服务注册发现到配置,开发者都可以通过同一套 OpenSergo CRD 标准配置针对每一层进行统一的治理管控,而无需关注各框架、语言的差异点,降低异构化、全链路服务治理管控的复杂度
Q:为什么了解全链路灰度之前先给我介绍 OpenSergo?
A:OpenSergo 定义了一套统一的 YAML 配置方式来针对分布式架构进行全链路的服务治理的规范,介绍规范与标准的同时,我们可以了解其中的技术细节的实现,同时我们还可以将新的组件与 OpenSergo 的标准进行实现。
流量路由,顾名思义就是将具有某些属性特征的流量,路由到指定的目标。流量路由是流量治理中重要的一环,开发者可以基于流量路由标准来实现各种场景,如灰度发布、金丝雀发布、容灾路由、标签路由等。
全链路灰度示例:
流量路由规则(v1alpha1) 主要分为三部分:
我们可以赋予标签不同的语义,从而实现各个场景下的路由能力。
需要将具有某些属性特征的流量,打上对应的标签。
假设现在需要将内部测试用户灰度到新版主页,测试用户 uid=12345,UID 位于 X-User-Id header 中:
- apiVersion: traffic.opensergo.io/v1alpha1
- kind: TrafficLabelRule
- metadata:
- name: my-traffic-label-rule
- labels:
- app: my-app
- spec:
- selector:
- app: my-app
- trafficLabel: gray
- match:
- - condition: "==" # 匹配表达式
- type: header # 匹配属性类型
- key: 'X-User-Id' # 参数名
- value: 12345 # 参数值
- - condition: "=="
- value: "/index"
- type: path
通过上述配置,我们可以将 path 为 /index,且 uid header 为 12345 的 HTTP 流量,打上 gray 标,代表这个流量为灰度流量。
那么如何给服务节点添加不同的标签呢?在如今火热的云原生技术推动下,大多数业务都在积极进行容器化改造之旅。这里,我就以容器化的应用为例,介绍在使用 Kubernetes Service 作为服务发现和使用比较流行的 Nacos 注册中心这两种场景下如何对服务 Workload 进行节点打标。
在使用 Kubernetes Service 作为服务发现的业务系统中,服务提供者通过向 ApiServer 提交 Service 资源完成服务暴露,服务消费端监听与该 Service 资源下关联的 Endpoint 资源,从 Endpoint 资源中获取关联的业务 Pod 资源,读取上面的 Labels 数据并作为该节点的元数据信息。所以,我们只要在业务应用描述资源 Deployment 中的 Pod 模板中为节点添加标签即可。
在使用 Nacos 作为服务发现的业务系统中,一般是需要业务根据其使用的微服务框架来决定打标方式。如果 Java 应用使用的 Spring Cloud 微服务开发框架,我们可以为业务容器添加对应的环境变量来完成标签的添加操作。比如我们希望为节点添加版本灰度标,那么为业务容器添加 http://traffic.opensergo.io/label: gray ,这样框架向 Nacos 注册该节点时会为其添加一个 gray 标签。
对于一些复杂的 workload 打标场景(如数据库实例、缓存实例标签),我们可以利用 WorkloadLabelRule CRD 进行打标。示例:
- apiVersion: traffic.opensergo.io/v1alpha1
- kind: WorkloadLabelRule
- metadata:
- name: gray-sts-label-rule
- spec:
- workloadLabels: ['gray']
- selector:
- app: my-app-gray
请求链路上各个组件如何识别出不同的灰度流量?答案就是流量染色,为请求流量添加不同灰度标识来方便区分。我们可以在请求的源头上对流量进行染色,前端在发起请求时根据用户信息或者平台信息的不同对流量进行打标。如果前端无法做到,我们也可以在微服务网关上对匹配特定路由规则的请求动态添加流量标识。此外,流量在链路中流经灰度节点时,如果请求信息中不含有灰度标识,需要自动为其染色,接下来流量就可以在后续的流转过程中优先访问服务的灰度版本。
目前在 OpenSergo v1alphal1 并未详细定义流量染色这一块的标准,可以后续社区一起讨论来设计流量染色标准。Apache APISIX 也会适配实现 OpenSergo 的标准,开发者可以通过同一套 OpenSergo CRD 标准配置针对流量网关层进行统一的治理管控,可以释放基于 Apache APSIX 的微服务架构的新价值。
全链路灰度是微服务最核心的功能之一,也是云上用户在微服务化深入过程中必须具备的功能。全链路灰度因为涉及到的技术和场景众多,如果企业一一进行自我实现,需要花费大量人力成本对其进行扩展与运维。
介绍完技术,下面来介绍一下阿里云上基于 Apache APISIX 的全链路灰度的产品实践。
APISIX 架构如下图所示,我们需要安装 APISIX。
1.安装 apisix、apisix-ingress-controller、etcd 等组件
- helm repo add apisix https://charts.apiseven.com
- helm repo add bitnami https://charts.bitnami.com/bitnami
- helm repo update
- kubectl create ns ingress-apisix
- helm install apisix apisix/apisix \
- --set gateway.type=LoadBalancer \
- --set ingress-controller.enabled=true \
- --set etcd.persistence.storageClass="alicloud-disk-ssd" \
- --set etcd.persistence.size="20Gi" \
- --namespace ingress-apisix \
- --set ingress-controller.config.apisix.serviceNamespace=ingress-apisix
- kubectl get service --namespace ingress-apisix
看到在 ingress-apisix命名空间下看到无状态 apisix、apisix-ingress-controller 应用、以及有状态的 etcd 应用
2.安装 APISIX Admin
- helm repo add apisix https://charts.apiseven.com
- helm repo update
- helm install apisix-dashboard apisix/apisix-dashboard --namespace ingress-apisix
安装完成后,可以绑定一个 SLB
通过{slb-ip}:9000 访问 APISIX 控制台(默认密码admin/admin)
这一步骤中,需要开通 MSE 微服务治理、安装 MSE 服务治理组件(ack-onepilot)并为应用开启微服务治理。具体操作信息可参考阿里云官方教程:https://help.aliyun.com/product/123350.html
在阿里云容器服务中部署 A、B、C 三个应用,每个应用分别部署⼀个base 版本和⼀个gray 版本;并部署⼀个 Nacos Server 应用,用于实现服务发现。具体可参考此教程完成应用部署:部署Demo 应用程序。部署完成后,你可以通过 APISIX Dashboard 为应用配置 Service 进行上游配置。
有些客户端没法改写域名,希望能访问 http://www.demo.com 通过传入不同的参数来路由到灰度环境。例如下图中,通过 env=gray 这个请求参数,来访问灰度环境。
调用链路 Ingress-APISIX -> A -> B -> C ,其中 A 可以是一个 spring-boot 的应用。
在 APISIX Dashboard 选择路由并单击创建。匹配条件中新建高级匹配规则、请求路径选择 /*,选择对应的上游。分别配置如下路由:
然后进行 base 对应的路由配置:
- {
- "uri": "/*",
- "name": "spring-cloud-a",
- "methods": [
- "GET",
- "POST",
- "PUT",
- "DELETE",
- "PATCH",
- "HEAD",
- "OPTIONS",
- "CONNECT",
- "TRACE"
- ],
- "host": "www.demo.com",
- "upstream_id": "401152455435354748",
- "labels": {
- "API_VERSION": "0.0.1"
- },
- "status": 1
- }
进行 gray 对应的路由配置,如下图所示:
- {
- "uri": "/*",
- "name": "spring-cloud-a-gray",
- "priority": 1,
- "methods": [
- "GET",
- "POST",
- "PUT",
- "DELETE",
- "PATCH",
- "HEAD",
- "OPTIONS",
- "CONNECT",
- "TRACE"
- ],
- "host": "www.demo.com",
- "vars": [
- [
- "arg_env",
- "==",
- "gray"
- ]
- ],
- "upstream_id": "401163331936715388",
- "labels": {
- "API_VERSION": "0.0.1"
- },
- "status": 1
- }
你需要配置完成 MSE 的全链路发布,具体操作细节可参考此教程:配置全链路灰度。
此时,访问 http://www.demo.com 路由到 基线环境
- curl -H"Host:www.demo.com" http://47.97.253.177/a
- A[172.18.144.15] -> B[172.18.144.125] -> C[172.18.144.90]%
此时,访问 http://www.demo.com 同时env=gray时路由到灰度环境
- curl -H"Host:www.demo.com" http://47.97.253.177/a?env=gray
- Agray[172.18.144.16] -> Bgray[172.18.144.57] -> Cgray[172.18.144.157]%
注意:其中 47.97.253.177 为 APISIX 的公网 IP
目前 MSE 服务治理全链路灰度能力已经支持了云原生网关、ALB、APISIX、Apache Dubbo、Spring Cloud、RocketMQ 以及数据库。
基于 Apache APISIX 灵活的路由能力,配合 MSE 全链路灰度能力,可以快速实现企业级的全链路灰度的能力。APSIX 支持按照 Header、Cookie、Params、域名等多种方式进行路由,只需要在网关侧根据需求将流量路由至不同的“泳道”环境后,流量在对应标签的“泳道”中自动闭环,当泳道中并不存在调用链中所依赖的其他服务时,流量需要回退至基线环境,进一步在必要的时候路由回对应标签的泳道。
服务治理是微服务改造深入到一定阶段之后的必经之路,在这个过程中我们不断有新的问题出现。
当我们在探索服务治理的过程中,我们在对接其他微服务的时候,我们发现治理体系不同造成的困扰是巨大的,打通两套甚者是多套治理体系的成本也是巨大的。为此我们提出了 OpenSergo 项目。OpenSergo 要解决的是不同框架、不同语言在微服务治理上的概念碎片化、无法互通的问题。
相关链接
作者:十眠
本文为阿里云原创内容,未经允许不得转载。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。