关于微服务:连流量染色都没有你说要搞微服务

52次阅读

共计 3556 个字符,预计需要花费 9 分钟才能阅读完成。

一、序言

在当下流行的微服务架构下,服务数量多导致的依赖问题常常会成为开发过程中的绊脚石。也常常会在各种技术交流会上听到相似的话题,大家都在踊跃的探讨这种问题如何去解决。于是决定给大家介绍下流量染色的原理以及能解决微服务架构下开发过程中的哪些问题。

二、流量染色的概念

流量染色说白了就是为对申请的流量打上标签进行染色,而后这个申请在整个链路中都会携带这个标签信息,能够通过标签进行流量的调度等性能。

基于流量染色能够实现很多性能,比方灰度逻辑,蓝绿部署,泳道隔离等。

这里简略讲下流量染色跟微服务的关系,省得大家感觉这是一篇题目党的文章。试想一下,如果是一个单体利用,还能有流量染色的利用场景吗?申请的大抵流程就是 App -> 负载平衡 -> 利用,整个链路就很简略,流量染色在这个场景下齐全无用武之地。只有在服务数量泛滥的状况下,一个业务性能波及到 N 个服务,才须要对流量进行染色管制来解决咱们开发,测试等过程中遇到的问题。

三、基于流量染色的利用

测试环境多套部署的痛点,只需增量部署

目前,咱们的测试环境除了常常用的 T 环境,还有很多 MF 环境。而 MF 环境基本上是在独立的需要中会用到,失常的版本迭代都是走 T 环境。

  • 问题一:各环境配置不同

这样就会导致一个问题,很多性能是在 T 环境进行测试的,当有独立需要须要在 MF 环境中测试时,就须要部署对应的服务,部署过程中常常会碰到各种配置的缺失或者谬误的状况,导致利用无奈启动。

  • 问题二:没有改变的服务也要部署

有一个需要须要在 MF 环境测试,服务也部署好了,联调的时候却发现依赖的上游服务都没有部署。但这些服务在这个需要是没有改变的,依赖的接口也是曾经上线了的性能。

如果没有在对应的环境部署,整个链路就无奈调通。所以这个时候又要去找对应的上游,让上游去部署这些服务,上游部署的时候可能也会呈现各环境配置不同的问题,导致整个联调后期的耗时较长,影响我的项目进度。

  • 流量染色如何解决上述问题?

比如说以后在开发一个需要,而后会在要改变的利用中配置一个版本,这个版本信息会存储在注册核心的元数据外面。

而后就去创立一个属于这个需要的泳道(独立环境)进行部署,只须要部署这个需要改变的利用即可。这个利用依赖的上游利用不须要部署,在以后环境找不到对应的服务提供者就来路由到稳固环境,如果稳固环境中也没有就报错。

研发本地启动随便注册问题

研发有的时候会在本地启动服务,次要是用来调试某个问题,益处就是可能疾速复现测试环境的问题,及时发现问题代码。

因为本地启动的服务也会注册到注册核心外面,这样测试环境的申请就有可能会路由到研发本地启动的这个服务上,研发本地的这个服务代码有可能不是最新的,导致调用异样。

这个问题目前罕用的解决方案是通过在本地启动时屏蔽掉服务的注册性能,也就是不注册下来,这样就不会被失常的测试申请路由到。

如果有了流量染色的性能,研发本地启动服务的时候指定一个属于本人的版本号,只有不跟失常测试的版本统一即可。失常测试的申请就不会路由到研发注册的这个实例上。

利用级别的灰度

针对接口级别的灰度,目前都是在利用内进行灰度管制。然而利用级别的,目前没有特地好的形式来管制灰度。比方有一个技改需要,须要将 Redis 的 Client 从 Lettuce 换成 Jedis,这种场景的灰度就是利用级别的,目前的做法就是公布一个节点,而后完结公布流程,具体能被灰度到的量是由服务实例的总数量来决定的,没方法灵便管制。

如果有流量染色,能够新发一个节点,这个节点的版本升级一下,比方之前的版本是 V1,那么新发的就是 V2 版本。首先 V1 版本必定是承载生产所有流量的,能够通过网关进行管制让流量按某种形式转发到 V2 版本,比方用户白名单,地区,用户比例等等。有问题也能够随时将流量切回 V1,十分不便。

服务的优雅下线

服务要想无损进行优雅下线,还是须要做很多工作的,比方目前公布时会先将要公布的服务从注册核心登记掉,然而利用外部还是会有服务实例信息的缓存,须要等到肯定的工夫缓存实现革除后,对应的指标实例才不会被申请到。

如果基于染色去实现的话,将须要下线的实例信息(IP:PORT)通过配置核心推送给网关进行染色解决,染色信息跟随着申请贯通整个链路,利用内的负载平衡组件,MQ 等中间件会对要下线的指标实例信息进行过滤,这样就不会有流量到要下线的实例下来。

生产环境公布提速

目前,支流的公布都是滚动部署,滚动公布的益处是成本低,不必额定减少部署的资源,一个萝卜一个坑,缓缓替换就是。不好的点在于公布工夫长,全链路依赖太重大,如果公布之前依赖关系错乱了,那就是一个线上故障。

要解决这个公布速度的问题,能够基于流量染色来实现蓝绿部署。也就是在公布的时候重新部署一个 V2 的版本,这个 V2 版本的实例数量跟 V1 保持一致,因为这个 V2 版本是没有流量的,所以不存在依赖关系,大家能够同时公布,等到全副发完之后,就能够通过网关进行流量散发了,先散发一点点流量到 V2 版本进行验证,如果没有问题就能够缓缓放大流量,而后将 V1 版本的容器开释掉。

公布速度的确晋升了,可是问题在于蓝绿部署的老本太高了,资源老本要翻倍,尽管公布后老的资源就回收了,然而你总的资源池还是得包容下这 2 个版本并行才行。

那有没有折中的形式,既能进步公布效率又能不减少资源老本呢?

能够在公布的时候采纳替换的模式,先公布一半的实例,这一半的实例就是咱们的 V2 版本,公布时是没有流量的,所以还是能够并行的去公布。

公布实现后,开始放量到 V2 版本,而后验证。验证之后就能够公布另一半的实例了,这样的形式总的资源是没有变动的,然而有一个比较严重的问题就是间接停掉了一半的实例,剩下的实例能不能撑持以后的流量,因为交易内的利用都是面向 C 端用户的,流量很有可能在短时间内达到很高的量。

全链路压测

全链路压测对于电商业务来说必不可少,每年有 N 次大促,都须要提前进行压测来确保大促的稳固。其中全链路压测最外围的一点就是流量的辨别,须要辨别流量是失常的用户申请还是压测平台的压测流量。

只有辨别了流量,能力将压测流量进行对应的路由,比方数据库,Redis 等流量须要路由到影子库中。基于流量染色就很容易给流量打标,从而辨别流量的类型。

四、流量染色的实现

利用要有版本的概念

每个利用都须要有版本的概念,其实就跟每次迭代绑定即可。只不过是要将这个版本信息放入我的项目中的配置文件外面,我的项目启动的时候会将这个版本信息跟本身的实例信息一起注册到注册核心外面,这些信息个别称之为元数据(Metadata)。

有了 Metadata,在管制流量路由的时候才能够依据染色的信息进行对应的匹配,比方某个申请指定了对订单的调用要走 V2 版本,那么在路由的时候怎么匹配出 V2 版本的实例信息呢?就须要依赖 Metadata。

染色信息全链路透传

染色信息全链路透传这个很要害,如果不能全链路透传就没方法在所有节点进行流量的路由管制。这个染色信息的透传其实跟分布式链路跟踪是一样的原理。

目前支流反对分布式链路跟踪的有 Skywalking,Jaeger 等等,基本上都借鉴了 Google Dapper 的思维。每次申请都会在入口处生成一个惟一的 TraceId,通过这个 TraceId 就能够将整个链路关联起来,这个 TraceId 就须要在整个链路中进行传递,流量染色的信息也是一样须要全链路传递。

传递的伎俩个别分为两种,一种是在独立的 Agent 包中进行传递,一种是在根底框架中进行埋点传递。如果内网之间采纳 Http 进行接口的调用,那么就在申请头中将信息进行传递。如果是用 RPC 的形式,则能够用 RpcContext 进行传递。

信息传递到了利用中,在这个利用中还会持续调用其余上游的接口,这个时候要持续透传,个别都是将信息放入到 ThreadLocal 中,而后在发动接口调用的时候持续透传。这里须要留神的就是用 ThreadLocal 要防止出现线程池切换的场景,否则 ThreadLocal 中的信息会失落。当然也有一些伎俩来解决 ThreadLocal 异步场景下的信息传递问题,比方应用 transmittable-thread-local。

流量路由管制

当流量有了标签信息,剩下的工作就是要依据标签信息将申请路由到正确的实例上。如果外部框架是 Spring Cloud 体系,能够通过 Ribbon 去管制路由。如果是 Dubbo 体系,能够通过继承 Dubbo 的 AbstractRouter 重新制定路由逻辑。如果是外部自研的 RPC 框架,必定留有对应的扩大去管制路由。

五、总结

流量染色总体来说还是十分有用的,但这也是一个大的技术改造。除了在根底框架层面要买通染色信息的传递,更为重要的是各业务方的配合,当然如果是 Agent 形式的接入就更好了,不然每个业务方还要去升级包,的确有点烦。

* 文 / 尹吉欢
@得物技术公众号

正文完
 0