UP | HOME

Service Mesh 调研

Table of Contents

1 背景

最近公司在搞单元化,老大想看看能否趁着这个机会上Service Mesh。所以让我先调研一番。但是有几点要求,一是需要保证可控,二是能够进行二次开发。 目前调研了以下产品的实现方式:

  • Istio
  • SOFAMesh
  • Kuma Mesh
  • Traefik Mesh

下面我将从几个方面介绍不同服务网格的实现与特性。

2 部署模型

以上所有的Service Mesh都分为控制面跟数据面。

  • 控制面:主要用于更新,下发配置。
  • 数据面:主要用于使用控制面的配置进行流量代理。

对于Istio,SOFAMesh,Kuma Mesh来说他们的部署方式大同小异,都是部署一个控制面在容器中。数据面部署以Pod中sidecar容器的方式存在。而Traefik Mesh则有点不同,它使用每一个node部署一个数据面,优点是十分简单而且方便,缺点是需要业务主动接入数据面进行流量代理。Kuma Mesh有个好处是支持ecs跟容器的方式。而其他几个基本都需要有k8s的能力的支持。

3 流量劫持

在流量劫持这块一般有两个做法,一是透明流量劫持,istio,SOFAMesh, Kuma Mesh都是支持的,二是用户主动接入,SOFAMesh跟Traefik Mesh支持这种.

3.1 透明流量劫持

透明流量劫持是通过修改iptables规则,把进入或则出去pod的流量导入sidecar容器,sidecar再通过控制面下发的配置文件来确定流量导向何方。

3.2 主动接入

  • SOFAMesh 虽然也支持透明流量劫持,但是由于iptables性能问题,所以蚂蚁在使用的时候是通过sidecar容器来代理业务容器注册到注册中心,这样注册到服务注册中心的ip地址就是sidecar容器的地址,这样当服务进行发现的时候也是发现的sidecar地址,这样就可以进行流量劫持。而且iptables依赖于conntrack模块,而线上很多机器这个模块是不启用的。
  • Traefik Mesh 使用另外的方式,必须修改业务方的代码,把请求地址改为traefik服务提供的地址。比如当你访问serviceA的时候,你需要访问serviceA.treafik。ps:这跟traefki mesh的部署方式有关,treafik mesh的部署方式是没有node一个traefik网关代理此node的所有流量(而不是像istio一样每个pod一个sidecar)

4 容器注入

除了traefik mesh的的部署方式外,其他的service mesh方案都需要每个pod一个sidecar进行流量代理,所以需要容器注入方案。注入方案也大同小异。

  • 自动注入:通过给namespace打上label,当pod创建的时候通过patch注入init容器跟sidecar容器。
  • 手动注入:通过patch的方式给pod注入init跟sidecar容器。

5 连接迁移

  • 蚂蚁的数据面的一个很实用的特点就是实现了TCP连接透明迁移,会通过unix socket在父子进程中传递tcp连接。连接迁移的一个好处就是当升级sidecar的时候能够进行无感升级,对业务方的流量没有任何损耗. 而且对长连接十分友好。
  • 而对于envoy这样的数据面代理的长连接,会在等待一段时候后强行断开tcp连接,照成流量损失。

6 sidecar 升级

目前在k8s中只支持当修改pod中容器的镜像时可以原地升级,但是跟depolyment会不同步,所以当对于想service mesh中需要实现原地升级镜像的功能一般都是自己实现一个类似deployment的功能。然后通过patch的方式更改pod的image。当然也可以魔改kubelet。

7 选择与实现

在参考了众多开源的service mesh方案与实现后,最终我们选择了魔改traefik mesh。把traefik mesh改成istio的架构模式。主要有以下特性:

  • 基于traefik mesh进行二次开发. 因为traefik的数据面是golang实现,这符合我们的技术栈,而且traefik的代码足够简洁,让我们能够很容易的控制它。
  • 我们选择使用istio的sidecar注入模式,这是因为traefik mesh的模型相当于是一个node一个sidecar,虽然可以对sidecar做高可用,但是我们还是担心流量会互相影响,变得不够健壮。
  • 直接使用istio的iptables命令进行流量劫持,主要是因为这样改动对业务方侵入比较小,可以实现业务无感知接入。而且iptables的性能损耗对于我们的业务是可以接受的。
  • 支持协议探测,在traefik默认的实现中是不支持流量探测的,比如它做不到如下功能:如果一个协议是http,则先寻找http路由规则,当找不到http路由时,再降级到tcp路由。所以我们修改了traefik的实现,让能够支持这种功能。

8 总结

通过这次调研,基本了解了Service Mesh目前的特性跟动态,还有落地上的一些困难。目前主要的落地的一些困难我觉得有以下几点:

  • 开发对Service Mesh的需求不够急迫,Service Mesh属于锦上添花的一种方案,而不是雪中送炭,所以在惰性的情况下大家没什么动力。
  • iptables带来的性能损耗,原来本来是A->B,现在变成A->iptables+sidecar->iptables+sidecar->B,如果不用iptables而采用手动接入又会对业务方产生工作量。感觉只能等ebpf的普及可能会绕过iptables实现流量的高效代理。但是目前ebpf需要的内核还比较新,所以也需要一段时间的等待。
  • 配置的下发的性能问题,目前istio在配置分发下也有一定的性能问题,这是因为目前istio的配置不是按需下发,而基本是全量下发,所以当k8s集群中所有的pod的向控制面请求数据的时候,流量跟请求量也是一个问题。而且如何控制面部署多个会对api server照成一定影响,因为需要watch很多资源。

最后的最后,虽然我们已经实现了一个我们想要的service mesh的demo版本,但是目前项目处于暂停状态,一个是投入的成本问题,还有是线上配置架构迁移问题。这些还需要老大再做决断。总而言之,这次调研跟demo版本的实现让我学到了很多知识,也对这个方向产生了很大的兴趣。