是时候聊一下 istio 了

1,138 阅读13分钟

☝点击上方蓝字,关注我们!

本文字数:3657

预计阅读时间:15分钟

导 读

在过去的几年中,微服务技术迅猛发展。随着容器相关技术的普及,服务间的通信管理越来越受到人们的重视。回忆服务间的通信史,从原始的网线直连,到网络层的出现,从应用程序自我控制,到专用的服务发现应用(库)和断路器。技术在不断地快速地进行着更迭。到了 2017 年,以 Spring Cloud 为代表的传统侵入式开发框架,牢牢占据着微服务市场,它甚至一度成为微服务的代名词。天下苦侵入式久矣。就是在这样的大环境下,2017 年以 istio 和 linkerd 为代表的服务网格横空出世,人们才惊觉微服务原来还有这种玩法。那么所谓服务网格和 istio 到底讲了些什么呢,让我们跟随下面的文章来一探究竟吧。

基本概念

服务网格是什么

服务网格(Service Mesh):构成应用程序的微服务网络以及应用之间的交互

服务网络的需求包括:服务发现、负载均衡、故障恢复、指标收集和监控、运维需求(例如 A/B 测试、金丝雀发布、限流、访问控制和端到端认证等)。

服务网格的特点:

  • 应用程序间通讯的中间层;

  • 轻量级网络代理;

  • 应用程序无感知;

  • 解耦应用程序的重试/超时、监控、追踪和服务发现。

istio是什么

Istio 提供一种简单的方式来为已部署的服务建立网络,该网络具有负载均衡、服务间认证、监控等功能,而不需要对服务的代码做任何改动。

简单的说:Istio 提供了一个完整的解决方案来实现服务网格。

istio 具有以下特征:

  • istio 适用于容器或虚拟机环境(特别是k8s),兼容异构架构;

  • istio 使用 sidecard(边车模式)代理服务的网络,不需要对业务代码本身做任何的改动;

  • HTTP、gRPC、WebSocket 和 TCP 流量的自动负载均衡;

  • istio 通过丰富的路由规则、重试、故障转移和故障注入,可以对流量行为进行细粒度控制,支持访问控制、速率限制和配额;

  • istio 对出入集群入口和出口中所有流量的自动度量指标、日志记录和跟踪。

istio架构

istio 构架如图,由数据平面和控制平面组成,具体如下:

数据平面(data plane)

  • 数据平面:由一组以 sidecar 方式部署的智能代理(Envoy1)组成;

  • 作用:调节和控制微服务之间所有的网络通信,以及与 Mixer (控制平面控制器)之间的通信。

sidecar(边车模式):将应用程序的功能划分为单独的进程,在 k8s 中既在同一 pod 中起多个不同功能划分的 container。

Envoy代理

  • Envoy 被部署为 sidecar,和对应服务在同一个 Kubernetes pod 中;

  • 调解服务网格中所有服务的所有入站和出站流量。

控制平面(control plane)

  • 管理和配置代理。

Mixer

  • 负责在服务网格上执行访问控制使用策略

  • 从 Envoy 代理和其他服务收集遥测数据

Pilot

  • 为 Envoy sidecar 提供服务发现功能;

  • 为智能路由(例如 A/B 测试、金丝雀部署等)和弹性(超时、重试、熔断器等)提供流量管理功能

  • 将控制流量行为的高级路由规则转换为特定于 Envoy 的配置。

Citadel

  • 传输身份验证(服务到服务身份验证);

  • 来源身份认证(最终用户身份验证)。

Galley

  • 其他的 Istio 控制平面组件;

  • 验证用户编写的 Istio API 配置;

  • 将其他的 Istio 组件与从底层平台(例如 Kubernetes)获取用户配置的细节中隔离开来。

功能

Istio 最令人感到激动的地方就是它丰富的功能,主要分为:流量管理、安全与访问控制、监控(遥测)三个方面。

流量管理

  1. http 路由:根据 http 内容进行路由,比如根据 http header 中的用户信息进行权限控制;

  2. tcp 路由:TCP 流量控制;

  3. 基于权重的路由:按比例控制流量,支持 http、tcp;

  4. 故障注入:可以在服务之间注入延迟、终止等,在测试服务时会有帮助。

  5. 超时设置:可以给 http 请求设置超时。istio 的超时和应用本身的超时设置结合起来可以使语义更清晰,控制更精细;

  6. ingress 控制:利用 istio gateway,可以将监控、路由规则应用于进入集群的流量;

  7. egress 控制:通过 ServiceEntry 可以控制(监控、路由规则)集群调用外部服务;

  8. 熔断:可以自定义配置熔断规则,包括:并发限制、开放时间等;

  9. 镜像流量:可以将实时流量的副本发送到镜像服务,镜像的请求是“即发即弃”(镜像请求引发的响应会被丢弃)。

安全与访问控制

  • TLS、CA;

  • service role:namespace 级访问控制、服务集(service)访问控制;

  • 身份验证(JWT):基于组(用户组)、基于列表。

监控(遥测)

Prometheus

从 envoy 收集日志和指标,存储,提供查询接口。

主要的指标有:

  1. Request Count:随 Istio 代理处理的每个请求递增;

  2. Request Duration:它测量请求的持续时间;

  3. Request Size:它测量 HTTP 请求的 body 大小;

  4. Response Size:它测量 HTTP 响应 body 的大小;

  5. Tcp Byte Sent:它测量在 TCP 连接场景下响应期间发送的总字节数,由服务端代理测量;

  6. Tcp Byte Received:它测量在 TCP 连接场景下请求期间接收的总字节数,由服务端代理测量。

Granfana

日志指标的可视化展示。

Jeager

分布式追踪,通过往 http 请求中加入特定 header 实现,要求应用必须转发传播该 header(异构项目兼容)。

示例

为了更好了理解 istio 强大的功能,下面以官网 book-info 为例,简单看一下流量控制和遥测等功能。

首先部署一个简短书评网站,构架如图:

网站包括四个微服务:

  • productpage :本服务会调用 details 和 reviews 两个微服务,用来生成页面;

  • details :这个微服务包含了书籍的信息;

  • reviews :这个微服务包含了书籍相关的评论,它还会调用 ratings 微服务;

  • ratings :ratings 微服务中包含了由书籍评价组成的评级信息。

reviews 微服务有 3 个版本:

  • v1 版本不会调用 ratings 服务;

  • v2 版本会调用 ratings 服务,并使用 1 到 5 个黑色星形图标来显示评分信息;

  • v3 版本会调用 ratings 服务,并使用 1 到 5 个红色星形图标来显示评分信息。

访问效果如下:

由于 Bookinfo 示例部署了三个版本的 reviews 微服务,当我们多次访问应用程序时,可以看到有时输出包含星级评分,有时又没有。

智能路由

可以通过路由规则对流量进行细粒度的控制。

自定义路由

首先将所有流量导入 v1 版本的 reviews,使用如下配置,并提交给 k8s :

 1apiVersion: networking.istio.io/v1alpha3 2kind: VirtualService 3metadata: 4  name: reviews 5spec: 6  hosts: 7  - reviews 8  http: 9  - route:10    - destination:11        host: reviews12        subset: v1

稍等几秒钟就可以看到变化:

可以看到现在所有流量都走 v1 版 review。

根据header内容分发流量

istio 可以基于内容分发流量,在这里我们让普通用户全部访问 v1 版,而特殊用户(jason)访问 v2 版,使用如下配置,并提交给 k8s:

 1apiVersion: networking.istio.io/v1alpha3 2kind: VirtualService 3metadata: 4  name: reviews 5spec: 6  hosts: 7    - reviews 8  http: 9  - match:10    - headers:11        end-user:12          exact: jason13    route:14    - destination:15        host: reviews16        subset: v217  - route:18    - destination:19        host: reviews20        subset: v1

可以看到普通用户仍然访问 v1 版 review。

而以 jason 身份登录后会访问 v2 版 review(黑色五角星)。

除此以外,istio 可以在服务之间注入延迟、断开等故障,也可以做到按比例迁移等需求。

监控

在 Istio 中,可以让 Mixer 自动为所有的网格内流量生成和报告新的指标以及新的日志流。下面以 book-info 应用为例,展示分布式追踪。

Prometheus

用作指标采集与查询。

分布式追踪

虽然 Istio 代理能够自动发送 Span 信息,但还是需要一些辅助手段来把整个跟踪过程统一起来。应用程序应该自行传播跟踪相关的 HTTP Header,这样在代理发送 Span 信息的时候,才能正确的把同一个跟踪过程统一起来。

productpage 服务访问总览:

调用链追踪:

服务拓扑图:

grafana

使用 grafana 对 istio 本身和服务网格进行监控。

服务大盘:

原理分析

sidecar

sidecar(边车模式):将应用程序的功能划分为单独的进程,在 k8s 中既在同一 pod 中起多个不同功能划分的 container。

istio 手工注入 sidecar 会修改 deployment,增加两个容器:

  • Init 容器 istio-init:用于给 Sidecar 容器即 Envoy 代理做初始化,设置 iptables 端口转发;

  • Envoy sidecar 容器 istio-proxy:运行 Envoy 代理。

一个 istio 注入的 sidecar deployment 模板示例:

 1containers: 2- name: istio-proxy 3  image: istio.io/proxy:0.5.0 4  args: 5  - proxy 6  - sidecar 7  - --configPath 8  - {{ .ProxyConfig.ConfigPath }} 9  - --binaryPath10  - {{ .ProxyConfig.BinaryPath }}11  - --serviceCluster12  {{ if ne "" (index .ObjectMeta.Labels "app") -}}13  - {{ index .ObjectMeta.Labels "app" }}14  {{ else -}}15  - "istio-proxy"16  {{ end -}}
sidecar 的流量劫持是通过 iptables 转发实现的,详细的流量劫持过程可以参考这篇文章[1]

Pilot与Envoy通信

  1. discovery service(pilot-discovery二进制):从Kubernetes apiserver list/watch service、endpoint、pod、node等资源信息,监听istio控制平面配置信息(如VirtualService、DestinationRule等), 翻译为 Envoy 可以直接理解的配置格式;

  2. proxy(Envoy二进制):也就是 Envoy,直接连接 discovery service 获取配置(相当于间接地从 Kubernetes 等服务注册中心获取集群中微服务的注册情况);

  3. agent(pilot-agent二进制):生成 Envoy 配置文件,管理 Envoy 生命周期;

  4. service A/B:使用了 istio 的应用,如 Service A/B的进出网络流量会被 proxy 接管。

性能测试

官方性能测试

在官方给定的标准测试[2]下(1000 services、2000 sidecars、70,000/s 网格内调用),大概性能数据如下:

  • Envoy 代理每 1000 qps 消耗 0.6 vCPU 和 50 MB 内存;

  • 遥测服务每 1000 qps (网格内调用)消耗 0.6 vCPU;

  • Pilot 消耗 1 vCPU 和 1.5 GB 内存;

  • Envoy 代理使得 90% 的调用都增加 8ms 的延迟。

有几点需要注意一下:

  • proxy 的策略越复杂,延时增加越多;

  • 遥测数据异步发送,不影响当前请求的响应时间,但是会造成网络拥堵,间接增加延时。

测试方案说明

本次测试基于 istio 1.2 版本,单机版 k8s(v1.14.3)。

  1. fortio 是一个端到端负载测试工具,在本例中调用 Service A;

  2. Service A 与 Service B 之间有调用关系,可以控制他们的调用深度(即 Service A 返回给 fortio 之前经过 几次 A 和 B 之间调用);

  3. fortio 与两个 Service 在同一 namespace 下;

  4. 测试结果 1 ~ 3 没有包含了基本遥测配置。

测试结果

1. istio性能损耗

在 500 QPS、调用深度为 3(即 Service A 返回给 fortio 之前经过 3 次 A 和 B 之间调用)的情况下,有 istio 代理和没有 istio 代理的性能差异:

可以看到,istio 的 P90 = 6.63 ms(90% 的调用都小于 6.63 ms),没有 istio 的 P90 = 3.70 ms 。调用延时增加了 3ms。

2. 调用深度对延迟的影响

在 500 QPS、调用深度分别为 0、3、5、8、10、12 的情况下,有 istio 代理的调用延迟分析图:

无 istio 代理的调用延迟分析图:

选取调用深度分别为 5、8、10、12的测试,进行对比:

红线左侧是深度分别为 5、8、10、12 时有 istio 代理的调用延迟,红线右侧是深度分别为 5、8、10、12 时无 istio 代理的调用延迟。

可以看到随着调用深度的增加,istio 代理所增加的延时相应增加,但增加幅度放缓。8 次以上的调用深度,有 istio 代理的 P90 平均比无 istio 代理的 P90 高 10 ms。

3. QPS对延迟的影响

在调用深度为 3、QPS 分别为 300、 500、 1000 的情况下,有 istio 代理的调用延迟分析图:

无 istio 代理的调用延迟分析图:

可以看到,QPS 的增加并不会增加调用延时。

性能测试小结

  • 调用延时的增加主要和调用深度(经过 istio proxy 的层数)正相关;

  • 调用层数每增加一层,有 istio 的 P90 延时比无 istio 的 P90 延时平均增加 1 ms;

  • QPS 的增加并不会增加调用延时。

备注:我在测试时,服务间调用 QPS 最高压到过 45k,以上结论仍然成立。对于 istio proxy 的 QPS 极限在哪里,需要后面做出更详细的测试。

go-client操作istio资源

我们可以利用 k8s 提供的 go-client 来操作 istio crd 资源。

步骤如下:

  • 在 pkg/apis/{API Group}/{version} 下编写 crd 定义;

  • 增加合适的代码生成标签,参考[3]

  • 利用 code-generator[4] 生成 clientset、informer 等代码。

如果是需要操作别人已经预先定义好的 crd,可以直接在定义 crd 时进行引用。以 istio 的 virtual service 为例,只需引入 istio.io/api/networking/v1alpha3/VirtualService 即可。

我已经把生成好的 api 代码,放到了 github 上,有需要的同学可以自行取用[5]

Istio crd代码生成脚本

1# 代码生成的工作目录,也就是我们的项目路径2ROOT_PACKAGE="github.com/RuiWang14/k8s-istio-client"34# 安装 k8s.io/code-generator5go get -u k8s.io/code-generator/...6cd $GOPATH/src/k8s.io/code-generator78# 执行代码自动生成,其中 pkg/client 是生成目标目录,pkg/apis 是类型定义目录9./generate-groups.sh all "$ROOT_PACKAGE/pkg/client" "$ROOT_PACKAGE/pkg/apis" "authentication:v1alpha1 networking:v1alpha3"

参考:

[1].https://jimmysong.io/istio-handbook/concepts/sidecar-injection-deep-dive.html

[2].https://istio.io/docs/concepts/performance-and-scalability/  

[3].https://blog.openshift.com/kubernetes-deep-dive-code-generation-customresources/

[4].https://github.com/kubernetes/code-generator

[5].https://github.com/RuiWang14/k8s-istio-client


也许你还想看

(▼点击文章标题或封面查看)

搜狐新闻推荐算法 | 呈现给你的,都是你所关心的

2018-08-30

新闻推荐系统的CTR预估模型

2019-04-18

互联网架构演进之路

2018-08-16

加入搜狐技术作者天团

千元稿费等你来!

戳这里!☛