观看直播回放:https://yqh.aliyun.com/live/detail/29692
微服务治理与 OpenSergo
随着微服务(MicroServices) 理念的兴起,让大规模、高并发、低延迟的分布式应用成为可能。但是微服务架构是一把双刃剑,随着微服务架构复杂化,在大规模之下,再小的问题都会牵一发而动全身,因此随着微服务架构增长,如果不对微服务进行恰当的治理,微服务架构带来的效率、稳定性问题很可能会远大于微服务本身带来的架构红利。可以说,现代微服务架构的四大件:服务提供者、服务消费者、注册配置中心,当然还有容易被大家忽视但又十分重要的一点,那就是微服务治理。微服务治理的使命就是对微服务体系中的各个组件与环节进行治理,可以说做好微服务治理那就是把微服务做稳做好的必不可少的一环。
在企业内部,往往存在着不同语言、不同通信协议的微服务,这种异构化的架构会导致治理微服务的过程中,业务开发者、架构师无法用统一的方式来对所有服务进行治理管控,并且这类异构会衍生出更多的痛点:
- 业内对服务治理的能力和边界没有明确的认识,每个企业所定义的服务治理概念不一致,造成很高的理解和沟通成本。
- 开源微服务框架众多,对于服务治理缺乏一些标准化的约定。例如,Spring Cloud 中定义的微服务接口和 Dubbo 中定义的接口就没有办法互通,通过 Dubbo 和 Istio 管理的微服务也没有办法进行统一治理。开发者无法通过统一的配置方式来对不同框架、不同语言的服务进行统一治理管控。
- 缺少真正面向业务、能够减轻认知负担的抽象和标准。开发者真正想要的可能是简单的、指定服务间的调用关系和配置规则。但现在对于业务开发者来说,不仅需要了解不同微服务框架的部署架构,也要了解不同服务治理方式的概念和能力区别,认知成本很大。
基于上面这些痛点,阿里巴巴在2022年1月开始和 bilibili、CloudWego等厂商、社区讨论服务治理如何规范化和更加普及,从而共同发起了 OpenSergo 项目。
OpenSergo 是开放通用的,覆盖微服务及上下游关联组件的微服务治理项目,从微服务的角度出发,涵盖流量治理、服务容错、服务元信息治理、安全治理等关键治理领域,提供一系列的治理能力与标准、生态适配与最佳实践,支持 Java, Go, Rust 等多语言生态。OpenSergo 的最大特点就是以统一的一套配置/DSL/协议定义服务治理规则,面向多语言异构化架构,做到全链路生态覆盖。对于开发者来说可以通过同一套 OpenSergo CRD 标准配置针对微服务架构涉及到的每一个组件进行统一的治理管控,而无需关注各框架、语言的差异点,降低异构化、全链路服务治理管控的复杂度。
下面我们将从流量路由这个场景入手,从常见的微服务治理场景出发。先是根据流量路由的实践设计流量路由的 Spec,同时在 Spring Cloud Alibaba 中实践遵循 OpenSergo 标准的流量路由能力。
流量路由
流量路由,顾名思义就是将具有某些属性特征的流量,路由到指定的目标。流量路由是流量治理中重要的一环,我们可以基于流量路由标准来实现各种场景,如全链路灰度、标签路由、金丝雀发布等。
标签路由
标签路由是按照标签为维度对目标负载进行划分,符合条件的流量匹配至对应的目标,从而实现标签路由的能力。当然基于标签路由的能力,赋予标签各种含义我们就可以实现各种流量路由的场景化能力。
金丝雀发布
金丝雀发布是一种降低在生产中引入新软件版本的风险的技术,方法是在将更改推广到整个基础架构并使其可供所有人使用之前,缓慢地将更改推广到一小部分用户。金丝雀发布是一种在黑与白之间,能够平滑过渡的一种发布方式。让一部分用户继续用旧版本,一部分用户开始用新版本,如果用户对新版本没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到新版本上面来。一直都有听说,安全生产三板斧的概念:可灰度、可观测、可回滚。那么灰度发布能力就是帮助企业软件做到快速迭代验证的必备能力。
在K8s中金丝雀发布的最佳实践如下:第一步:新建灰度 Deployment,部署新版本的镜像,打上新版本的标签。第二步:配置针对新版本的标签路由规则。第三步:验证成功,扩大灰度比例。第四步:若验证成功,将稳定版本的应用更新成最新镜像;若验证失败,把灰度的 Deployment 副本数调整到 0 或删除该 Deployment。
全链路灰度
全链路灰度发布就是通过线上多个应用部署灰度版本,灰度流量全部进入灰度版本,正常流量进入生产版本。灰度版本只针对灰度流量验证,有效减少风险。我们可以通过流量路由结合流量染色可以实现全链路的流量灰度能力。
流量路由标准化
业界微服务治理存在概念不统一、配置形式不统一、能力不统一、多框架统一管控较为复杂等问题。比如我们希望实现流量路由的能力,在 Spring Cloud 中可能需要通过 Spring Cloud 动态规则的方式进行配置,在 istio 中可能又是另一套配置方式,在其它组件上可能又是不同的配置。不同框架治理配置方式的不一致使得微服务统一治理管控的复杂度相当高。为此我们需要通过OpenSergo实现一套标准化的流量路由能力与实践,这样在任 OpenSergo生态中的组件上需通过配置 OpenSergo TrafficRouter 规则,即可实现一致的流量路由能力。
我们在实践了许多流量路由的场景后,将流量路由规则进行了如下的设计与抽象。
OpenSergo 的流量路由规则 (v1alpha1) 主要分为如下:
- Workload 集合的抽象 (
VirtualWorkloads
):将某一组VirtualWorkload
(如 Kubernetes Deployment, Statefulset 或者一组 pod,或某个 JVM 进程,甚至是一组 DB 实例)按照一定的特征进行分类。 - 流量标签规则 (
RouterRule
):将特定特征的流量映射至特定特征所对应的 VirtualWorkloads 上。 - 路由链规则(
RouterChain
)将特定的RouterRule
跟VirtualWorkloads
按照一定逻辑排列组合成 pipeline。
Workload 集合的抽象 (VirtualWorkloads
)
VirtualWorkloads
虚拟工作负载集合的抽象即 VirtualWorkload 集合,其中会将 VirtualWorkload 按照一定的特征进行分类。
VirtualWorkload
虚拟工作负载即 workload 集合的抽象,将一定属性特征的 workload 集合划分成一个 VirtualWorkload,其中 VirtualWorkload 可以是目标 service 集合也可以是 deployment,甚至可以是 database 的实例、库、表集合。
对于通用的 workload 场景,我们可以利用 VirtualWorkloads CRD 进行描述。特别地,对于 Kubernetes workload,我们可以通过直接在 workload 上打 label 的方式进行特征标记,如在 Deployment 上打上 traffic.opensergo.io/label: gray
标签代表当前 Deployment 的标签特征为 gray。
一个标准的 workloads 描述应该类似于:
apiVersion: traffic.opensergo.io/v1alpha1 kind: VirtualWorkloads metadata: name: tag-rule spec: selector: app: my-app virtualWorkload: - name: my-app-gray target: my-app-gray-deployment type: deployment selector: tag: gray
流量路由规则 (RouterRule
)
流量路由规则 (RouterRule
) 将特定特征的流量映射至特定特征所对应的 VirtualWorkloads 上。
假设现在需要将内部测试用户灰度到新版主页,测试用户 uid=12345,UID 位于 X-User-Id header 中,不符合条件的外部用户流量访问原版主页。那么只需要配置如下 CRD 即可:
apiVersion: traffic.opensergo.io/v1alpha1 kind: RouterRule metadata: name: tag-traffic-router-rule spec: selector: app: my-app http: - name: my-traffic-router-http-rule rule: match: header: X-User-Id: # 参数名 exact: 12345 # 参数值 uri: exact: "/index" targets: - workloads: my-app-worksloads name: gray target: workloads: my-app-worksloads name: base
通过上述配置,我们可以将 path 为 /index
,且 uid header 为 12345 的 HTTP 流量为灰度流量,访问灰度版本的新版主页。
标签路由场景的流量路由配置
假设我们希望 Header x-user-id为123的流量访问 spring-cloud-a 的具备 gray 标签的实例。其中 spring-cloud-a 的标签情况如下:
那么我们需要配置对应的 TrafficRouterRule 配置如下:
apiVersion: traffic.opensergo.io/v1alpha1 kind: TrafficRouterRule metadata: name: tag-traffic-router-rule spec: selector: app: spring-cloud-a http: - name: my-traffic-router-http-rule rule: match: headers: X-User-Id: # 参数名 regex: "^(?!(?:\d{1,2}|100)$)[0-9]\d+$" # 参数值 queryParams: name: exact: xiaoming uri: prefix: "/" targets: - workloads: spring-cloud-a-worksloads name: gray target: - workloads: spring-cloud-a-worksloads name: base
对应的 VirtualWorkloads 配置如下:
apiVersion: traffic.opensergo.io/v1alpha1 kind: VirtualWorkloads metadata: name: spring-cloud-a-worksloads spec: selector: app: spring-cloud-a virtualWorkload: - name: gray target: spring-cloud-a type: deployment selector: tag: gray loadbalance: random - name: base target: spring-cloud-a type: deployment selector: tag: _base loadbalance: random
金丝雀发布场景的流量路由配置
我们配置了如下的金丝雀规则,希望 10% 的流量访问spring-cloud-a中具有 gray 标签的实例
对应的 TrafficRouterRule 配置如下:
apiVersion: traffic.opensergo.io/v1alpha1 kind: TrafficRouterRule metadata: name: tag-traffic-router-rule spec: selector: app: spring-cloud-a http: - name: my-traffic-router-http-rule rule: targets: - workloads: spring-cloud-a-worksloads name: gray weight: 10 - workloads: spring-cloud-a-worksloads name: base weight: 90 target: - workloads: spring-cloud-a-worksloads name: base
流量路由 Demo 演示
- Spring Cloud Alibaba Consumer 应用中增加 OpenSergo 的依赖,并启动Spring Cloud Alibaba流量路由的Demo
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>opensergo-resource-transform</artifactId> <version>2.2.9-SNAPSHOT</version> </dependency>
配置OpenSergo流量路由
- 启动 OpenSergo 控制面
- 下发 TrafficRouterRule CRD规则
假设现在需要将灰度流量路由到v2版本,灰度请求符合如下条件 header:name=xiaoming,Params:location=shenzhen的请求流量去往灰度 v2 版本,不符合条件的流量访问v1版本。那么只需要配置如下 CRD 即可
apiVersion: fault-tolerance.opensergo.io/v1alpha1 kind: TrafficRouterRule metadata: name: http-foo-rule labels: app: foo-app spec: http: match: headers: name: 'xiaoming' queryParams: location: 'shenzhen' targets: - name: "v2" selectors: version: "v2" target: name: "v1" selectors: version: "v1"
结果验证
当我们执行 curl http://127.0.0.1:18083/router-test
NacosRegistration{nacosDiscoveryProperties=NacosDiscoveryProperties{serverAddr='127.0.0.1:8848', endpoint='', namespace='', watchDelay=30000, logName='', service='service-provider', weight=1.0, clusterName='DEFAULT', group='DEFAULT_GROUP', namingLoadCacheAtStart='false', metadata={preserved.register.source=SPRING_CLOUD, version=v1}, registerEnabled=true, ip='192.168.1.4', networkInterface='', port=18082, secure=false, accessKey='', secretKey='', heartBeatInterval=null, heartBeatTimeout=null, ipDeleteTimeout=null, failFast=true}}
其中返回默认v1版本的实例
当我们执行curl -H 'name:xiaoming' http://127.0.0.1:18083/router-test\?location\=shenzhen
NacosRegistration{nacosDiscoveryProperties=NacosDiscoveryProperties{serverAddr='127.0.0.1:8848', endpoint='', namespace='', watchDelay=30000, logName='', service='service-provider', weight=1.0, clusterName='DEFAULT', group='DEFAULT_GROUP', namingLoadCacheAtStart='false', metadata={preserved.register.source=SPRING_CLOUD, version=v2}, registerEnabled=true, ip='192.168.1.4', networkInterface='', port=18081, secure=false, accessKey='', secretKey='', heartBeatInterval=null, heartBeatTimeout=null, ipDeleteTimeout=null, failFast=true}}
其中符合流量匹配的条件,返回默认v2版本的实例。
总结与展望
流量路由是微服务流量治理中的重要的一环,当然 MSE 还提供更广范围、更多场景的微服务治理能力,包括全链路灰度、无损上下线、微服务数据库治理、日志治理等一系列的微服务治理能力。服务治理是微服务改造深入到一定阶段之后的必经之路,是将微服务做稳做好的关键。同时我们也在与 CloudWeGo、Kratos、Spring Cloud Alibaba、Dubbo、ShardingSphere 等社区共同建设 OpenSergo 微服务治理标准,将企业与社区中微服务治理的场景与最佳实践共同提取成标准规范,也欢迎更多社区与企业一起参与 OpenSergo 微服务治理标准的共建。欢迎大家加入 OpenSergo 社区交流群(钉钉群)进行讨论:34826335