Istio 支持通过 Envoy 代理进行分布式追踪,代理自动为其应用程序生成追踪 span,只需要应用程序转发适当的请求上下文即可。Istio 支持很多追踪系统,包括 Zipkin, Jaeger,Lightstep 和 Datadog,其中 Jaeger 目前已经成为 Istio 默认的分布式追踪工具。在我们的容器云平台中,我们采用了Istio + Jaeger的组合,为应用程序提供了低侵入性的链路追踪功能。本文将重点介绍如何通过Envoy代理和Jaeger实现应用程序的分布式追踪。

1、Envoy 分布式追踪 Jaeger 的实现原理

  Envoy 原生支持 Jaeger,追踪所需 x-b3 开头的 Header 和 x-request-id 在不同的服务之间由业务逻辑进行传递,并由 Envoy 上报给 Jaeger,最终 Jaeger 生成完整的追踪信息。
  为了将各种追踪 span 整合在一起以获得完整的追踪图,应用程序必须在传入和传出请求之间传播追踪上下文信息。特别是,Istio 依赖于应用程序传播 b3 追踪 Header 以及由 Envoy 生成的请求 ID,即应用程序服务请求时需携带这些 Header。这些 Header 包括:

  • x-request-id: 这是一个唯一的请求标识符,用于标识单个请求。它有助于追踪请求,但不涉及分布式跟踪。在Istio中,这通常是由Envoy代理生成的,以便在服务之间传递请求标识。
  • x-b3-traceid: 追踪ID,是一个在整个请求链中唯一的标识符。它用于标识一个请求在分布式系统中的路径。
  • x-b3-spanId: 跨度ID,用于标识单个操作或跨度。每个服务处理请求时都会创建一个新的SpanId。它有助于将请求的不同部分关联起来。
  • x-b3-parentspanid: 父跨度ID,指示当前操作的父操作的SpanId。这有助于构建操作之间的层次关系,以便更好地理解请求的调用链。
  • x-b3-sampled:采样标志,用于指示是否对请求进行采样,以决定是否在分布式跟踪系统中记录该请求的信息。如果采样标志为 "1",则对该请求进行采样,如果为 "0",则不采样。
  • x-b3-flags:标志位,用于标识请求的特定属性。在一些系统中,可能会使用这个标志位来传递额外的信息。

  如果请求中没有 B3 HTTP Header,Istio Sidecar 代理(Envoy) 会自动生成初始化的 Headers。

  在 Istio 中,Envoy 和 Jaeger 的关系如下:

  上图中 Front Envoy 指的是第一个接收到请求的 Envoy Sidecar,它会负责创建 Root Span 并追加到请求 Header 内,请求到达不同的服务时,Envoy Sidecar 会将追踪信息进行上报。

2、应用程序通过 Envoy 代理和 Jaeger 进行分布式追踪

2.1 查看通过 Envoy 代理的应用程序会被自动生成初始化哪些 Headers

  在第一章介绍 Envoy 分布式追踪 Jaeger 的实现原理时,我们知道 Envoy 原生支持 Jaeger,追踪所需 x-b3 开头的 Header 和 x-request-id 在不同的服务之间由业务逻辑进行传递,并由 Envoy 上报给 Jaeger,最终 Jaeger 生成完整的追踪信息。如果请求中没有 B3 HTTP Header,Istio Sidecar 代理(Envoy) 会自动生成初始化的 Headers。在这一小节,我们将看一下通过 Envoy 代理的应用程序会被自动生成初始化哪些 Headers。

(1) 构建个简单镜像能够打印 HTTP 请求信息

以下是一个示例,使用 Go 语言来创建一个简单的 HTTP 服务器,并在其中打印请求信息:

1)创建一个名为 main.go 的 Go 源代码文件,内容如下:

package main

import (
"fmt"
"log"
"net/http"
) func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// 打印请求信息
fmt.Println("Request Method:", r.Method)
fmt.Println("Request URL:", r.URL.String())
fmt.Println("Request Headers:")
for header, value := range r.Header {
fmt.Printf(" %s: %v\n", header, value)
}
fmt.Println("Request Body:", r.Body) // 返回响应
w.WriteHeader(http.StatusOK)
w.Write([]byte("Hello, World!"))
}) log.Fatal(http.ListenAndServe(":80", nil))
}

2)创建一个名为 Dockerfile 的文件,内容如下:

# 使用 Golang 官方的 Golang 镜像作为基础镜像
FROM golang:1.17 # 设置工作目录
WORKDIR /app # 将 main.go 文件复制到容器中的 /app 目录下
COPY ./main.go . # 编译 Go 代码
RUN go build -o http_request_printer main.go # 在容器启动时运行 Go 应用
CMD ["./http_request_printer"]

3)使用以下命令构建 Docker 镜像:

docker build -t http_request_printer .

4)构建完成后,可以使用以下命令运行容器:

docker run -p 8080:80 http_request_printer

注意 1:如果宿主机暴露 18080 端口,不要用谷歌浏览器或者谷歌浏览器里面的 Postman 插件进行测试,因为谷歌浏览器默认会禁用 18080 端口。

5)修改镜像 tag ,将镜像推送到镜像仓库,此步骤比较简单,忽略命令。

6)通过 Postman 测试访问此容器:

7)通过容器日志查看请求信息:

可以看到除了自定义 Header 外,谷歌浏览器里面的 Postman 插件帮我们加了一些 Header 信息,但是可以很明确的看到这些 Header 都和链路追踪没有关系。

(2) 验证通过 Envoy 代理的应用程序会被自动生成初始化哪些 Headers

1)定义 http_request_printer 服务声明式配置文件

# http_request_printer_deploy_svc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: tracing
labels:
version: v1
app: http-request-printer
name: http-request-printer-v1
spec:
replicas: 1
selector:
matchLabels:
version: v1
app: http-request-printer
template:
metadata:
labels:
version: v1
app: http-request-printer
annotations:
cloudbases.io/containerSecrets: '{"container-rr19ea":"harbor"}'
spec:
containers:
- name: container-rr19ea
imagePullPolicy: IfNotPresent
image: '10.20.32.201:80/library/http_request_printer'
ports:
- name: http-80
protocol: TCP
containerPort: 80
servicePort: 80
serviceAccount: default
affinity: {}
initContainers: []
volumes: []
imagePullSecrets:
- name: harbor
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25%
maxSurge: 25%
---
apiVersion: v1
kind: Service
metadata:
namespace: tracing
labels:
version: v1
app: http-request-printer
annotations:
cloudbases.io/serviceType: statelessservice
name: http-request-printer
spec:
sessionAffinity: None
selector:
app: http-request-printer
template:
metadata:
labels:
version: v1
app: http-request-printer
ports:
- name: http-80
protocol: TCP
port: 80
targetPort: 80
type: NodePort

2)在 Kubernetes 集群中部署 http_request_printer 服务

kubectl apply -f http_request_printer_deploy_svc.yaml

3)查看服务访问信息,并通过 Postman 访问此服务

[root@master1 ~]# kubectl get svc -n=tracing
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
http-request-printer NodePort 10.234.131.36 <none> 80:32513/TCP 74s

4)通过容器日志查看请求信息:

可以看到除了自定义 Header 外,谷歌浏览器里面的 Postman 插件帮我们加了一些 Header 信息,但是可以很明确的看到这些 Header 都和链路追踪没有关系。

5)修改应用deployment配置让注入边车

    #修改Pod模板标签,添加边车注入标签 sidecar.istio.io/inject: 'true'
   labels:
app: http-request-printer
sidecar.istio.io/inject: 'true'
version: v1

6)Pod重启后,确定容器已注入边车

7)注入边车后,再通过 Postman 访问此服务

查看容器日志可以看到多了5个和链路追踪相关的 Header 数据。

由此证明,如果请求中没有 B3 HTTP Header,Istio Sidecar 代理(Envoy) 会自动生成初始化的 Headers。

8)可以看到 x-b3-sampled 值为1,代表 Jaeger 会记录该请求的信息

3、总结

  Envoy 原生支持 Jaeger,追踪所需 x-b3 开头的 Header 和 x-request-id 在不同的服务之间由业务逻辑进行传递,并由 Envoy 上报给 Jaeger,最终 Jaeger 生成完整的追踪信息。

 为了将各种追踪 span 整合在一起以获得完整的追踪图,应用程序必须在传入和传出请求之间传播追踪上下文信息。特别是,Istio 依赖于应用程序传播 b3 追踪 Header 以及由 Envoy 生成的请求 ID,即应用程序服务请求时需携带这些 Header。

  如果请求中没有 B3 HTTP Header,Istio Sidecar 代理(Envoy) 会自动生成初始化的 Headers。

参考:分布式追踪

应用程序通过 Envoy 代理和 Jaeger 进行分布式追踪(一)的更多相关文章

  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. 2022-11-10:写一个 bash 脚本以统计一个文本文件 words.txt 中每个单词出现的频率。 为了简单起见,你可以假设: words.txt只包括小写字母和 ‘ ‘ 。 每个单词只由小写

    2022-11-10:写一个 bash 脚本以统计一个文本文件 words.txt 中每个单词出现的频率. 为了简单起见,你可以假设: words.txt只包括小写字母和 ' ' . 每个单词只由小写 ...

  2. 2022-07-12:以下go语言代码输出什么?A:1 1;B:1.0 1.0;C:编译不通过;D:1.0 1。 package main import “fmt“ func main() {

    2022-07-12:以下go语言代码输出什么?A:1 1:B:1.0 1.0:C:编译不通过:D:1.0 1. package main import "fmt" func ma ...

  3. 2022-04-15:给定一个非负数组arr,学生依次坐在0~N-1位置,每个值表示学生的安静值, 如果在i位置安置插班生,那么i位置的安静值变成0,同时任何同学都会被影响到而减少安静值, 同学安静值

    2022-04-15:给定一个非负数组arr,学生依次坐在0~N-1位置,每个值表示学生的安静值, 如果在i位置安置插班生,那么i位置的安静值变成0,同时任何同学都会被影响到而减少安静值, 同学安静值 ...

  4. 【Qt 6】读写剪贴板

    剪贴板是个啥就不用多介绍了,最直观的功能是实现应用程序之间数据共享.就是咱们常说的"复制"."粘贴"功能. 在 Qt 中,QClipboard 类提供了相关 A ...

  5. 【设计模式】使用 go 语言实现简单工厂模式

    最近在看<大话设计模式>,这本书通过对话形式讲解设计模式的使用场景,有兴趣的可以去看一下. 第一篇讲的是简单工厂模式,要求输入两个数和运算符号,得到运行结果. 这个需求不难,难就难在类要怎 ...

  6. 7-2 Broken Pad (20 分)

    1.题目描述: The party began, the greasy uncle was playing cards, the fat otaku was eating, and the littl ...

  7. 如何使用Map处理Dom节点

    本文浅析一下为什么Map(和WeakMap)在处理大量DOM节点时特别有用. 我们在JavaScript中使用了很多普通的.古老的对象来存储键/值数据,它们处理的非常出色: const person ...

  8. nodejs 中 stream.pipe()直接将文件输出到页面乱码

    最近仿照anywhere写个anyentry目录读取器,发现使用stream.pipe()将文件输入到页面时,出现中文乱码 看哇 看到着实不爽,不解决咋能算 于是开始寻找问题根源 一.配置encodi ...

  9. git从配置到使用

    一 .安装git 1.1 官方地址为:https://git-scm.com/download/win 1.2 双击下载的.exe文件 1.3 直接下一步 1.4 自定义安装目录 1.5 勾选命令行和 ...

  10. MySQL之视图,索引,存储过程,触发器--实操

    一.视图 什么是视图? 视图是一个虚拟表,其内容由查询定义. 同真实的表一样,视图包含系列带有名称的列和行数据. 行和列数据来自定义视图的查询所引用的表,并且在引用视图时动态生成. 简单的来说视图是由 ...