NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

通过 Istio 重新实现微服务(四):跨服务跟踪和流量管理

  • 2019-05-27
  • 本文字数:6980 字

    阅读完需:约 23 分钟

通过 Istio 重新实现微服务(四):跨服务跟踪和流量管理

内置的特性

通过拦截所有的网络通信,Istio 能够得到一些指标和数据,这些指标和数据能够用来实现整个应用的可观察性。Kiali是一个开源的项目,它能够利用这些数据回答这样的问题:微服务是如何成为 Istio 服务网格的一部分的,它们是如何连接在一起的?

Kiali——可观察性

在安装 Istio 到我们的集群中之前,我们创建了一个用于 kiali 的 secret(还有另外一个用于 grafana),其中,我们将 user 和 password 都设置为 admin。要访问 Kiali 的 Admin UI,需要执行如下的命令:


$ kubectl port-forward \  $(kubectl get pod -n istio-system -l app=kiali \   -o jsonpath='{.items[0].metadata.name}') \  -n istio-system 20001
复制代码


打开http://localhost:20001/并使用“admin”(不含引号)作为 user 和 password 进行登录。这里很有多有用的特性,比如检查 Istio 组件的配置、拦截网络请求和响应所收集的信息构建的可视化服务,比如“谁调用了谁?”,“哪个版本的服务出现了故障?”等等。在进入下一步章节学习使用 Grafana 可视化指标之前,请花一些时间检验 Kiali 的功能。



图 10 Kiali——服务可观察性

Grafana——指标可视化

Istio 收集到的指标被放到了 Prometheus 中,并使用 Grafana 进行可视化。要访问 Grafana 的 Admin UI,请执行如下的命令并打开http://localhost:3000


$ kubectl -n istio-system port-forward \  $(kubectl -n istio-system get pod -l app=grafana \   -o jsonpath='{.items[0].metadata.name}') 3000

复制代码


在左上角点击 Home 菜单,并选择 Istio Service Dashboard,然后选择 sa-web-app 打头的服务,这样我们就会看到收集到的指标,如下图所示:



图 11 Grafana 指标的可视化


这是一个空的视图,一点也无法调动我们的兴致,管理层是不允许这样的。通过如下的命令,我们可以造一些负载出来:


$ while true; do \  curl -i http://$EXTERNAL_IP/sentiment -H "Content-type: application/json" \   -d '{"sentence": "I love yogobella"}' \  sleep .8; done
复制代码


现在,我们的图表漂亮多了,除此之外,我们还有一些非常棒的工具,Prometheus 能够用来监控,Grafana 能用来对指标进行可视化,有了它们之后,我们就能知道随着时间的推移服务的性能、健康状况以及是否有升级和降级。


最后,我们将会研究一下如何跨服务进行跟踪。

Jaeger——跟踪

我们需要跟踪系统的原因在于服务越多就越难以定位失败的原因。以下面图中这个简单的场景为例:



图 12 一个常见的请求失败


请求调用进来了,但是出现了失败,失败的原因是什么呢?是第一个服务失败还是第二个服务失败?两者都发生了异常,我们需要探查它们的日志。我们有多少次重复这样的经历了?在一定程度上讲,我们更像软件侦探,而不是开发人员。


这是微服务中一个非常普遍的问题,借助分布式的跟踪系统可以解决该问题,这种跟踪系统会在服务间传递一个唯一的 header 信息,然后这个信息会发送至分布式跟踪系统中,这样请求的跟踪信息就能汇总在一起了。样例如图 13 所示:



图 13 用于识别请求 span 的 TraceId


Istio 使用了 Jaeger Tracer,后者实现了 OpenTracing API,这是一个独立于供应商的框架。要访问 Jaegers UI,请执行如下的命令:


$ kubectl port-forward -n istio-system \  $(kubectl get pod -n istio-system -l app=jaeger \   -o jsonpath='{.items[0].metadata.name}') 16686
复制代码


然后通过http://localhost:16686打开 UI,选择 sa-web-app 服务,如果服务没有出现在下拉列表中的话,那么在页面进行一些活动,并点击刷新。随后点击 Find Traces 按钮,它只会展现最近的 trace,选择任意一条记录,所有的跟踪信息将会分别展示,如图 14 所示:



图 14 Jaeger-一个请求的跟踪信息


trace 展示了如下所述的信息:


  1. 传入 istio-ingressgateway 的请求(这是第一次与某个服务产生关联,所以会生成 Trace ID),随后网关将请求转发至 sa-web-app 服务;

  2. sa-web-app 服务中,请求会被 Envoy 容器捕获并生成一个 span child(这就是我们能够在 trace 中看到它的原因),然后会被转发至 sa-web-app 应用。

  3. 在这里,sentimentAnalysis 方法会处理请求。这些 trace 是由应用生成的,这意味着需要对代码进行一些修改;

  4. 在此之后,会发起针对 sa-logic 的 POST 请求。sa-web-app 需要将 Trace ID 传播下去;

  5. ……


注意:在第 4 步,我们的应用需要获取 Istio 生成的 header 信息,并将其向下传递给下一个请求,如下面的图片所示。



图 15 (A)Istio 传播 header 信息,(B)服务传播 header 信息


Istio 承担了主要的工作,它会为传入的请求生成 header 信息、为每个 sidecar 创建新的 span 并传递 span,但是,如果我们的服务不同时传播这些 header 信息的话,那么我们就会丢失请求的完整跟踪信息。


要传播的 header 信息如下所示:


x-request-idx-b3-traceidx-b3-spanidx-b3-parentspanidx-b3-sampledx-b3-flagsx-ot-span-context
复制代码


尽管这是一个很简单的任务,但依然有很多的库在简化这个过程,例如,在 sa-web-app 服务中,RestTemplate 客户端就进行了 instrument 操作,这样的话,我们只需要在依赖中添加 Jaeger 和 OpenTracing 就能传播 header 信息了。


在研究了开箱即用(以及部分开箱即用)的功能之后,我们看一下这里的主要话题,也就是细粒度路由、管理网络流量以及安全性等等。

流量管理

借助 Envoy,Istio 能够提供为集群带来很多新功能:


  • 动态请求路由:金丝雀发布、A/B 测试

  • 负载均衡:简单一致的 Hash 均衡

  • 故障恢复:超时、重试、断路器

  • 故障注入:延时、请求中断等。


在本文后面的内容中,我们将会在自己的应用中展示这些功能并在这个过程中介绍一些新的概念。我们要介绍的第一个概念就是 DestinationRules,并使用它们来实现 A/B 测试。

A/B 测试——Destination Rule 实践

A/B 测试适用于应用有两个版本的场景中(通常这些版本在视觉上有所差异),我们无法 100%确定哪个版本能够增加用户的交互,所以我们同时尝试这两个版本并收集指标。


为了阐述这种场景,我们部署前端的第二个版本(使用绿色按钮替换白色按钮)。执行如下的命令:


$ kubectl apply -f resource-manifests/kube/ab-testing/sa-frontend-green- deployment.yamldeployment.extensions/sa-frontend-green created
复制代码


绿色版本的部署 manifest 有两点差异:


  1. 镜像基于不同的标签:istio-green

  2. pod 添加了version: green标记。


因为两个 deployment 都有app: sa-frontend标记,所以 virtual service sa-external-services在将请求路由至sa-frontend服务时,会转发到这两者上面,并且会使用 round robin 算法进行负载均衡,这样会导致图 16 所示的问题。



图 16 请求的文件未找到


这里有文件没有找到的错误,这是因为在应用的不同版本中它们的名称不相同。我们验证一下:


$ curl --silent http://$EXTERNAL_IP/ | tr '"' '\n' | grep main/static/css/main.c7071b22.css /static/js/main.059f8e9c.js$ curl --silent http://$EXTERNAL_IP/ | tr '"' '\n' | grep main/static/css/main.f87cd8c9.css/static/js/main.f7659dbb.js
复制代码


也就是说,index.html在请求某个版本的静态文件时,被负载均衡到了另外一个版本的 pod 上了,这样的话,就会理解为其他文件不存在。这意味着,对我们的应用来说,如果想要正常运行的话,就要引入一种限制“为 index.html 提供服务的应用版本,必须也要为后续的请求提供服务”。


我们会使用一致性 Hash 负载均衡(Consistent Hash Loadbalancing)来达成这种效果,这个过程会将同一个客户端的请求转发至相同的后端实例中,在实现时,会使用一个预先定义的属性,如 HTTP header 信息。使用 DestionatioRules 就能够让这一切变成现实。

DestinationRules

在 VirtualService 将请求路由至正确的服务后,借助 DestinationRules 我们能够为面向该服务实例的流量指定策略,如图 17 所示。



图 17 借助 Istio 资源进行流量管理


注意: 图 17 用非常易于理解的方式可视化地展现了 Istio 资源是如何影响网络流量的。但是,精确决定请求要发送至哪个实例是 Ingress Gateway 的 Envoy 完成的,它需要使用 CRD 来进行配置。


借助 Destination Rules 我们可以配置负载均衡使用一致哈希算法,从而确保相同的用户会由同一个服务实例提供响应。我们可以通过如下的配置实现这一点:


apiVersion: networking.istio.io/v1alpha3 kind: DestinationRulemetadata:  name: sa-frontendspec:  host: sa-frontend  trafficPolicy:      loadBalancer:        consistentHash:            httpHeaderName: version   # 1
复制代码


1.根据“version”头信息的内容生成 consistentHash


执行如下的命令应用该配置:


 $ kubectl apply -f resource-manifests/istio/ab-testing/destinationrule-sa- frontend.yaml destinationrule.networking.istio.io/sa-frontend created
复制代码


执行如下命令并校验在指定 version header 信息时会得到相同的文件:


$ curl --silent -H "version: yogo" http://$EXTERNAL_IP/ | tr '"' '\n' | grep main
复制代码


注意:在浏览器中,你可以使用chrome扩展为 version 设置不同的值。


DestinationRules 有很多其他负载均衡的功能,关于其细节,请参考官方文档


在更详细地探索 VirtualService 之前,通过如下的命令移除应用的 green 版本和 DestinationRules:


$ kubectl delete -f resource-manifests/kube/ab-testing/sa-frontend-green- deployment.yamldeployment.extensions "sa-frontend-green" deleted$ kubectl delete -f resource-manifests/istio/ab-testing/destinationrule-sa- frontend.yamldestinationrule.networking.istio.io "sa-frontend" deleted
复制代码

Shadowing———Virtual Services 服务实践

当我们想要在生产环境测试某项变更,但是不想影响终端用户的时候,可以使用影子(Shadowing)或镜像(Mirroring)技术,这样的话,我们能够将请求镜像至具有变更的第二个实例并对其进行评估。或者说更简单的场景,你的同事解决了一个最重要的缺陷,并提交了包含大量内容的 Pull Request,没人能够对其进行真正的审查。


为了测试这项特性,我们通过如下的命令创建 SA-Logic 的第二个实例(它是有缺陷的):


$ kubectl apply -f resource-manifests/kube/shadowing/sa-logic-service.buggy.yaml
复制代码


执行下面的命令校验所有的版本除了app=sa-logic之外都带有对应版本的标记:


$ kubectl get pods -l app=sa-logic --show-labelsNAME                              READY   LABELSsa-logic-568498cb4d-2sjwj         2/2    app=sa-logic,version=v1sa-logic-568498cb4d-p4f8c         2/2    app=sa-logic,version=v1sa-logic-buggy-76dff55847-2fl66   2/2    app=sa-logic,version=v2sa-logic-buggy-76dff55847-kx8zz   2/2    app=sa-logic,version=v2
复制代码


因为sa-logic服务的目标是带有app=sa-logic标记的 pod,所以传入的请求会在所有的实例间进行负载均衡,如图 18 所示:



图 18 Round Robin 负载均衡


但是,我们想要将请求路由至 version v1 的实例并镜像至 version v2,如图 19 所示:



图 19 路由至 v1 并镜像至 v2


这可以通过组合使用 VirtualService 和 DestinationRule 来实现,Destination Rule 声明子集,而 VirtualService 路由至特定的子集。

通过 Destination Rule 声明子集

我们通过如下的配置定义子集:


apiVersion: networking.istio.io/v1alpha3 kind: DestinationRulemetadata:  name: sa-logicspec:  host: sa-logic   # 1  subsets:  - name: v1   # 2      labels:        version: v1  # 3  - name: v2      labels:      version: v2

复制代码


  1. host 定义这个规则只适用于路由至 sa-logic 服务的请求;

  2. 当路由至子集实例时所使用子集名称;

  3. 以键值对形式定义的标记,将实例定义为子集的一部分。


通过执行如下的命令应用该配置:


$ kubectl apply -f resource-manifests/istio/shadowing/sa-logic-subsets- destinationrule.yamldestinationrule.networking.istio.io/sa-logic created
复制代码


在子集定义完之后,我们可以继续配置 VirtualService,让针对 sa-logic 的请求遵循如下的规则:


  1. 路由至名为 v1 的子集;

  2. 镜像至名为 v2 的子集。


这可以通过如下的 manifest 实现:


apiVersion: networking.istio.io/v1alpha3 kind: VirtualServicemetadata:  name: sa-logicspec:  hosts:    - sa-logic  http:  - route:    - destination:        host: sa-logic        subset: v1    mirror:      host: sa-logic      subset: v2

复制代码


所有的配置都很具有表述性,我们不再赘述,接下来看一下它的实际效果:


$ kubectl apply -f resource-manifests/istio/shadowing/sa-logic-subsets-shadowing- vs.yamlvirtualservice.networking.istio.io/sa-logic created
复制代码


通过执行如下命令生成一些负载:


$ while true; do curl -v http://$EXTERNAL_IP/sentiment \   -H "Content-type: application/json" \  -d '{"sentence": "I love yogobella"}'; \  sleep .8; done
复制代码


在 Grafana 检查结果,你会发现有缺陷的版本会出现 60%的请求失败,但是这些失败都不会影响终端用户,因为他们是由当前活跃的服务来提供响应的。



图 20 sa-logic 服务的成功率


在本节中,我们第一次看到如何将 VirtualService 用到服务的 envoy 上,当 sa-web-app 发起对 sa-logic 的请求时,会经过 sidecar envoy,借助我们配置的 VirtualService,将会路由至 sa-logic 的 v1 子集并镜像至 v2 子集。

金丝雀部署

金丝雀(Canary)部署指的是让少量用户使用应用新版本的一个过程,借助这一过程能够验证新版本是否存在问题,然后能够确保以更高的质量发布给更多的受众。


我们继续使用sa-logic带有缺陷的子集来阐述金丝雀发布。


首先,我们大胆地将 20%的用户发送至带有缺陷的版本(这就是金丝雀发布),并将 80%的用户发送至正常的服务,这可以通过如下的 VirtualService 来实现:


apiVersion: networking.istio.io/v1alpha3 kind: VirtualServicemetadata:  name: sa-logicspec:  hosts:    - sa-logic  http:  - route:    - destination:    host: sa-logic    subset: v1    weight: 80         # 1  - destination:    host: sa-logic    subset: v2      weight: 20         # 1
复制代码


1.权重声明了请求要转发到目的地或目的地子集的百分比。


通过下面的命令,更新上述的sa-logic virtual service:


$ kubectl apply -f resource-manifests/istio/canary/sa-logic-subsets-canary-vs.yamlvirtualservice.networking.istio.io/sa-logic configured
复制代码


我们马上可以看到有些请求失败了:


$ while true; do \  curl -i http://$EXTERNAL_IP/sentiment -H "Content-type: application/json" \   -d '{"sentence": "I love yogobella"}' \  --silent -w "Time: %{time_total}s \t Status: %{http_code}\n" -o /dev/null; \   sleep .1; doneTime: 0.153075s      Status: 200Time: 0.137581s      Status: 200Time: 0.139345s      Status: 200Time: 30.291806s    Status: 500
复制代码


VirtualServices 实现了金丝雀发布,借助这种方法,我们将潜在的损失降低到了用户群的 20%。非常好!现在,当我们对代码没有确切把握的时候,就可以使用 Shadowing 技术和金丝雀发布。

超时和重试

代码不仅仅会有缺陷,在“分布式计算的8个谬误”中,排名第一的就是“网络是可靠的”。网络实际上是不可靠的,这也是我们需要超时和重试的原因。


为了便于阐述,我们将会继续使用有缺陷版本的sa-logic,其中随机的失败模拟了网络的不可靠性。


带有缺陷的服务版本会有三分之一的概率在生成响应时耗费过长的时间,三分之一的概率遇到服务器内部错误,其余的请求均能正常完成。


为了降低这些缺陷的影响并给用户带来更好的用户体验,我们会采取如下的措施:


  • 如果服务耗时超过了 8 秒钟,将会超时;

  • 对于失败的请求进行重试。


这可以通过如下的资源定义来实现:


apiVersion: networking.istio.io/v1alpha3 kind: VirtualServicemetadata:  name: sa-logicspec:  hosts:    - sa-logic  http:  - route:    - destination:        host: sa-logic        subset: v1      weight: 50    - destination:        host: sa-logic        subset: v2      weight: 50  timeout: 8s  # 1  retries:    attempts: 3  # 2    perTryTimeout: 3s  # 3

复制代码


  1. 请求有 8 秒钟的超时;

  2. 它会尝试 3 次;

  3. 如果耗时超过 3 秒钟就将本次尝试标记为失败。


这是一种优化:用户的等待不会超过 8 秒钟,如果失败的话,我们将会重试三次,这样的话增加了获取成功响应的概率。


通过如下命令应用更新后的配置:


$ kubectl apply -f resource-manifests/istio/retries/sa-logic-retries-timeouts- vs.yamlvirtualservice.networking.istio.io/sa-logic configured
复制代码


查阅 Grafana 中的图表,看成功率是否有所提升(参见图 21)。



图 21 在使用超时和重试功能之后,带来了成功率的提升


在进入下一节之前,通过如下命令移除掉sa-logic-buggy和 VirtualService:


$ kubectl delete deployment sa-logic-buggydeployment.extensions "sa-logic-buggy" deleted$ kubectl delete virtualservice sa-logicvirtualservice.networking.istio.io "sa-logic" deleted
复制代码




系列回顾


通过 Istio 重新实现微服务 (一):认识 Istio


通过 Istio 重新实现微服务 (二):Istio 实践


通过 Istio 重新实现微服务 (三):使用 Istio 代理运行应用


2019-05-27 10:235760

评论

发布
暂无评论
发现更多内容

小程序运营怎么做?

源字节1号

软件开发 前端开发 后端开发 小程序开发

LeetCode第一个错误版本使用JavaScript解题

大师兄

算法 前端 10月月更

leetcode 785. Is Graph Bipartite判断二分图 (中等)

okokabcd

LeetCode 数据结构与算法

打破“双十定律”,华为云AI推动超级抗菌药Drug X研发加速

华为云开发者联盟

AI 华为云 药物研发 盘古大模型 企业号十月 PK 榜

翻遍GitHub,这份MySQL全面手册,受喜爱程度不输任何大厂笔记

Geek_0c76c3

Java MySQL 程序员 架构 面试

一文读懂 MySQL 索引

说故事的五公子

MySQL 数据库 索引

OpenHarmony社区运营报告(2022年9月)

OpenHarmony开发者

OpenHarmony

算法基础(五)| 差分算法及模板详解

timerring

算法 10月月更 差分算法

web3 chainlink 预言机喂价、VRF

1_bit

智能合约 web3 chanlink

初学大数据培训学习入门

小谷哥

前端线下面授培训机构该怎么选择?

小谷哥

【LeetCode】仅执行一次字符串交换能否使两个字符串相等Java题解

Albert

LeetCode 10月月更

来看看这份对标80W+年薪的Java进阶路线图,职业规划路线该怎么走一目了然!

Geek_0c76c3

Java 程序员 架构 面试

阿里 DBA 首次公开 MySQL 调优笔记,GitHub上已经开始疯狂涨星

Geek_0c76c3

Java 数据库 开源 程序员 面试

唐刘:透明一切,是我们在复杂环境下与客户建立信任的最佳途径

PingCAP

TiDB

多云管理平台支持哪些平台?哪款比较火?

行云管家

云计算 多云 云管理

大数据学习培训机构怎么去选择

小谷哥

快速上手SpringBoot

亮点

Java spring-boot 10月月更

GitHub已置顶安排!Alibaba最终Guide版Java面试突击宝典+架构师系统进阶指南

Geek_0c76c3

Java 数据库 开源 程序员 开发

MobPush iOS端常见问题

MobTech袤博科技

ios

技术分享预告|DocArray x Redis 比快更快的向量搜索

Jina AI

人工智能 开源 算法 向量检索 神经搜索

三翼鸟:智能的是产品,智慧的是生活

脑极体

从简历被拒到收割8个大厂offer,我只用了三个月

程序知音

Java 架构 java面试 后端技术 Java面试八股文

浅析+在Node中实现JWT鉴权机制!

CoderBin

前端 Node JWT Express 10月月更

前端培训学习的就业前景是什么样的

小谷哥

web前端技术培训学习好点

小谷哥

ShareSDK Android端权限说明

MobTech袤博科技

sdk Andriod

HummerRisk V0.4发布:新增云资源态势、资源拓扑、检测规则组、支持在 K8s 安装及大量功能优化

HummerCloud

云计算 云原生 态势感知 云安全 混合云

STM32L051测试 (二、开始添加需要的代码)

矜辰所致

stm32 STM32CubeMX 10月月更

抖音后端123面开挂,全靠这份啃了58天的「Java进阶核心知识集」

Geek_0c76c3

Java 数据库 程序员 架构 面试

启科量子国产量子编程软件项目将启动开源计划

启科量子开发者官方号

人工智能 量子计算 量子模拟 Python. C++

通过 Istio 重新实现微服务(四):跨服务跟踪和流量管理_文化 & 方法_Rinor Maloku_InfoQ精选文章