1、概述

  在《应用程序通过 Envoy 代理和 Jaeger 进行分布式追踪(一)》这篇博文中,我们详细介绍了单个应用程序通过 Envoy 和 Jaeger 实现链路追踪的过程。通过这个示例我们知道,Istio 支持通过 Envoy 代理进行分布式追踪,代理会自动为其应用程序生成追踪 span,只需要应用程序转发适当的请求上下文即可。特别是,Istio 依赖于应用程序传播 b3 追踪 Header 以及由 Envoy 生成的请求 ID,即应用程序服务请求时需携带这些 Header。如果请求中没有 B3 HTTP Header,Istio Sidecar 代理(Envoy) 会自动生成初始化的 Headers。

  在《Nginx Ingress Contoller 通过 Envoy 代理和 Jaeger 进行分布式追踪(二)》这篇博文中,进一步扩展链路追踪范围,演示了如何将 Nginx Ingress Controller 与之前提到的应用程序一起使用,从而实现更为复杂的分布式链路追踪。

  在本文将继续扩展链路追踪范围,演示 Nginx Ingress Controller(http协议)——》前端服务(http协议)——》后端服务(http协议)——》告警客户端后端服务 (grpc协议)——》告警服务端后端服务的分布式链路追踪。

  其中 Nginx Ingress Controller 服务和前端服务默认会自动转发请求的上下文信息(Header),后端服务通过少量的代码侵入将原请求的上下文信息(Header)转发给告警客户端后端服务,告警客户端后端服务通过少量的代码侵入将原请求的上下文信息(Grpc Metadata)转发给告警服务端后端服务。

2、示例演示

2.1 环境准备

本文主要目的是讲解分布式链路追踪,因此不再讲解各组件的部署,这些组件部署时都需要注入 Envoy 边车,注入边车后,各组件通过 Envoy 代理和 Jaeger 进行分布式追踪。

2.2 Nginx Ingress Controller(http协议)——》前端服务

Nginx Ingress Controller 的部署本文略,这里只展示下 Nginx Ingress Controller 是如何将服务代理到前端服务的。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: xxxx
nginx.ingress.kubernetes.io/service-upstream: "true"
nginx.ingress.kubernetes.io/upstream-vhost: dashboard.xxxx.svc.cluster.local
name: dashboard-tracing
spec:
rules:
- host: dashboard-tracing.10.20.32.203.nip.io
http:
paths:
- backend:
service:
name: dashboard
port:
number: 80
path: /
pathType: ImplementationSpecific

2.3 前端服务(http协议)——》后端服务

前端服务默认会自动转发请求的上下文信息(Header)信息到后端服务,所以前端服务无需侵入,其他前端相关内容本文不再赘余,我们只需要知道前端服务会自动转发请求的上下文信息即可。

2.4 后端服务(http协议)——》告警客户端后端服务

后端服务需要通过少量的代码侵入将原请求的上下文信息(Header)信息转发给告警客户端后端服务,下面通过侵入源码来分析下是如何将原请求的上下文信息转发给告警客户端后端服务的。

主要是使用 k8s.io/apimachinery 库的 proxy 包,通过 proxy 包的 ServeHTTP 方法作为客户端调用告警客户端后端服务。调用 ServeHTTP 方法时后端服务会将 request 对象作为参数(request对象除了组织告警客户端 Host 信息外,还将前端服务传递过来的 Header 信息放到了request 对象中,此块代码因隐私问题不再粘贴),这样在 ServeHTTP 方法逻辑里面就能获取到前端服务传递过来的上下文信息(Header)了。

......
httpProxy := proxy.NewUpgradeAwareHandler(u, http.DefaultTransport, false, false, &errorResponder{})
httpProxy.ServeHTTP(response, request.Request)

下面看下 ServeHTTP 方法逻辑,可以看到通过调用 utilnet.CloneHeader 方法将前端服务传递过来的上下文信息(Header)传递给告警客户端后端服务。

// 方法包路径: k8s.io/apimachinery@v0.21.7/pkg/util/proxy/upgradeaware.go
// ServeHTTP handles the proxy request
func (h *UpgradeAwareHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
.......
// WithContext creates a shallow clone of the request with the same context.
newReq := req.WithContext(req.Context())
// 主要看这里,新的请求会克隆老请求对象里面的 Header 头信息
newReq.Header = utilnet.CloneHeader(req.Header)
if !h.UseRequestLocation {
newReq.URL = &loc
}
......
proxy.ServeHTTP(w, newReq)
}

2.5 告警客户端后端服务(grpc协议)——》告警服务端后端服务

在2.2-2.4中,都是 http 之间的链路追踪,都是通过 header 传递链路追踪相关的上下文信息,2.5告警客户端后端服务是通过 grpc 协议访问告警服务端后端服务的,但是在 grpc 中怎么传递呢?
grpc 底层采用 http2 协议也是支持传递数据的,采用的是 Metadata,Metadata 对于 gRPC 本身来说透明, 它使得 client 和 server 能为对方提供本次调用的信息。
就像一次 http 请求的 RequestHeader 和 ResponseHeader,http header 的生命周期是一次 http 请求, Metadata 的生命周期则是一次 RPC 调用。

下面来看下告警客户端后端服务是如何将从后端服务转发的上下文信息通过 Metadata 传递给告警服务端后端服务的。

下面以修改查询告警消息列表方法逻辑为例,演示警客户端后端服务如何将从后端服务转发的上下文信息通过 Metadata 传递给告警服务端后端服务,其他方法修改方式和此方法一致。

......
// 传播追踪上下文信息,将后端服务传递过来的上下文信息放置到metadata对象中,通过context传递给告警服务端后端服务
// type MD map[string][]string
httpHeader := metadata.MD(utilnet.CloneHeader(request.Request.Header))
ctx = metadata.NewOutgoingContext(ctx, httpHeader)
......

2.6 客户端在前端服务访问查询告警消息列表功能,然后在 Jaeger UI 查看上报链路信息

客户端在前端服务访问查询告警消息列表功能时,告警客户端后端服务作为 grpc 客户端调用了两次告警服务端后端服务的接口,总共11个 span,envoy 上报链路信息如下:

(1)Nginx Ingress Controller 入站流量劫持 ——》nginx ——》(2)Nginx Ingress Controller 出站流量劫持 ——》(3)前端服务入站劫持 ——》前端服务 ——》(4)前端服务出站劫持 ——》(5)后端服务入站劫持 ——》 后端服务 ——》(6)后端服务出站劫持 ——》(7)告警客户端后端服务入站劫持 ——》告警客户端后端服务 ——》(8)告警客户端后端服务出站劫持 ——》(9)告警服务端后端服务入站劫持 ——》 告警服务端后端服务消息列表方法(回包)——》 告警客户端后端服务 ——》 (10)告警客户端后端服务出站劫持 ——》(11)告警服务端后端服务入站劫持 ——》 告警服务端后端服务消息历史方法(回包)

注意 1:如果访问容器的入站流量不是inbound、或者出站流量不是outbound,请检查对应服务的服务协议是否正确,尤其出站流量是 PassthroughCluster。

这时候可以通过 istioctl pc listener <pod-name>.<pod-namespace> --port 端口命令排查是否没有进行路由匹配。例如以下示例能成功匹配下面路由的话出站流量就为 outbound。

3、总结

  通过《应用程序通过 Envoy 代理和 Jaeger 进行分布式追踪(一)》、《Nginx Ingress Contoller 通过 Envoy 代理和 Jaeger 进行分布式追踪(二)》加上本篇三篇博文,详细解决了应用程序如何通过 Envoy 代理和 Jaeger 进行分布式追踪,最主要的还是这一点:为了将各种追踪 span 整合在一起以获得完整的追踪图,应用程序(不管是http协议、grpc协议、或者是其他Istio支持的能上报链路追踪的服务协议)必须在传入和传出请求之间传播追踪上下文信息

应用程序通过 Envoy 代理和 Jaeger 进行分布式追踪 —— Ingress Controller + Http服务 + Grpc服务(三)的更多相关文章

  1. ASP.NET Core使用Jaeger实现分布式追踪

    前言 最近我们公司的部分.NET Core的项目接入了Jaeger,也算是稍微完善了一下.NET团队的技术栈. 至于为什么选择Jaeger而不是Skywalking,这个问题我只能回答,大佬们说了算. ...

  2. 总结两种动态代理jdk代理和cglib代理

    动态代理 上篇文章讲了什么是代理模式,为什么用代理模式,从静态代理过渡到动态代理. 这里再简单总结一下 什么是代理模式,给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原 ...

  3. 通过一个工具类更深入理解动态代理和Threadlocal

    动态代理和Threadlocal 一个代理类返回指定的接口,将方法调用指定的调用处理程序的代理类的实例.返回的是一个代理类,由指定的类装载器的定义和实现指定接口指定代理实例调用处理程序最近用到一个工具 ...

  4. 爬虫--requests模块高级(代理和cookie操作)

    代理和cookie操作 一.基于requests模块的cookie操作 引言:有些时候,我们在使用爬虫程序去爬取一些用户相关信息的数据(爬取张三“人人网”个人主页数据)时,如果使用之前requests ...

  5. java的静态代理、jdk动态代理和cglib动态代理

    Java的代理就是客户端不再直接和委托类打交道,而是通过一个中间层来访问,这个中间层就是代理.使用代理有两个好处,一是可以隐藏委托类的实现:二是可以实现客户与委托类之间的解耦,在不修改委托类代码的情况 ...

  6. JAVA高级架构师基础功:Spring中AOP的两种代理方式:动态代理和CGLIB详解

    在spring框架中使用了两种代理方式: 1.JDK自带的动态代理. 2.Spring框架自己提供的CGLIB的方式. 这两种也是Spring框架核心AOP的基础. 在详细讲解上述提到的动态代理和CG ...

  7. AOP的底层实现-CGLIB动态代理和JDK动态代理

    AOP是目前Spring框架中的核心之一,在应用中具有非常重要的作用,也是Spring其他组件的基础.它是一种面向切面编程的思想.关于AOP的基础知识,相信多数童鞋都已经了如指掌,我们就略过这部分,来 ...

  8. JDK动态代理和CGLIB的区别

    Aspect默认情况下不用实现接口,但对于目标对象,在默认情况下必须实现接口 如果没有实现接口必须引入CGLIB库 我们可以通过Advice中添加一个JoinPoint参数,这个值会由spring自动 ...

  9. JDK动态代理和CGLib动态代理简单演示

    JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期间创建接口的代理实例. 一.首先我们进行JDK动态代理的演示. 现在我们有一个简单的业务接口Saying,如下: package te ...

  10. SpringAOP-JDK 动态代理和 CGLIB 代理

    在 Spring 中 AOP 代理使用 JDK 动态代理和 CGLIB 代理来实现,默认如果目标对象是接口,则使用 JDK 动态代理,否则使用 CGLIB 来生成代理类. 1.JDK 动态代理 那么接 ...

随机推荐

  1. 机器学习数据顺序随机打乱:Python实现

      本文介绍基于Python语言,实现机器学习.深度学习等模型训练时,数据集打乱的具体操作. 1 为什么要打乱数据集   在机器学习中,如果不进行数据集的打乱,则可能导致模型在训练过程中出现具有&qu ...

  2. Cobalt Strike 连接启动教程(1)

      第一步:把cobaltstrike4(解压后)拷贝到虚拟机Kali系统的root目录下 第二步:进入cobalstrike4文件夹中 第三步:选寻kali系统 IP地址 第四步: 启动服务端:(t ...

  3. 代码随想录算法训练营Day35 贪心算法

    代码随想录算法训练营 代码随想录算法训练营Day35 贪心算法| 860.柠檬水找零 406.根据身高重建队列 452. 用最少数量的箭引爆气球 860.柠檬水找零 题目链接:860.柠檬水找零 在柠 ...

  4. 【Python&RS】遥感影像的像素坐标转地理坐标(仿射变换)

    ​         GDAL(Geospatial Data Abstraction Library)是一个在X/MIT许可协议下的开源栅格空间数据转换库.它利用抽象数据模型来表达所支持的各种文件格式 ...

  5. CKS 考试题整理 (09)-日志审计 log audit

    Task 在cluster中启用审计日志.为此,请启用日志后端,并确保: 日志存储在 /var/log/kubernetes/audit-logs.txt 日志文件能保留 10 天 最多保留 2 个旧 ...

  6. JIRA安装

    JIRA安装 操作系统: 阿里云centos6.8 域名: yan.jzhsc.com 1.安装与配置JAVA sudo -u root -H bash # 在oracle官网下载JDK,安装并配置环 ...

  7. 人工智能政策@🤗: 回应美国国家电信和信息管理局 (NTIA) 关于人工智能问责制的评论请求

    6 月 12 日,Hugging Face 向美国国家电信和信息管理局 NTIA 提交了一份关于 AI 责任政策的信息请求回应.在我们的回应中,我们强调了文档和透明度规范在推动 AI 责任过程中的作用 ...

  8. google colab使用体验

    复现的TRSSL 的代码似乎是python3.8的,在本地跑电脑带不起来,即时把处理图形数改为1 但是colab用3.8不太好下载包, 因此直接上了3.9 除了一些库没有意外,遇到了一点小问题: Ca ...

  9. Unity中的InitializeOnLoad特性:深入解析与实践

    Unity中的InitializeOnLoad特性:深入解析与实践 在Unity开发过程中,我们经常需要在编辑器启动时或脚本重新编译后执行一些操作,例如初始化数据.注册事件等.这时,我们可以使用Ini ...

  10. S32Kxxx bootloader之LIN bootloader

    了解更多关于bootloader 的C语言实现,请加我Q扣: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). 上一次发布博文到如今既 ...