服务网格的最佳实践

2021-02-23 15:55:01 浏览数 (1)

微服务发展的这几年,新的技术和概念层出不穷,这些技术的引入本质上都是在围绕服务稳定性和业务开发效率提升,最近两年服务网格越来越被广大的微服务用户所认知。

在 Kubernetes 已经成为云原生时代的操作系统的今天,如何更好的拥抱 Kubernetes 生态,实现业务快速上云,享受云计算带来的能力,其中服务网格是一个必须要提的关键技术,但是在服务网格使用过程中我们会碰到很多的问题,比如:如何让现有的应用迁移到服务网格,如何支持多种语言、框架的互通和治理,如何使用可观测产品排查问题,接下来我将从如何接入服务网格、异构服务框架、语言的互通和可观测三个方面回答这个问题。

迁移应用到服务网格中

服务网格

服务网格是用于处理服务间通信的专用基础设施层,它负责通过包含现代云原生应用程序的复杂服务拓扑来可靠地传递请求。实际上,服务网格通常通过一组轻量级网络代理来实现,这些代理与应用程序代码一起部署,而不需要感知应用程序本身。

目前主流的服务网格开源软件是 Istio,其整体架构如下:

从图中可以看到服务网格与业务容器是在同一个 Pod 中的不同容器,带来的优势有如下三点:

  • 微服务治理与业务逻辑的解耦。服务网格把 SDK 中的大部分能力从应用中剥离出来,拆解为独立进程,以 Sidecar 的模式进行部署,服务网格通过将服务通信及相关管控功能从业务程序中分离并下沉到基础设施层,使其和业务系统完全解耦,使开发人员更加专注于业务本身。
  • 异构语言/框架的统一治理。随着新技术的发展和人员更替,在同一家公司中往往会出现不同语言、不同框架的应用和服务,为了能够统一管控这些服务,以往的做法是为每种语言、每种框架都开发一套完整的 SDK,维护成本非常之高,而且给公司的中间件团队带来了很大的挑战,有了服务网格之后,通过将主体的服务治理能力下沉到基础设施,多语言的支持就轻松很多了。
  • 服务网格不但可以承担流量代理,对于业务共用的、通用的场景和需求都可以成为服务网格的一部分,这样能有效提高业务开发效率。

应用接入服务网格

目前服务网格对 Kubernetes 支持最完整,同时也支持了 VM 的应用接入,但是需要较多的配置,我们推荐首先将 VM 上的服务容器化后在接入网格中,逐步迁移已有的应用,通过网关来打通服务网格中的应用和 VM 中没有接入服务网格的应用。

服务网格的接入首先是需要安装 Istiod,然后通过对 Namespace 打标来完成 Sidecar 的自动注入,可以选择性的对一些服务不进行 Sidecar 的注入,比如类似 MySQL、Redis 等中间件应用,主要是减少 Envoy 带来的延迟,在 EDAS 中可以针对每个应用进行打标,对需要加入服务网格的应用才进行 Sidecar 的注入。

异构微服务的互通、治理

由于业务的发展,基于业务产品的选择,业务开发语言越来越多种多样,这些语言之间的互通成为大家关注的问题,目前常见的场景如 Java 语言和非 Java 语言的互通,互通中最重要的问题就是服务发现和通信协议的支持。

服务发现

通常我们在使用 Kubernetes 上部署服务如下,其中定义了 Kubernetes Service 用于服务间请求的域名:

代码语言:javascript复制
apiVersion: apps/v1
kind: Deployment
metadata:
  name: details-v1
  labels:
    app: details
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: details
      version: v1
  template:
    metadata:
      labels:
        app: details
        version: v1
    spec:
      containers:
      - name: details
        image: docker.io/istio/examples-bookinfo-details-v1:1.16.2
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080

apiVersion: v1
kind: Service
metadata:
  name: details
  labels:
    app: details
    service: details
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: details

Istio 监听 Kubernetes Api Server,获取服务的 Service、Pod 等数据,通过 XDS 方式提供给 Envoy,Envoy 会通过获取的数据做负载均衡。

很多微服务框架都在使用如 Nacos、Consul、Zookeeper 等注册中心,这部分微服务如何在不进行大规模改造下使用服务网格呢,这就设计到 Istiod 跟注册中心的打通,目前社区提供了以下的几种方式实现注册中心数据打通:

1. MCP Server

编写自定义的 MCP Server 从第三方注册中心获取服务数据,转换为 ServiceEntry 和 WorkloadEntry 资源,通过 MCP 协议提供给 Istio 中的 MCP Config Controller, Istiod 需要配置MCP Server地址,目前在开源项目中包含 MCP Server 的注册中心的有很多,阿里云 MSE 提供托管的 Nacos 注册中心,直接提供 MCP Server 能力。

2. ServiceEntry 和 WorkloadEntry

编写独立的第三方组件,该组件从注册中心中获取服务数据,然后转换为 Istio 中 ServiceEntry 和 WorkloadEntry CRD,写入到 Kubernetes API Server 中。Pilot 的 Kube Controller 会监听 Kubernetes API Server 中和 Istio 相关资源的变化,并将 ServiceEntry 和 WorkloadEntry 转换为内部Service模型,通过Xds协议同步给Sidecar。

3. 自定义适配器

编写自定义的 Adapter 来集成第三方注册中心,该适配器从注册中心中获取服务和服务实例,转换为 Pilot 内部的Service模型,集成到 Service Controller 中,类似现有的Consul Service Registry的适配方式,这种方式的优点就是不需要通过第三方进行转换,但是跟Istio耦合在一起,在 Istio 版本升级较快的时候,需要不断的适配对应的新版本。

MSE 注册中心

第一种方式需要注册中心提供支持,第二种方式需要独立的三方组件进行同步,可用性、维护是一个负担,第三种需要对 Istio 非常熟悉,维护升级成本很高,目前 MSE 注册中心已经支持 MCP Over XDS 的方式对接 Istio,可用性高,免维护。

我们通过 Java Agent 支持Xds协议的方式对接 Istio,同时 Istio 也通过 MCP Over XDS 对接 Nacos 注册中心,这样服务发现的数据在 Java Agent 和 Sidecar 中都能拿到, Java 和非 Java 的服务可以互相发现,互相调用。

服务网格的服务治理

服务网格 Sidecar 通过容器的方式与业务容器共享网络,通过Iptables的方式将 inbound 和 outbound 流量都劫持到 Sidecar 上,Sidecar 解析数据包,获取请求后通过匹配服务发现数据找到对应的服务端,然后匹配对应的路由规则找到满足条件的服务端发送请求。

服务网格的服务治理中Istio的路由规则最关键的两个CRD是VirtualService和DestinationRule,他们描述了请求匹配、路由的过程,如下所示:

代码语言:javascript复制
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
  - name: v3
    labels:
      version: v3
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1

DestinationRule 中包含了 reviews 服务的三个版本,VirtualService 描述了对 reviews 服务的请求会发送到 subset 为 v1 的版本中。其他的服务治理能力还包括了故障注入、服务鉴权、服务超时、熔断等,可以通过写入对应的规则来完成,目前Istio也没有提供非常好使用的白屏化服务治理界面,在 EDAS/MSE 中提供白屏界面操作如服务鉴权、服务查询、离群摘除、金丝雀发布等,保证在操作过程中流量不丢失,路由规则的操作需要遵循以下几个原则:

1、通常使用服务网格服务治理的最佳实践方式是从一开始就为每一个服务创建具有默认路由的 VirtualService,即当你只有一个版本的时候,就写入该版本的 VirtualService 规则,这样在你部署第二个版本中,不至于流量会打到第二个版本中,需要配置路由规则才可以,保证新版本验证过程中不会出现由于新版本自身问题导致的大规模报错。

2、VirtualService 和 DestinationRule 在使用的过程中,Envoy 会首先查看 VirtualService 中的路由规则,以决定是否路由到特定的子集去,只有路由到对应的子集才会激活在 DestinationRule 中对应子集配置的如熔断、离群摘除等规则,同时可以看出 VirtualService 和DestinationRule 的配置也是有顺序的,首先配置 DestinationRule,然后在配置 VirtualService,否则会导致找不到对应的 Subset 报错。

3、更新 DestinationRule 添加一个新的 Subset 后,需要等待 DestinationRule 传播到 Envoy Sidecar,然后再更新对应的 VirtualService。

双模微服务治理

互通的问题通过对接注册中心的方式解决了,那异构框架的服务治理则通过 MSE 来支持,MSE 的服务治理中心可以对接 Java 服务,同时也可以支持服务网格的服务。

MSE 在控制面上支持双模微服务治理,即 Java 服务治理和非 Java 服务治理,控制面对外提供统一的治理模型,我们参考 Istio 的路由规则设计模型,提出一个统一的服务治理规则模型,模型的设计主要考虑到 Dubbo、Spring Cloud 和服务网格治理的通用性。

代码语言:javascript复制
{
    "RegisterConfig":Object{...},
    "protocol":"springcloud",
    "rule_type":"fault_inject",
    "rule":{
        "hosts":Array[1],
        "rule_policy":[
            {
                "match":Array[1],
                "fault":Object{...},
                "route":Array[1],
                "Timeout":"10s",
                "retries":Object{...},
                "mirror":Object{...},
                "mirror_percent":100,
                "headers":Object{...},
                "tls":Object{...}
            },
            {
                "route":[
                    {
                        "destination":Object{...},
                        "weight":"100",
                        "headers":Object{...}
                    }
                ]
            }
        ]
    }
}

上述模型中包含了注册中心、协议、规则类型、路由规则,路由规则中包含了匹配的规则和路由的目的地,MSE通过生成对应这样的CRD来定义不同类型的路由规则,Java Agent 的和服务网格都可以通过监听这样的 CRD 来管理自己的流量,后续我们也会在 OAM 中推出这一套微服务治理规则,用于统一服务治理模型。

可观测

社区开源方案

可观测是微服务能力的重要组成部分,服务网格可以跟目前开源的可观测产品结合,可观测性上主要围绕 Metrics、Tracing 和 Logging 来展开,在 Metrics 上提供数据供 Prometheus 采集,在 Tracing上,Istio 支持 Apache SKyWalking、Zipkin、Jaeger 的链路追踪,这三个中间件都支持 OpenTracing 协议,在 Logging 上,对于日志采集组件的要求也越来越高,目前比较流行的方案是使用 Fluentd 或者 Filebeat 替代 Logstash。

阿里云 EDAS 方案

阿里云 Xtrace 为服务网格提供可观测能力,包含链路追踪、应用概览、拓扑、Metrics 统计,在应用发布后直接可以通过应用详情查看,如下图所示:

拓扑图如下:

可以通过链路追踪查看每个请求过程中的问题,协助问题定位,同时 Xtrace 也提供了不同语言的 SDK,接入 SDK 后可以查看更细粒度的数据。

0 人点赞