01问题背景智净科技成立于2013年12月,是纺织行业领先的互联网公司,国家高新技术企业。旗下拥有“百部”、“全部”、“天工”、“智井金条”、“智井纺织智能制造园”、“智井智能仓储物流园”等业务板块,致力于利用大数据、云计算、物联网等新一代信息技术将全面打通纺织服装行业的信息流、物流和资金流,助力行业实现协同化、柔性化、智能化升级,构建数字化、智能化融合的产业链。纺织服装垂直一体化服务平台。作为集团公司成立2年多的业务团队,越来越多的项目并行开发上线。值得一提的是,我们目前正处于微服务拆分的起步阶段。目前有35个微服务,拆分后会有60个左右的微服务。在这样的背景下,大家原本都是用一套开发/测试/生产环境来串行跑研发流程。随着项目数量、开发测试需求的增加,以及微服务的拆分,原来的方式已经不适用了。我们。下面简单列举一下我们在这个过程中遇到的三个问题。1.项目测试环境被抢占最典型的问题是一个项目的测试环境经常被缺陷修复测试流程抢占,导致项目测试断断续续,测试缺乏沉浸式体验,测试流程成为项目并行化的主要原因瓶颈,验证影响项目迭代的进度。2.开发联调环境不稳定。为了保证开发体验,开发环境允许开发者自由发布。由于使用同一个环境,不同的同学发布开发环境,经常会导致联调中断。很多开发同学转向端到端的离线联调,在个人机器上部署上下游应用。微服务推广之后,这种模式基本很难往前推进,尤其是面对海量的微服务应用。如何在开发阶段解决代码调试的可移植性,成为我们遇到的第二个问题。3、缺乏在线灰度环境第三个问题也是最重要的。之前,我们缺少专门提供给产品经理进行功能验证的预发布环境。新功能测试完成后,直接上线到线上环境。研发团队为了避免对客户造成不良影响,发布计划往往安排在晚上。撇开研发团队的发布快乐不谈,线上环境灰度发布能力的缺失,意味着新功能上线后,就要发布给所有用户。一旦出现产品设计缺陷或代码漏洞,影响将是巨大的。是全网,风险巨大,不可控。综上所述,我们需要解决离线缺乏隔离的多环境来支持多个项目的开发和测试,同时在线上需要有灵活的流量路由策略来支持灰度发布需求。02计划研究探索结合我们公司的实际情况,我们的目标是开发团队不依赖运维团队,即DEV=OPS。一键拉起逻辑隔离的开发/项目环境,支持预发布环境隔离。对于生产环境,我们可以配置灰度规则流量和自然流量进行全链路灰度验证。根据我们对目前问题的分析,参考网上目前的解决方案,都指向了项目环境治理和服务流量治理的解决方案。我们简单罗列几种常用的解决方案,最终选择了阿里云微服务引擎MSE全链路灰度+云效应用交付平台APPSTACK的一体化解决方案。1.自研Ribbon实现我们使用SpringCloud框架。在平时的业务开发过程中,后端服务之间的调用往往是通过Fegin或者RestTemplate进行的。这是通过Ribbon组件来帮我们做负载均衡的功能。灰度的核心是路由。我们可以重写Ribbon默认的负载均衡算法,在负载均衡调用前加入流量路由逻辑,即可以控制业务流量的转发。如果要实施这个计划,对于大厂来说,确实可以从0进化到1,再进化到100。对于我们来说,如果只是实现一个路由功能,做一个只支持核心场景东西的简单版本,真的不是很难。但是,如果要达到成熟适用的阶段,就需要投入专门的技术资源进行管理和维护。同时,由于SpringCloud微服务框架本身的复杂性,随着微服务数量的逐渐增多,链接变得越来越长。相关微服务治理问题的定位和解决也会消耗大量的时间和成本。2、物理隔离(蓝绿发布)该方案需要为灰度服务搭建一个网络隔离、资源无关的环境,并将灰度版本的服务部署在其中。由于与基础环境隔离,基础环境中的其他服务无法访问需要灰度的服务,因此需要在灰度环境中对这些服务进行冗余部署,使整个调用链路能够正常进行流量转发。此外,注册中心等其他一些依赖的中间件组件也需要在灰度环境中冗余部署,以保证微服务之间的可见性,保证获取的节点IP地址只属于当前网络环境。该方案需要针对这些业务场景,通过堆叠机器的方式维护多套灰度环境,会造成过高的运维和机器成本,成本和成本远远超过收益;当然,如果申请的数量不多,只有两三个申请,这种方式还是很方便的,也可以接受。3.MSELabelRouting+APPSTACKApplicationOrchestration(我们的选择)这两款产品的文档见链接CloudEffectApplicationDeliveryPlatformAppStack:https://help.aliyun.com/document_detail/321856.htmlAliyunMicroserviceEngineMSE全链接灰度:https://help.aliyun.com/document_detail/170454.html我们假设读者通过以上两篇文章已经对这两款产品有了一个简单的了解,一句话介绍就是:APPSTACK是负责应用环境管理和流水线发布,MSE负责流量全链路灰度。MSE全链路灰度重要概念对比下图MSE标签路由,我们重点介绍MSE标签路由的几个重要概念,如应用标记、流量着色/自动着色、链路转移识别等。图也是我们解决方案的核心原理,用域名来标识不同的逻辑隔离环境。核心示意图(1)应用(服务)标记对比核心示意图,我们发现每个应用都有一个(基础/灰色)标签。有了这个标签,我们就可以根据标签定义流量规则。我们在创建MSE应用时,通过特定的注解和环境变量来标记MSE应用。具体注解:alicloud.service.tag=dev1环境变量:spring.cloud.nacos.discovery.metadata.version添加具体注解和环境变量。比如注解标记后,我们可以在MSE标签路由中定义流量规则,同时我们也可以看到Nacos中的服务有一个标签相关的元数据(_micro.service.env_);Nacos中的MSE流量规则配置元数据信息还有一个添加容器环境变量的方法:spring.cloud。nacos.discovery.metadata.version该方法会在Nacos服务元数据中添加一个版本属性。比如MSE云原生网关会使用这个版本属性进行流量管理,MSE全链路灰度是基于alicloud.service.tag定义的标签进行流量管理。给容器添加灰色相关的环境变量MSE流量规则配置出现灰色节点Nacos包含灰色环境元数据信息MSE云原生网关可以选择灰色版本(二)流量着色/自动着色简单来说,流量着色就是流量是brought特殊标识,对于HTTP请求,是在请求头中携带一些标识信息,对于Message,则是在消息头中携带标识信息;这里主要说一下HTTP流量着色的问题;一种是手动发送HTTP请求,在里面添加标识信息,比如前端请求后端API时,添加一个xx:111的标识信息,那么我们就说流量被染色了。自动着色是指未识别的HTTP请求。经过一个标记的nacos服务后,在调用下一个服务时,这个nacos服务的标签信息会自动包含在请求头中;finally一个简单的例子,应用a调用b(灰色)应用,那么应用b调用下面的应用c时,会自动带上x-mse-tag:gray的请求头,也就是自动着色。这里特别提到x-mse-tag:xxx,是MSE系统保留的。它不仅代表染色,还代表链接传递(请求链接上的每个节点都会依次传递这个标签。)和默认路由规则(优先选择xxx标识的服务,如果没有找到,则选择基本服务-未标记)。这个默认路由规则不需要明确定义。我们的解决方案也特别利用了这一点。对比核心示意图,我们在域名中加入流量标识,然后在Ingress-Nginx中解析流量标识,通过x-mse-tag:xxx一路传递,这样xxx标识的服务就是全链路优先选择,底线使用无标识的基础服务。(3)标识链接传输的流??量被染色,即请求头有特定标识后,这个标识如何在调用链接中传递,比如header为user-id的HTTP请求: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所需的配置工作。同时,在微服务架构下,我们希望应用被拆分之后,每个应用都有自己的主人。通过APPSTACK,我们可以屏蔽K8s的deployment、service、ingress等细节。R&D同学面向应用+环境+流水线。这样,最终开发者通过APPSTACK中的pipeline完成了应用的环境部署,每个环境都会根据MSE标签路由的要求打上不同的标签。应用的多个环境部署图每个环境都会根据MSE标签路由的要求,标注不同的标识,此时可以设置MSE标签路由所需的各种环境变量和注解。03我们的解决方案在考察了以上能力后,我们根据公司的实际场景和业务需求,以及不同环境的特点,定义了多环境的抽象,并以此为基础构建了一站式的动态多环境能力。并针对主要场景设计了不同的实现方案。1环境定义通过调研阿里云微服务引擎MSE标签路由和云效应用编排APPSTACK,结合我们上面提到的问题,我们最终定义了我们整个研发体系需要的环境体系:多套开发环境(包括基础的环境)+多套项目环境(含基础环境)+(集成)测试环境+预发布环境+(支持灰度)生产环境,如下图多套开发环境:目标是支持多个projects在开发阶段的开发联调中,核心要求是各个项目动态隔离,支持端云互联。动态项目隔离是指每个项目都有自己的开发联调环境,只需要部署变化的应用即可。端云互联是一种开发,可以将自己本地运行的应用注册到MSE系统中,达到本地调试的目的。两个研发团队可以进行本地点对点调试,跟踪问题。基础开发环境负责调用底层服务。每个应用生产部署完成后,需要同步更新基础开发环境,保证基础环境是最新的生产版本。多套项目环境:目标是支持耗时较长的大型项目,如重大技改、重大业务项目,需要长期占用测试环境,与内外部进行稳定测试关联方。核心需求是各个项目的动态隔离。项目动态隔离的定义同上。测试环境:目标是支持短、平、快的项目测试和集成测试,比如日常的缺陷修复,或者多个小项目需要一起集成发布。也是我们日常自动化测试的环境。项目环境中的特性分支也需要通过测试环境的自动化测试才能上线。预发布环境:目标是支持产品经理在真实环境中验证产品功能并进行验收检查。预发布环境中使用的基础设施,如数据库,与生产环境保持一致。当然也会对系统设计提出更高的要求,比如要保持向前兼容,就像数据库一样,只能增列不能减列,不能在sql中使用select*等。我们用DMS对数据库结构变化进行约束,通过代码检查来保证,这里不再赘述。生产环境:目标是支持常规流量+自然流量的全链路灰度。这里的常规流量是指具有明显特征的流量。MSE的流量规则可以明确定义请求,如请求头、参数、cookie等,正文中的数据符合规则。自然流量则相反。我们不指定任何特征。例如,所有流量的1%被导入灰度环境。我们将此理解为自然流量。整体来看,在目前的环境体系中,开发环境和项目环境存在动态隔离,需要部署基础环境来完成服务能力。这个基础环境也是MSE标签路由中无标签(基础)应用的提供者。.这套环境体系的流程主要包括:1.将feature分支拉入开发环境进行本地开发和前后端联调,然后测试到项目环境2.项目结束后环境经过测试组测试,应用将被部署到(集成)测试环境3.在(集成)测试环境中完成与其他特性分支的集成,通过自动化测试和简单验证,即可部署到预发布环境4.产品经理在预发布环境进行功能验收测试,通过后可以发布到生产环境进行灰度验证。5.在生产环境中,可以按照常规流量+自然流量进行灰度验证。通过后,即可导入所有流量。6.最后将feature分支合并到主干中,使用最新的生产版本更新开发/项目基础环境。2.主要场景实现场景一:项目隔离的动态多环境根据我们的方案,项目环境需要实现逻辑隔离的动态多环境,相当于通过APPSTACK为每个应用部署基础环境(负责bottom-upnoTagbaseapplication)和动态项目环境(withchanges)同时需要保证前端调用后端的域名可以转换为x-的请求头mse标签。1、通过APPSTACK部署有标签的应用(项目环境)和无标签的应用(基础环境)。以下屏幕截图仅用于演示。2、在ingress-nginx中解析域名中的tag属性,转换为x-mse-tag请求,通过header链接,通过ingress配置携带header到api网关。通过注解nginx.ingress.kubernetes.io/configuration-snippet实现,如下:metadata:annotations:nginx.ingress.kubernetes.io/configuration-snippet:proxy_set_headerx-mse-tagdev1经过这么简单的配置后,前端调用在客户端服务时,只要请求特定的域名,ingres-nginx会自动在该域名对应的请求中添加一个x-mse-tag请求,传递给api网关application,然后使用特殊的x-mse-tag作为请求头,在调用下游服务时,会一路优先选择有dev1标签的服务,没有dev1标签的服务会自下而上的进行base服务。场景二:流量正常的全链路灰度生产环境1.通过APPSTACK在生产环境中部署带有灰度标识的应用。2.定义流量路由规则,在MSE控制台为该灰度链路的ingress应用设置流量路由规则。例如本次发布更新了A-B-C三个应用,A为入口应用。这样定义之后,我们就可以设置满足某些特征的流量进入应用A的灰色版本,逐层传递,而不需要为每个应用重复路由规则。这将满足常规流量的全链路灰度要求。场景三:自然流量全链路灰度的生产环境1.通过APPSTACK、sketch在生产环境中部署带有灰度标识的应用。这里至少需要给本项目的入口应用A(或所有应用)添加一个自动着色变量profiler.micro.service.tag.trace.enable=true。这个变量会自动跟踪经过这个入口应用的流量A.着色,后面经过的时候自动加上x-mse-tag请求头,实现全链路灰度2.定义流量规则,即比例进入灰色环境的自然流量,让入口应用自动着色,通过对入口应用的自然流量进行批处理,可以让进入入口应用灰色节点的自然流量进入应用的灰色环境。全链路(灰度优先,基础应用覆盖)。至此,我们默认实现了根据域名动态隔离项目/开发多环境逻辑的效果;同时,我们为研发团队提供了方便的白屏管理工具,可以由项目组独立拉起整个环境,通过三个基于场景的实施方案,完美解决了开头提到的三个问题。3.相关技术原理概述介绍MSE+APPSTACK的解决方案。核心在于交通规则的定义和交通标识的传递。图:如何实现解析Extract和注入Inject的核心功能?答案是探头。为每个MSE管理的应用运行时添加一个java代理探针,完成一个类JVMAOP的能力。在ACK(K8s)容器中,MSE通过以下方式自动为应用安装java代理;1。配置Webhook,然后根据Pod中的Labels或者Namespac判断是否挂载JavaAgent。如果需要挂载,则对Pod声明文件进行后续修改2.获取并添加环境变量JAVA_TOOL_OPTIONS,用于加载JavaAgent。3.在业务容器中添加一个Volume,用于存放JavaAgent的文件内容。4.在Pod中添加一个Init容器,用于在业务容器启动前下载JavaAgent。最后,我们每个MSE管理的应用程序在POD层面可以看到如下信息:通过这个探针,我们可以拦截所有的HTTPREQUEST处理类,暂存我们关心的标识信息,然后添加MSE支持的路由逻辑在应用内部消费Nacos服务时,选择合适的服务提供者(例如灰色标注),同时调用该提供者的服务,此时可以在请求头中携带暂存的流量标识,继续传下去,大致类似于我们开头提到的自研Ribbon方法。但是,MSE在这方面相对成熟。同时不仅支持HTTPREST的服务调用方式,还包括Dubbo、RocketMQ消息灰度、数据库灰度等,当然全链路灰度只是微服务引擎MSE的一个小功能。微服务引擎MSE(MicroservicesEngine)是面向业界主流开源微服务生态的一站式微服务平台。提供注册配置中心(原生支持Nacos/ZooKeeper/Eureka)、云原生网关(原生支持Ingress/Envoy)、微服务治理(原生支持SpringCloud/Dubbo/Sentinel,遵循OpenSergo服务治理规范),感兴趣同学们可以看看官方文档。04借力育人作为一个创业团队,能够快速一站式解决服务治理问题是一件很酷的事情。在整个方案的讨论和实施过程中,研发团队对K8s、NginxIngress、MSE有了深刻的理解。“像我们部门的研发团队,没有专门的运维团队,每个开发人员都能深入了解每个产品的来龙去脉,想想也有道理。”
