作者: 李思源、武良军
问题布景
致景科技成立于 2013 年 12 月,是抢先的纺织产业互联网企业,国家高新技能企业。旗下拥有“百布”、“全布”、“天工”、“致景金条”、“致景纺织智造园”、“致景智慧仓物流园”等事务板块,致力于经过大数据、云核算、物联网等新一代信息技能,全面打通纺织服装职业的信息流、物流和资金流,协助职业完结协同化、柔性化、智能化的晋级,构建纺织服装纵向一体化的数智化归纳服务渠道。
咱们作为集团公司现已成立 2 年多的一个事务团队,项目并行开发上线的状况越来越多。值得一提的是,咱们现在处于微服务化拆分刚开端的阶段,现在 35 个微服务,拆完之后大概会去到 60 个左右。在这样的布景下,原先大家都运用一套开发/测验/出产环境串行跑研制流程,随着项目数量、开发测验需求的变多,微服务拆分的进行,原先的办法现已不太适宜咱们。下面简略罗列一下,咱们在这过程中所遇到的三个问题。
项目测验环境被抢占
最典型的问题便是一个项目测验环境经常性被缺点修正的测验流程抢占,导致项目测验时断时续,对测验而言缺少沉浸式体会,一起测验环节成为项目并行度的首要瓶颈,验证影响项目迭代的进展。
开发联调环境不安稳
为了保证开发的体会,开发环境是允许开发同学自由发布。因为运用一套环境,不同的同学进行开发环境发布,经常性地导致联调中止。不少开发同学转而寻求端到端的线下联调,在个人机器上布置上下游运用,这种形式在微服务化推广之后,特别是面对众多的微服务运用基本上寸步难行。怎么处理开发阶段代码调试的便携性,成为了咱们遇到的第二个问题。
线上灰度环境的缺少
第三个问题也是最重要的,之前咱们缺少专门提供给产品司理进行功用验证的预发环境。新功用完结测验之后直接上线到线上环境,研制团队为了防止防止对客户发生不良影响,经常性地将发布计划安排在晚上。抛开研制团队的发布美好度不谈,线上环境缺少灰度发布才能意味着新功用上线今后就会对全量用户放开,一旦发生了产品规划缺点或许代码漏洞的状况,那么影响面将会是全网的,危险巨大且不可控。
综上所述,咱们需求处理线下缺少阻隔的多套环境来支撑多项意图开发和测验,一起在线上需求具有灵敏的流量路由策略支撑灰度发布需求。
计划调研与探索
结合咱们公司实际状况,咱们的方针是开发团队不依赖运维团队,即 DEV = OPS 。咱们能够一键拉起逻辑阻隔的开发/项目环境,一起能够支撑预发环境阻隔,关于出产环境能够经过装备灰度规矩流量、天然流量来进行全链路灰度的验证。
依据咱们对当时问题的分析,参考现在互联网上的处理计划,都指向了项目环境管理和服务流量管理的计划,咱们略微罗列下常用的几种计划,咱们终究挑选的是阿里云微服务引擎 MSE 全链路灰度 + 云效运用交给渠道 APPSTACK 的集成计划。
自研 Ribbon 完结
咱们运用的是 Spring Cloud 结构,在平常的事务开发过程中,后端服务与服务之间的调用往往经过 Fegin 或许 RestTemplate 两种调用办法。这其间是经过 Ribbon 这个组件帮咱们做了负载均衡的功用。灰度的中心便是路由,咱们能够经过重写 Ribbon 默许的负载均衡算法,在负载均衡调用之前,添加流量路由的逻辑,那么就意味着咱们能够控制服务流量的转发。
这个计划要施行下去,关于大厂来说的确能够从 0 到 1 再到 100 进化出来,对咱们来说,假如仅仅是完结一个路由的功用,做一个只支撑中心场景的简陋版的确不是十分困难的工作。但假如要到达老练可运用的阶段,需求投入专门的技能资源对其进行办理与保护,一起因为 Spring Cloud 微服务结构本身的复杂性,随着微服务数量逐步增多,链路越来越长,相关的微服务管理问题的定位与处理,也会耗费不菲的时间本钱。
物理阻隔(蓝绿发布)
这种计划需求为要灰度的服务建立一套网络阻隔、资源独立的环境,在其间布置服务的灰度版别。因为与根底环境阻隔,根底环境中的其他服务无法访问到需求灰度的服务,所以需求在灰度环境中冗余布置这些服务,以便整个调用链路正常进行流量转发。此外,注册中心等一些其他依赖的中间件组件也需求冗余布置在灰度环境中,保证微服务之间的可⻅性问题,保证获取的节点 IP 地址只归于当时的网络环境。这个计划需求为这些事务场景采用堆机器的办法来保护多套灰度环境,会造成运维、机器本钱过大,本钱和代价远超收益;当然假如运用数目很小,就两三个运用,这个办法仍是很便利的,能够接受的。
MSE 标签路由+APPSTACK 运用编列(咱们的挑选)
这两款产品的阐明文档见链接:
云效运用交给渠道 AppStack :
help.aliyun.com/document_de…
阿里云微服务引擎 MSE 全链路灰度 :
help.aliyun.com/document_de…
咱们假定经过上面的两篇文章,读者现已对这两个产品现已有了简略的了解,一句话介绍便是:APPSTACK 负责运用的环境办理和流水线发布,MSE 负责流量的全链路灰度。
- MSE 全链路灰度的重要概念
对照下面的 MSE 标签路由的图,咱们重点介绍下 MSE 标签路由的几个重要概念如运用的打标、流量染色/主动染色、标识链路传递等,一起下图也是咱们采用计划的中心原理,运用域名来标识不同的逻辑阻隔环境。
中心示意图
1. 运用(服务)打标
对照中心示意图,咱们发现每个运用都有个(base/gray)的 tag,有了这个 tag,咱们才能够依据 tag 界说流量规矩。
咱们创立 MSE 运用的时分是经过特定 annotation 和环境变量给 MSE 运用打标的。
特定 annotation:
alicloud.service.tag=dev1
环境变量:
spring.cloud.nacos.discovery.metadata.version
添加特定的 annotation 跟环境变量
比方经过 annotation 打标之后咱们就能够在 MSE 的标签路由中进行流量规矩界说,一起咱们也能够看到 Nacos 里边的服务有了一个标签相关的元数据(micro.service.env);
MSE 流量规矩装备
Nacos 里边元数据信息
也有额外添加一个容器环境变量的做法:
spring.cloud.nacos.discovery.metadata.version
这种做法会在 Nacos 的服务元数据中添加一个 version 特点,像 MSE 云原生网关就会凭借这个 version 特点进行流量办理,而 MSE 全链路灰度是凭借 alicloud.service.tag 界说的标签进行流量办理。
容器中添加 gray 相关的环境变量
MSE 流量规矩装备呈现 gray 节点
Nacos 里边有gray环境的元数据信息
MSE 云原生网关能够挑选 gray 版别
2. 流量染色/主动染色
简略讲,流量染色便是流量带上了特别的标识,关于 HTTP 恳求来说,是恳求头里带了一些标识信息,关于 Message 来说,是消息头里带了标识信息;咱们这儿首要讲下 HTTP 流量染色问题;一种是人工的往 HTTP 恳求里边添加标识信息,比方前端恳求后端 API 的时分,添加一个 xx:111 的标识信息,那咱们就说这个流量被染色了。而主动染色,则说的是一个没有标识的 HTTP 恳求,经由某个打了标的 nacos 服务之后,往后调用下一个服务的时分,主动会带上这个 nacos 服务的标签信息在恳求头里;最简略的举例便是 a 运用调用 b(gray)运用,那b运用调用后面的 c 运用的时分,会主动带上 x-mse-tag:gray 的恳求头,这便是主动染色。
这儿特别说到 x-mse-tag:xxx 这个标识,他是 MSE 系统保存的标识,不仅仅代表了染色,一起也代表了链路传递(这个恳求链路上的各个节点都会依次传递这个标签下去)和默许的路由规矩(优先挑选 xxx 标识的服务,没有找到的状况下,再挑选 base 服务-没有打标的),这个默许路由规矩是不需求显式界说的。
咱们的处理计划也是特别地利用了这一点,对照中心示意图,咱们在域名姓名中添加了流量标识,然后在 Ingress-Nginx 中将流量标识解析出来然后经过 x-mse-tag:xxx 的办法一路传递下去,这样就完结了在整个链路上优先挑选 xxx 标识的服务,运用没有标识的 base 服务进行兜底。
3. 标识链路传递
流量被染色,也便是恳求头中有特定标识之后,这个标识在调用链路中怎么能够传递下去,比方一个 HTTP 恳求,带了 user-id:100 的头,陆续需求经过 A->B->C。即调用 A 的时分带了 user-id:100,A 调用 B 的时分也期望能够带上 user-id:100 的恳求头,同样 B 调用 C 的时分也要带上 user-id:100。这个便是标识的链路传递,有了这个标识链路传递,咱们才能够在为 A/B/C 运用界说按 user-id 的值进行路由的策略。MSE 的标识链路传递的办法是界说环境变量 alicloud.service.header=x-user-id,在进口运用 A(一切版别,gray+base)添加该环境变量今后,往后的调用 B 和 C 的过程中,都会主动添加恳求头 x-user-id 进行传递,这样就便利咱们在 A,B,C 节点依照特有规矩进行路由界说。当然 x-mse-tag 这个特别的恳求头默许便是链路传递的,MSE 会把这个标识层层传递下去并进行默许的路由规矩(tag 优先,base 兜底);MSE 标识链路传递的原理如下,凭借分布式链路追踪的结构的完结办法,每个运用的探针阻拦恳求并解析标识,然后暂存到线程空间,在往后调用的时分再经过探针把标识塞到下个恳求。经过分布式链路追踪的结构完结标识传递。
- 阿里云效运用交给 APPSTACK 简述
咱们把云效 APPSTACK 引进进来,首要意图是便利开发同学经过白屏的办理办法自助完结 MSE 所需求的装备工作,一起在微服务架构下,咱们期望运用进行拆分之后,每个运用都有自己的 owner。
经过 APPSTACK 咱们能够屏蔽 K8s 的 deployment,service,ingress 等细节,研制同学面向的便是运用+环境+流水线。这样终究开发人员在 APPSTACK 经过流水线完结运用的环境布置,每个环境都会依照 MSE 标签路由的要求打上不同的标识。
运用的多套环境布置
每个环境都会依照 MSE 标签路由的要求打上不同的标识
在这儿咱们不打开叙述 APPSTACK 的中心功用,咱们这儿首要的便是凭借运用编列,让每个运用的每个环境布置的时分,能够设置好 MSE 标签路由所需求的各种环境变量和 annotation。
咱们的处理计划
咱们在调研了以上才能之后,依据自己公司的实际场景与事务需求,依据不同环境的特性,界说了多种环境的抽象,基于此构建了一站式动态多环境的才能,并针对首要场景规划了不同的施行计划。
环境界说
经过对阿里云微服务引擎 MSE 标签路由和云效运用编列 APPSTACK 的调研,结合咱们前面说到所面对的问题,咱们终究界说了咱们整个研制系统所需求的环境系统即:多套的开发环境(含根底环境)+多套项目环境(含根底环境)+(集成)测验环境+预发环境+(支撑灰度)出产环境,如下图
多套开发环境:方针是支撑多个项意图在开发阶段的开发联调,中心要求是各项目动态阻隔而且支撑端云互联,项目动态阻隔是每个项目都有自己的开发联调环境且只需布置有变动运用,端云互联是开发能够将自己本地跑的运用注册到这个 MSE 这个系统里边来,完结能够本地调试的意图,两个研制能够点对点地进行本地 debug 来跟踪问题。开发根底环境是负责兜底服务调用的,每个运用出产布置之后都需求同步更新开发根底环境,保证根底环境是最新的出产版别。
多套项目环境:方针是支撑耗时较长的大型项目,比方严重技改,严重事务项目,需求长期占用测验环境跟内外部关联方进行安稳测验的。中心要求是各个项目动态阻隔。关于项目动态阻隔的界说同上。
测验环境:方针是支撑短平快的项目测验和集成测验,比方日常的缺点修正,或许多个小项目需求集成到一起发布,一起也是咱们日常主动化测验的环境。项目环境中的特性分支也需求经过测验环境的主动化测验才能够上线。
预发环境:方针是支撑产品司理在真实环境中验证产品功用,进行检验,预发环境运用的根底建设如数据库等同出产环境是一致的,当然这儿对系统规划也会提出更高的要求,比方需求坚持向前兼容,就像数据库,只能增列不能减列,不能在 sql 中运用 select * 等等,这些咱们经过 DMS 进行数据库结构改变的约束和经过代码检查保证,此处不赘述。
出产环境:方针是支撑规矩流量+天然流量的全链路灰度,这儿的规矩流量指的是带有明显特征的流量,经过 MSE 的流量规矩能够清晰界说的恳求,比方恳求头,参数,cookie,body 中数据契合规矩的。天然流量则相反,咱们不指定任何特征,比方悉数流量的 1%导入到灰度环境,这个咱们就了解成天然流量。
归纳来看,现在的环境系统里,开发环境和项目环境涉及到动态阻隔,所以需求布置根底环境来完结服务兜底的才能,这个根底环境也便是 MSE 标签路由中无标签(base)运用的提供者。
这一套环境系统的流转流程首要有:
-
拉取特性分支进入开发环境进行本地开发和前后端联调,然后提测到项目环境
-
项目环境由测验团队完结功用测验之后,将运用布置到(集成)测验环境
-
在(集成)测验环境同其他特性分支一起完结集成,并经过主动化测验和简略验证,就能够布置至预发环境
-
产品司理在预发环境进行功用检验测验,经过之后能够发布到出产环境进行灰度验证
-
在出产环境能够依照规矩流量+天然流量进行灰度验证,经过之后就能够导入悉数流量
-
终究将特性分支兼并至骨干后用最新的出产版别更新开发/项目根底环境。
首要场景施行
- 场景一:项目阻隔的动态多环境
依照咱们的处理计划,项目环境要完结的是逻辑阻隔的动态多环境,相当于每个运用咱们要经过 APPSTACK 布置根底环境(负责兜底的无标签 base 运用)和动态项目环境(有改变的)一起咱们需求保证前端调用后端的域名能够转换成 x-mse-tag 的恳求头。
- 经过 APPSTACK 布置好有标签的运用(项目环境)和没标签的运用(根底环境),下列截图仅做示范
- 在 ingress-nginx 中解析域名中的 tag 特点转换成 x-mse-tag 恳求头链路传递,经过 ingress 装备携带 header 办法到 api 网关。
经过注解
nginx.ingress.kubernetes.io/configuration-snippet 完结,详细如下:
metadata:
annotations:
nginx.ingress.kubernetes.io/configuration-snippet:
proxy_set_header x-mse-tag dev1
经过这样简略装备之后,前端调用后端服务的时分,只需经过特定的域名恳求,那 ingres-nginx 就能够把这个域名对应的恳求主动添加一个 x-mse-tag 的恳求传递到 api 网关运用,然后凭借这个 x-mse-tag 的特别恳求头,在调用下游服务的时分,就会一路优先挑选 dev1 标签的服务,没有 dev1 标签的服务就会去找兜底的 base 服务。
- 场景二:规矩流量全链路灰度的出产环境
-
经过 APPSTACK 在出产环境布置好有灰度标识的运用。
-
界说流量路由规矩,在 MSE 控制台为本次灰度链路中的进口运用设置流量路由规矩,比方本次发布更新了 A-B-C 三个运用,A 便是进口运用。
经过这种办法界说之后,咱们能够设置契合某些特征的流量进入到 A 运用的 gray 版别,而且向后层层传递过去,不用每个运用重复设置路由规矩。这就会满足了规矩流量的全链路灰度的要求。
- 场景三:天然流量全链路灰度的出产环境
-
经过APPSTACK在出产环境布置好有灰度标识的运用,略图。这儿至少需求为本次项意图进口运用 A(也能够是悉数运用)添加一个主动染色的变量 profiler.micro.service.tag.trace.enable=true,这个变量会把经过这个进口运用 A 的流量主动染色,往后传递的时分主动添加 x-mse-tag 的恳求头,然后完结全链路灰度
-
界说流量规矩,即天然流量的多少份额进入 gray 环境
这样经过进口运用的主动染色,以及进口运用的天然流量分批,咱们就能够让进入到进口运用 gray 节点的天然流量进入到全链路的灰度环境(灰度优先,根底运用兜底)。
现在为止,咱们完结了默许依照域名进行项目/开发多环境逻辑动态阻隔的作用;一起提供给研制团队便捷的白屏办理的东西,能够由项目组独立拉起整个环境,经过三个场景化的施行计划,完美处理了开篇说到的三个问题。
相关技能原理概要介绍
MSE + APPSTACK 的处理计划,中心的地方在于流量规矩的界说以及流量标识的传递,其中心的处理计划在于流量中标识的解析和传递,咱们再看一次这个标识传递的图:
怎么样才能完结这儿面最中心的解析 Extract 和注入 Inject 的功用呢?
答案是探针,为每个 MSE 办理的运用运转时分添加一个 java agent 的探针,完结一个类似 JVM AOP 的才能,在 ACK(K8s)的容器中,MSE 经过如下的办法主动为运用安装 java agent;
-
装备 Webhook,然后依据 Pod 或许 Namespac中的 Labels,来判别是否要挂载 Java Agent。假如需求挂载,则就对 Pod 的声明⽂件做出后续修正
-
获取并添加环境变量 JAVA_TOOL_OPTIONS,⽤于加载 Java Agent。
-
给事务容器添加 Volume,⽤于存储 Java Agent 的⽂件内容。
-
给 Pod 添加 Init container,⽤于在事务容器发动前下载 Java Agent
终究咱们每个被 MSE 办理的运用在 POD 层面能够看到如下信息:
有了这个探针,咱们能够阻拦一切 HTTP REQUEST 的处理类,将咱们关心的标识信息暂存起来,然后在运用内部消费 Nacos 服务的时分添加 MSE 支撑的路由逻辑,挑选适宜的服务 provider(比方是打了 gray 标的),一起在调用这个 provider 的服务的时分,能够将暂存的流量标识带在恳求头里继续传递下去,大体上跟咱们最开端说到的自研 Ribbon 的办法类似。不过 MSE 在这块做得比较老练,一起不单单支撑了 HTTP REST 这种服务调用办法,还包括了 Dubbo、RocketMQ 的消息灰度、数据库灰度等。当然全链路灰度仅仅是微服务引擎 MSE 一个很小的功用,微服务引擎 MSE(Microservices Engine)是一个面向业界干流开源微服务生态的一站式微服务渠道,提供注册装备中心(原生支撑 Nacos/ZooKeeper/Eureka)、云原生网关(原生支撑 Ingress/Envoy)、微服务管理(原生 支撑Spring Cloud/Dubbo/Sentinel,遵从 OpenSergo 服务管理标准)的才能,有兴趣的同学能够看看官方文档。
借事修人
作为创业团队来讲,能够快速具有一站式处理服务管理问题,是一件十分酷的事。这整个计划的讨论施行过程中,研制团队关于 K8s、Nginx Ingress、MSE 都有较深化的了解。“像咱们部门研制团队,没有专门的运维团队,每个开发人员都能够深化了解每个产品的来龙去脉,想想就很有意义。”