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. 献给转java的c#和java程序员的数据库orm框架

    献给转java的c#和java程序员的数据库orm框架 一个好的程序员不应被语言所束缚,正如我现在开源java的orm框架一样,如果您是一位转java的c#程序员,那么这个框架可以带给你起码没有那么差 ...

  2. PHP反序列化常用魔术方法

    PHP反序列化 php序列化(serialize):是将变量转换为可保存或传输的字符串的过程 php反序列化(unserialize):就是在适当的时候把这个字符串再转化成原来的变量使用 PHP反序列 ...

  3. 近期SQL优化实战分享

    分享一下本周SQL优化的两个场景. 如果能对读者有一定的启发,共同探讨,不胜荣幸. 版本信息:mysql,5.7.19 引擎: innodb 场景1 我们有一张常口表,里面的数据由各种数据源合并而来, ...

  4. 【lwip】14-TCP协议分析之TCP协议之可靠传输的实现(TCP干货)

    lwip_14_TCP协议之可靠传输的实现 前言 ‍ 前面章节太长了,不得不分开. 这里已源码为主,默认读者已知晓概念或原理,概念或原理可以参考前面章节,有分析. 参考:李柱明博客:https://w ...

  5. doo 13 之11 :开发之看板视图和用户端 QWeb

    QWeb 是 Odoo 使用的模板引擎,它基于 XML 来生成 HTML 片断和页面.通过 QWeb可生成内容丰富的看板(Kankan)视图.报表和 CMS 网页.本文中我们将学习QWeb 语法以及如 ...

  6. 一分钟学一个 Linux 命令 - pwd

    前言 大家好,我是 god23bin.欢迎大家继续围观<一分钟学一个 Linux 命令>,每天只需一分钟,记住一个 Linux 命令不成问题.本篇文章将聚焦于 pwd 命令,一个超级简单又 ...

  7. ssh,socat端口转发

    ssh隧道 我们将要研究的第一个协议是SSH,因为它已经内置了通过SSH隧道进行端口转发的功能.虽然SSH曾经是与Linux系统相关联的协议,但现在Windows默认安装了OpenSSH客户端,因此您 ...

  8. WPF 入门笔记 - 03 - 样式基础

    程序的本质 - 数据结构 + 算法 本篇为学习李应保老师所著的<WPF专业编程指南>并搭配WPF开发圣经<WPF编程宝典第4版>以及痕迹大佬<WPF入门基础教程系列> ...

  9. 【HarmonyOS】HarmonyOS应用APP与HAP包签名信息查看方法

    ​HarmonyOS可以通过DevEco Studio 构建对应的APP包或者是HAP包,对于签名我们有两种方式: DevEco Studio提供了根据开发者信息生成自动调试签名的能力方便各位开发者进 ...

  10. oracle 19c rpm 个性化配置安装

    简单来说就是: 1.安装preinstall   :    oracle-database-preinstall-19c-1.0-1.el7.x86_64.rpm 2.安装 ee    : oracl ...