应用程序通过 Envoy 代理和 Jaeger 进行分布式追踪 —— Ingress Controller + Http服务 + Grpc服务(三)
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服务(三)的更多相关文章
- ASP.NET Core使用Jaeger实现分布式追踪
前言 最近我们公司的部分.NET Core的项目接入了Jaeger,也算是稍微完善了一下.NET团队的技术栈. 至于为什么选择Jaeger而不是Skywalking,这个问题我只能回答,大佬们说了算. ...
- 总结两种动态代理jdk代理和cglib代理
动态代理 上篇文章讲了什么是代理模式,为什么用代理模式,从静态代理过渡到动态代理. 这里再简单总结一下 什么是代理模式,给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原 ...
- 通过一个工具类更深入理解动态代理和Threadlocal
动态代理和Threadlocal 一个代理类返回指定的接口,将方法调用指定的调用处理程序的代理类的实例.返回的是一个代理类,由指定的类装载器的定义和实现指定接口指定代理实例调用处理程序最近用到一个工具 ...
- 爬虫--requests模块高级(代理和cookie操作)
代理和cookie操作 一.基于requests模块的cookie操作 引言:有些时候,我们在使用爬虫程序去爬取一些用户相关信息的数据(爬取张三“人人网”个人主页数据)时,如果使用之前requests ...
- java的静态代理、jdk动态代理和cglib动态代理
Java的代理就是客户端不再直接和委托类打交道,而是通过一个中间层来访问,这个中间层就是代理.使用代理有两个好处,一是可以隐藏委托类的实现:二是可以实现客户与委托类之间的解耦,在不修改委托类代码的情况 ...
- JAVA高级架构师基础功:Spring中AOP的两种代理方式:动态代理和CGLIB详解
在spring框架中使用了两种代理方式: 1.JDK自带的动态代理. 2.Spring框架自己提供的CGLIB的方式. 这两种也是Spring框架核心AOP的基础. 在详细讲解上述提到的动态代理和CG ...
- AOP的底层实现-CGLIB动态代理和JDK动态代理
AOP是目前Spring框架中的核心之一,在应用中具有非常重要的作用,也是Spring其他组件的基础.它是一种面向切面编程的思想.关于AOP的基础知识,相信多数童鞋都已经了如指掌,我们就略过这部分,来 ...
- JDK动态代理和CGLIB的区别
Aspect默认情况下不用实现接口,但对于目标对象,在默认情况下必须实现接口 如果没有实现接口必须引入CGLIB库 我们可以通过Advice中添加一个JoinPoint参数,这个值会由spring自动 ...
- JDK动态代理和CGLib动态代理简单演示
JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期间创建接口的代理实例. 一.首先我们进行JDK动态代理的演示. 现在我们有一个简单的业务接口Saying,如下: package te ...
- SpringAOP-JDK 动态代理和 CGLIB 代理
在 Spring 中 AOP 代理使用 JDK 动态代理和 CGLIB 代理来实现,默认如果目标对象是接口,则使用 JDK 动态代理,否则使用 CGLIB 来生成代理类. 1.JDK 动态代理 那么接 ...
随机推荐
- Javascript 常见的循环方式总结
本文地址: https://www.cnblogs.com/zichliang/p/17412968.html 在Javascript中有很多种循环方式.有多种循环方式可以用来遍历数组.对象.以及执行 ...
- 【汇编】老师太hun
老师只是随手发实验项目卡,从未提过实验报告的事情 可是 他却要在 复习周 一下子 收6次 实验报告 也不发资料,不说每次的时间点,不讲实验 这人心中有 学生 吗? 上课发 上个班直播的录播 一节课就发 ...
- linux LVM和磁盘配额
目录 一.LVM原理 二.LVM的命令 三.创建lvm过程 四.扩容 五.磁盘配额 一.LVM原理 lvm是逻辑卷管理,可以让用户动态管理磁盘,不用考虑物理磁盘的问题,可以快速扩充磁盘大小,可以不用一 ...
- More than one file was found with OS independent path 'lib/armeabi-v7a/libflutter.so'
今日一个flutter 整合ai到原生android 时老是提示如下错误 Caused by: com.android.builder.merge.DuplicateRelativeFileExcep ...
- git从配置到使用
一 .安装git 1.1 官方地址为:https://git-scm.com/download/win 1.2 双击下载的.exe文件 1.3 直接下一步 1.4 自定义安装目录 1.5 勾选命令行和 ...
- SpringIOC和SpringAOP
作为一个Spring使用者条件: 拥有深入的Spring框架知识和开发经验,能够熟练地运用Spring框架来构建复杂的应用程序. 了解Spring框架的核心概念和设计思想,如控制反转(IoC).依赖注 ...
- 手把手实践丨基于STM32+NBIOT+华为云IOT设计智能井盖
摘要:本文介绍基于STM32微控制器.BC26 NBIOT模组和华为云IOT平台,实现了一款智能井盖系统. 本文分享自华为云社区<基于STM32+NBIOT+华为云IOT设计的智能井盖>, ...
- spark连接mysql数据库
1.安装启动检查Mysql服务.netstat -tunlp (3306) 2.spark 连接mysql驱动程序. –cp /usr/local/hive/lib/mysql-connector-j ...
- 如何在.net6webapi中记录每次接口请求的日志
为什么在软件设计中一定要有日志系统? 在软件设计中日志模块是必不可少的一部分,可以帮助开发人员更好的了解程序的运行情况,提高软件的可靠性,安全性和性能,日志通常能帮我们解决如下问题: 调试和故障排查: ...
- Visual Studio2019如何添加引用
同一解决方案中添加引用 比如我们想在Test项目中添加Queue项目的引用 1.鼠标右击引用-->添加引用 2."引用管理器"-->项目-->解决方案--&g ...

