乐趣区

关于云原生:兑现-Service-Mesh-的新价值精确控制爆炸半径

作者:至简

软件是以继续迭代的形式去一直演进的。某种程度上,咱们并不放心软件不欠缺,但放心软件的迭代速度太慢而影响了欠缺的速度。在分布式软件畛域,如何疾速、平安地验证新的软件版本始终是大家所关怀并摸索的。服务网格(Service Mesh)的呈现将这个畛域的摸索推向了新的高度。“泳道”这一概念在分布式软件畛域并非新词,只不过,这次咱们是以服务网格为根底技术去构建,充分发挥云原生技术人造具备灵便治理流量的劣势。
本文分享了阿里云外部所积淀的全链路流量打标与路由的能力,做出服务网格技术新体验的同时,很好地兑现了服务网格的新价值。

概念与场景

图 1 以 Istio 官网所提供的 Bookinfo 示例程序为例示例阐明了应用场景中的要害概念。其中紫色的圆边方框代表了 Envoy。图中所有泳道的性质是一样的,不同的命名只是为了辨别细分场景或用户。

• 基线(baseline):指业务所有服务都部署到了这一环境中。基线能够来自实在的生产环境,也能够专为开发工作而构建的与生产环境齐全独立的环境。

• 流量泳道(traffic lane):代表了一个与基线环境相隔离的软环境,通过给机器(即 Kubernetes 中的 Pod)打标签的办法,将机器退出到该泳道中。显然,退出泳道的机器在网络层面与基线中的机器是互通的。

• 流量回退(traffic fallback):泳道中所部署的服务数量并非要求与基线环境完全一致,当泳道中并不存在调用链中所依赖的其余服务时,流量须要回退至基线环境,进一步在必要的时候返流泳道。比方,图 1 中 dev1 泳道中并不存在 productpage 服务所依赖的 reviews 服务,因而须要让流量回退到基线中的 reviews 服务(图中深蓝色线所示),紧接着基线中的 reviews 服务须要将流量打回 dev1 泳道中的 ratings 服务。

• 流量标识透传(traffic label passthrough):所有服务边上的 Sidecar 都须要有能力将调入申请中所携带的流量标签主动放到由这一申请所分叉出的每一个调出申请中去,以便实现全链路流量标识透传和按流量标识路由,否则泳道与基线间的流量无奈来回穿梭。
• 入口服务(entrance service):指流量进入泳道时所触达的第一个服务。图 1 中代表服务的图形在左边框边上打上三角形标识的就代表它是一个入口服务。

图 1

泳道技术能够使用于如下场景:

• 单个服务的日常开发或多个服务间的日常开发联调。开发者建设泳道,将减少了新性能的服务部署到泳道中,基于流量的特色通过定义规定将测试流量引入泳道中进行验证。因为泳道只需部署被测试服务的新版本,省去了搭建全链路测试环境的麻烦。在这一场景中,须要留神测试流量所存在的数据落盘问题,解决好开发与联调过程中所留下的脏数据。

• 全链路灰度。对于波及重大性能上线中的多个服务,能够通过泳道以全链路灰度的形式做更为全面的性能验证。全链路性能验收通过后,再将服务的新版本公布至基线。

• 要害业务重保。相似批发场景的业务(比方 POS 机收银),咱们不心愿因为软件的故障而引发微小的舆情,这时能够通过泳道对业务流量进行隔离实现重保。

技术实现

### 流量打标计划与实现

在使用泳道技术时,依据流量打标的地位不同而存在三种不同的计划。值得指出,尽管计划有所不同,但就服务网格而言的技术实现是完全一致的,将计划列举进去是为了帮忙读者更好地了解。

图 2 示例阐明了计划一。在这个计划中,流量进入服务网格的 Ingress 网关之前还有一级网关,咱们权且称之为 API 网关(比方,Nginx)。通常 API 网关能够依据流量的特色,在转发收到的申请前先加上额定的头,从而实现对流量的打标动作。图中对于特定的流量将减少名为 x-asm-traffic-lane: dev1 的 HTTP 头,代表须要将流量打到 dev1 泳道中。在这个计划,服务网格中的 Envoy 无需有任何流量打标动作。

图 2

图 3 示例阐明了计划二。本计划中,客户端的流量间接打到服务网格的 Ingress 网关上。由 Ingress 网关依据流量的特色通过 Istio 原生的 VirtualService 匹配规定辨认出后,在转发申请前加上名为 x-asm-traffic-lane 的 HTTP 头,随后将流量路由到相应的泳道。

图 3

图 4 示例阐明了计划三。实质上,这一计划与计划二是齐全一样的,同样通过 Istio 原生的 VirtualService 匹配规定辨认出相应的流量后加上名为 x-asm-traffic-lane 的 HTTP 头。惟一的不同在于,计划二中的 Envoy 的角色是 Ingress,而计划三中 Envoy 的角色是 Sidecar。

图 4

流量一旦实现打标后,由服务网格中的每一个 Envoy 基于流量标和管制面下发的配置做全链路的标透传和按标路由。

流量标识透传

图 5 示例阐明了服务网格中一个服务与边上的 Envoy (Sidecar)间的流量细节。

图 5

从 Envoy 的视角来看,蕴含对流入和流出两种流量的转发。I1 是流入的流量,收到后将转发给本地的 Svc A;O1 是流出的流量(因为解决 l1 的须要而去调用别的服务所引发),收到后将转发给内部的被调用的服务。流入与流出只与申请(request)相干,与申请对应的响应(response)没有关系。显然,一个流入的申请可能导致有多个流出的申请产生(即“分叉”),这齐全取决于 Svc A 的具体业务逻辑。

泳道技术所需解决的外围点在于,当流入的流量打上了相应的标签后,如何让由其所分叉出的每一个流出的流量都带上同样的标签,咱们采纳的计划是联合链路追踪技术(比方,OpenTelemetry)去解决。链路追踪技术是通过 traceId 去惟一标识一条调用链树,为根申请调配并带上全网惟一的 traceId 后,之后由其所分叉出的所有新调用都得带上值齐全一样的 HTTP 头,换句话说服务开发者须要在编程的过程中确保这一头被流传到后续的服务调用中(比方,调用 OpenTelemetry 的 SDK 实现头流传)。换句话说,使用泳道技术的前提是须要每个服务都采纳了链路追踪技术,作为微服务构架的最佳实际之一这一先决条件很容易满足。回到图 5,Svc A 收到 I2 申请并对之解决时须要发动 O1 调用,此时须要确保 I2 中的 traceId 头流传到 O1 申请中,这是 Svc A 的开发者须要特地留神的一个细节。

一旦服务网格中所有服务的申请都带上了 traceId,那么通过 Envoy 实现全链路的流量标透传就是非常简单的事了。大体分这几大步骤:

• Envoy 外部构建一张映射表,记录 traceId 与流量标的映射。比方,图 5 所示的流量标是放在 x-asm-traffic-lane 这一 HTTP 头中的。x-asm-traffic-lane: dev1 代表的流量标是 dev1,x-asm-traffic-lane: canary 代表的流量标是 canary。
• 当申请 I1 进到 Envoy 时,Envoy 基于申请中所带的 traceId 和流量标,在映射表中减少一条映射记录。
• Envoy 对于收到的每一个 O1 申请,基于申请中的 traceId 从映射表中找到对应的流量标并将之减少到 O2 申请中再转发进来。

通过服务网格基于 traceId 打标的技术计划的益处在于,将流量打标的动作和流量标传递做到齐全与服务解耦,将这一能力下沉到原本善于流量治理的服务网格中,让流量调度的灵动性得以进一步解锁。

流量标识与 traceld 的定义

咱们在 Istio 已有 CR 的根底上,新增了 TrafficLabel 这个全新的 CRD。抉择新增而非间接对 VirtualService 做扩大的起因是,VirtualService 的设计之初是利用维度的,当一个业务简单到全链路有很多利用须要放到泳道中时,就得对每个利用的 VirtualService 进行变更,背地所导致的时效性和可操作性会是一个问题。扩大 VirtualService 去实现的另一种思路是,让 VirtualService 具备配置全局规定的能力,而这就要用到规定的合并机制,这一点从实操层面也有问题。Istio 社区对于多个 VirtualService 进行合并的需要有不少探讨,目前只在网关上反对合并,对于 Sidecar 则不提供这一能力,起因在于放心合并的程序不同而导致故障。

图 6 示例阐明了如何应用 TrafficLabel 这一 CR 在 istio-system 根命名空间定义全局无效的流量打标办法。其中定义了名为 x-asm-traffic-lane 的标签,作为 HTTP 申请的头用于寄存流量标识(比方,dev1、dev2、canary 等),以及 traceId 基于 x-request-id 取得。用户能够依据本人所选型的链路追踪零碎的具体实现加以设置。图中设置为从 x-request-id 头中取得,是因为 Envoy 实现了通过 x-request-id 做全网链路唯一性标识的性能。采纳 x-request-id 作为映射表键意味着,咱们能够间接用 Istio 开源社区所提供的 Bookinfo 示例程序去演示泳道的成果,因为 Bookinfo 中的所有服务都做了 x-request-id 头从调入申请到调出申请的流传。

apiVersion: istio.alibabacloud.com/v1beta1
kind: TrafficLabel
metadata:
  name: global-traffic-label
spec:
  rules:
  - labels:
      - name: x-asm-traffic-lane
    protocols: "http"
    traceIdHeader: x-request-id
  hosts:
    - "*"

图 6

按流量标路由

为了反对按流量标路由,须要对 Istio 的 VirtualService 做扩大,让 destination 字段反对用 $x-asm-traffic-lane 这样的变量指定流量的目的地,如下图 7 所示。换句话说,蕴含 x-asm-traffic-lane: dev2 头的流量会打到 dev2 这个泳道中,背地其实是应用 DestinationRule 定义的名为 dev2 的 subset,如图 8 所示。请留神,图 7 中 VirtualService 中的 $x-asm-traffic-lane 这一名称要与图 6 中 TrafficLabel 内所定义的名保持一致。

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - match:
    - headers:
        end-user:
          exact: dev2
    route:
    - destination:
        host: reviews
        subset: dev2
      fallback:
        case: noinstances|notavailable
        target:
          host: reviews
          subset: baseline
      headers:
        request:
          set:
            x-asm-traffic-lane: dev2
  - route:
    - destination:
        host: reviews
        subset: $x-asm-traffic-lane
      fallback:
        case: noinstances|notavailable
        target:
          host: reviews
          subset: baseline
  - route:
    - destination:
        host: reviews
        subset: baseline

图 7

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  subsets:
  - labels:
      version: v2
    name: baseline
  - labels:
      version: v3
    name: dev2

图 8

从图 8 中 DestinationRule 的定义不难看出,除了 baseline 外只定义了 dev2 这个泳道,图 7 则是对应情景下的 VirtualService 定义。两者对应的应用场景正是图 1 中的基线和 dev2 泳道。

产品实现

在云原生的大技术背景之下,易用性被放到了聚光灯之下,咱们深刻理解背地意味着什么。为此,在设计产品的交互时,致力清空本人所知、站在用户所面临的场景上来思考和优化,在功能性和易用性之间致力做好均衡。

在用户应用泳道前,咱们认为他已构建了一个蕴含所有服务在内的基线环境。在 K8s 中,基线环境通常被部署于特定的命名空间中以便更好地运维和治理其中的服务。用户创立泳道时,只需提供泳道名称。本节接下来的内容以创立名为 dev2 的泳道开展。

泳道创立好后,须要将服务公布到泳道之中。因为所公布的服务已存于基线环境中并创立了 K8s Service 资源,所以泳道中公布服务其实是创立对应服务下的一个 Deployment,直观的了解就是创立已有服务的另一个软件版本。不难想到,这一公布动作蕴含确认基线版本,实例数和容器镜像地址。

当服务公布到泳道中后,须要通过泳道的服务列表确保所有服务都失常启动。此时泳道中并没有流量进入,须要通过配置引流规定能力将基线中的流量引入泳道中。

引流规定能够基于 HTTP 头、URI、Cookie 的特色去配置,不便咱们准确地抉择被测流量进入泳道。下图的规定是指将 HTTP 头 end-user 的值为 dev2 的流量引导致 dev2 泳道中。配置规定的同时,须要正确指定入口服务。

引流规定利用后,即可在网页上以 dev2 用户名登录,从而看到 dev2 泳道中服务所出现的成果。上面两图别离示例了全基线和 dev2 泳道所看到的页面成果。因为 dev2 泳道中并没有部署 productpage 和 details 两个服务,所以这两个服务会回退为应用基线中的,而最终出现的成果就是两图中 The Comedy of Errors 和 Book Details 两块的内容是完全一致的。

当服务公布到泳道中上线后,能够在泳道的服务列表中不便地查看各服务与基线版本的流量比对状况。帮忙开发者更好地理解泳道中服务的运行状况。

此外,通过服务拓扑图也能够清晰地看到,dev2 泳道中服务的调用状况(图中的 lane-dev2)。

总结与瞻望

咱们所摸索的基于服务网格的泳道技术,让开发者能秒级创立隔离环境用于开发测试或业务重保,通过准确的引流规定将“爆炸半径”管制到最小。很好地兑现了云原生服务网格技术的新体验和新价值。

接下来,咱们将进一步以场景化的形式买通泳道和版本灰度的性能,让用户能基于直觉应用好这些性能。性能层面,咱们将进一步欠缺泳道中反对的协定,比方 RocketMQ、Dubbo 3.0 等,通过丰盛泳道技术的利用场景去最大水平地施展其价值。

最初,咱们将继续以 Service Mesh as Infra 的理念去构建微服务架构的现代化服务治理平台,和业界搭档一起减速这一新技术的倒退和推广。

作者介绍:李云(花名:至简),阿里云服务网格混合云产品技术负责人。2018 年开始在阿里团体率领团队从事服务网格技术的倒退与建设工作,在 QCon 做过屡次云原生与服务网格的技术分享。

退出移动版