速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

通过 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:235905

评论

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

模块八作业:设计消息队列存储消息数据的 MySQL 表格

王大胖

ETL调度软件TASKCTL核心调度节点安装

敏捷调度TASKCTL

kettle 调度引擎 ETL 任务队列 调度任务

怒肝 JavaScript 数据结构 — 栈篇(三)

杨成功

数据结构 4月月更

无需编程,基于微软mssql数据库零代码生成CRUD增删改查RESTful API接口

crudapi

低代码 API crud crudapi 增删改查

10个商品图策略,引导亚马逊卖家提升客户购物体验

龙国富

电商 商品 亚马逊 客户体验

脉冲能量|Committer 专访——李理:Apache Pulsar 项目“体验师”

Apache Pulsar

开源 云原生 Apache Pulsar Apache Pulsar 社区 运维‘

敲重点!这些更新将会影响HarmonyOS原子化服务上架

HarmonyOS开发者

HarmonyOS 原子化服务

Android C++系列:JNI常见问题

轻口味

c++ android 4月月更

三高Mysql - 搭建“三高”架构之扩展与切换

懒时小窝

MySQL MySQL 高可用

netty系列之:netty中的自动解码器ReplayingDecoder

程序那些事

Java Netty 程序那些事 4月月更

超nei卷!连黑客勒索软件团伙都开始谈客户体验…

龙国富

黑客 客户体验 drakside 客户至上

都2022年了,HDFS为何还如此能战

华为云开发者联盟

大数据 hadoop hdfs 分布式文件系统 大数据存储

云效研发效能度量体系,如何展示和解读交付效能数据

阿里云云效

阿里云 运维 研发管理 研发效能 研发团队

13个问题帮你选型 “客户体验管理SaaS平台”

龙国富

SaaS 选型 客户体验 CEM CXM

盘点:阿里云上8款免费的开发者工具

阿里云云效

阿里云 开发者 云原生 开发者工具 研发工具

如何禁用XXE处理?

龙智—DevSecOps解决方案

漏洞扫描 代码安全 漏洞检测

H5营销有什么优势?企业需要定制开发H5吗?

源字节1号

前端开发 后端开发 H5制作

华为云GaussDB(for Influx)揭秘第五期:最佳实践之子查询

华为云开发者联盟

数据库 华为云 GaussDB(for Influx) 子查询 InfluxQL

java培训关闭流方法有顺序吗

@零度

JAVA开发 包装流

不写代码,带你徒手开发一个健康打卡应用

华为云开发者联盟

无代码 AppCube 应用开发 健康打卡 可视化编排

CPUvsGPU:谁才是游戏和视频编辑的核心?

Finovy Cloud

人工智能 gpu cpu

面试官:Redis的事务满足原子性吗?

码农参上

redis 事务 4月月更

消息队列存储消息数据的MySQL表格设计

Geek_36cc7c

大数据培训spark SQL中count(*)和count(1)源码分析

@零度

大数据开发 spark SQL

三高Mysql - 搭建“三高”架构之复制

懒时小窝

MySQL MySQL 高可用

企业知识管理的解决方案

小炮

知识管理 企业知识管理 企业知识管理工具

净推荐值(NPS)完整行动指南

龙国富

客户体验 NPS 净推荐值 北极星指标 客户忠诚度

web前端培训开发者要掌握的CSS 技巧有哪些

@零度

CSS 前端开发

平安普惠荆州分公司:警民齐心,共同抗疫

科技新消息

状态机引擎在vivo营销自动化中的深度实践 | 引擎篇02

vivo互联网技术

服务器 状态机

为什么做开源需要懂异步协作?

腾源会

开源 腾源会

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