Spring Cloud Sleuth + Zipkin 历险记

前言

经过近期的努力,已经为公司初步搭建起了一套基于 springcloud、docker、k8s、gitlab-ci 的微服务结构。虽然可以整条线跑起来了,但是还有很多支撑服务有待完善,今天主要讲一下我是如何通过 Spring Cloud Sleuth + Zipkin 来解决分布式链路跟踪问题的,以及过程中出现的问题。

Spring Cloud Sleuth 简介

Spring Cloud Sleuth 为服务之间调用提供链路追踪。通过Sleuth可以很清楚的了解到一个服务请求经过了哪些服务,每个服务处理花费了多长。从而让我们可以很方便的理清各微服务间的调用关系。

Zipkin 简介

Zipkin 是一个开放源代码分布式的跟踪系统,由 Twitter 公司开源,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集、存储、查找和展现。

每个服务向 Zipkin 报告计时数据,例如用户每次请求服务的处理时间等,可方便的监测系统中存在的瓶颈。

Zipkin 会根据调用关系通过 Zipkin UI 生成依赖关系图。

Spring Cloud Sleuth 与 Zipkin 的关系

Spring Cloud Sleuth 配合 Zipkin,将信息发送到 Zipkin,利用 Zipkin 的存储来存储信息,同时可以利用 Zipkin UI 来展示数据。Spring Cloud Sleuth 与需要进行供链路追踪的系统进行绑定。Spring Cloud 提供了spring-cloud-sleuth-zipkin 来方便集成 zipkin (指的是Zipkin Client,而不是Zipkin服务器),该 jar 包可以通过 spring-cloud-starter-zipkin 依赖来引入。

开始搭建 Zipkin Server

在整个结构中,我理解有这么几种角色:

  • Zipkin Server
    数据收集、存储、查找和展现。
  • 作为 Zipkin Client 的「服务提供者」
    通过 Spring Cloud Sleuth 将请求发送到 Zipkin Server。
  • 「服务调用者」
    向「服务提供者」发起请求。
前提条件

这里首先要说一下,本文中涉及到的所有系统,依赖的软件版本如下:

  • spring-boot:2.1.3.RELEASE
  • spring-cloud:Greenwich.SR1
一、搭建 Zipkin Server

Spring Boot 2.0 之前 Zipkin Server 是需要我们自己创建一个对应的 project 的。而 Spring Boot 2.0 之后,Zipkin 已不再推荐自定义 Zipkin Server 了,官方推荐了以下2种方式来部署 Zipkin Server:

  1. 通过 Jar 包部署
    下载官方提供的可执行 Jar 包,例如:zipkin-server-2.12.9-exec.jar,然后在服务器上运行即可,例如:java -jar zipkin-server-2.12.9-exec.jar。
  2. 通过 image 部署
    通过官方提供的镜像,例如:openzipkin/zipkin,采用 docke r或者 k8s 进行部署。

在前言中已经提到,我的所有服务是通过 k8s 进行部署的,所以,Zipkin Server 也不例外。k8s 环境如何搭建不是本文的重点,所以这里就不进行介绍了,直接说一下 Zipkin Server 所涉及的2个 YAML 文件:

  • annoroad-zipkin-deployment.yaml
    Zipkin Server 将会作为 k8s 的 Deployment 资源投递到 k8s 环境中,代码如下:
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: annoroad-zipkin
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: annoroad-zipkin
  template:
    metadata:
      labels:
        app: annoroad-zipkin
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: annoroad-zipkin
        env:
        - name: DEPLOY_TAG
          value: tag5
        - name: MY_NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        - name: MY_POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: MY_POD_NAMESPACE # 传入当前命名空间
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: MY_POD_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        - name: SERVICE_NAME # 因为pod 通过域名互相访问,需要使用headless服务名称
          value: annoroad-zipkin-service
        - name: STORAGE_TYPE
          value: mysql
        - name: MYSQL_HOST
          value: rm-1azzwo8172t6v014mm.mysql.rds.aliyuncs.com
        - name: MYSQL_USER
          value: user
        - name: MYSQL_PASS
          value: 123321
        - name: MYSQL_DB
          value: annoroad_zipkin_database
        - name: COLLECTOR_PORT
          value: '10400'
        - name: QUERY_PORT
          value: '10401'
        image: registry-vpc.cn-beijing.aliyuncs.com/annoroad-cloud/annoroad-zipkin:latest
        imagePullPolicy: Always #每次都重新拉取镜像
        readinessProbe:
          httpGet:
            path: /health
            port: 10401
          initialDelaySeconds: 30
          timeoutSeconds: 10
        livenessProbe:
          httpGet:
            path: /health
            port: 10401
          initialDelaySeconds: 60
          timeoutSeconds: 10
        ports:
        - name: http
          containerPort: 10400

这里提到的 registry-vpc.cn-beijing.aliyuncs.com/annoroad-cloud/annoroad-zipkin:latest 镜像,其实就是 openzipkin/zipkin 镜像,为了公司内部统一镜像名称我将 openzipkin/zipkin 打成 tag(registry-vpc.cn-beijing.aliyuncs.com/annoroad-cloud/annoroad-zipkin ),过程如下:

  • 拉取 openzipkin/zipkin 镜像
[root@123 /]# docker pull openzipkin/zipkin
  • 打tag
[root@123 /]# docker tag openzipkin/zipkin registry.cn-beijing.aliyuncs.com/annoroad-cloud/annoroad-zipkin
  • 推送到私有镜像仓库
[root@123 /]# docker push registry.cn-beijing.aliyuncs.com/annoroad-cloud/annoroad-zipkin

本文中 zipkin server 通过设置环境变量 STORAGE_TYPE:mysql 来指定存储类型(mysql),默认为缓存存储(STORAGE_TYPE:mem)。zipkin server 还可通过环境变量来获取 mysql 的相关信息,例如:MYSQL_HOST、MYSQL_USER、MYSQL_PASS 等等,所以我们可以根据真实环境来设置这些环境变量。我们还可以通过变量 STORAGE_TYPE 切换不同的存储策略。

这里还有注意两个PORT:

  • COLLECTOR_PORT
    The port to listen for thrift RPC scribe requests. Defaults to 9410
  • QUERY_PORT
    Listen port for the http api and web ui; Defaults to 9411。后边提到的 base_url 使用的是该端口。
  1. annoroad-zipkin-service.yaml
    为 Zipkin Server 创建一个 k8s 对应的 Service 资源,使 Zipkin Server 在 k8s 环境中有一个固定的对外的入口,例如:登录 Zipkin UI 查询等等,代码如下:
apiVersion: v1
kind: Service
metadata:
  name: annoroad-zipkin-service
  labels:
    app: annoroad-zipkin-service
spec:
  ports:
  - name: 4collector
    port: 10400
    protocol: TCP
    targetPort: 10400
  - name: 4query
    port: 10401
    protocol: TCP
    targetPort: 10401
  selector:
    app: annoroad-zipkin
  type: LoadBalancer

YAML 文件已经准备就绪,下面就可以部署 Zipkin Server 了,执行以下命令:

[root@123 /]# kubectl apply -f annoroad-zipkin-deployment.yaml -n test --record
[root@123 /]# kubectl create -f annoroad-zipkin-service.yaml -n test

Zipkin Server 已经部署了,我们如何能看到UI界面呢?首选要获取 Zipkin UI 访问入口,如下:

[root@123 /]# kubectl get svc -n test
NAME                        CLUSTER-IP      EXTERNAL-IP     PORT(S)                        AGE
annoroad-zipkin-service     252.16.10.32    23.6.80.234   10400:31351/TCP,10401:30040/TCP   1d

上边的 23.6.80.234 是一个公网地址,有了这个地址我们就可以访问 Zipkin UI 了。打开浏览器,在地址栏输入 http://23.6.80.234:10401,将会出现如下界面:
在这里插入图片描述
至此,恭喜你,Zipkin Server 已部署完成了!!!!!!!

这里还有一点需要说明的是,上图中的服务名 annoroad-alpha 对应的是 annoroad-alpha 项目中 application.xml 文件中的 spring.application.name,如下图:
在这里插入图片描述
如果未指定该值,则该 project(annoroad-alpha) 在 zipkin 中的服务名为 default。

二、配置 「服务提供者」

这里我以 annoroad-alpha 项目为例,步骤如下:

  1. 在 pom.xml 文件中增加依赖包,如下:
    </dependencies>
        <!-- zipkin 分布式请求跟踪监控 begin -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>
        <!-- zipkin 分布式请求跟踪监控 end -->
    </dependencies>
  1. 在application.yml文件中增加 Sleuth + ZipKin 相关配置,如下:
spring:
  # 调用链 Sleuth + ZipKin
  sleuth:
    sampler:
      # 采用比例,默认 0.1 全部采样 1.0
      probability: 1.0
  zipkin:
    # 指定了 Zipkin 服务器的地址
    base-url: http://annoroad-zipkin-service:10401/

这里的 annoroad-zipkin-service 对应了 k8s 环境中 name 为 annoroad-zipkin-service 的Service,也就是 annoroad-zipkin-service.yaml 定义的 Service。

annoroad-alpha 是如何将请求信息推送给 Zipkin Server 的呢?Zipkin 提供了很多种方式来实现。

本文采用的 http 的方式,也就 annoroad-alpha 通过请求 base-url 将请求 annoroad-alpha 的信息推送给 Zipkin Server。

这里再着重说一下初次配置 base-url 的几点疑惑:

  1. 10401 为 zipkin 的 QUERY_PORT,而不是 COLLECTER_PORT
  2. 对于 base-url,首先会将 base-url(http://annoroad-zipkin-service:10401/) 作为一个注册中心里的一个应用名称从注册中心查找相关服务,如果不存在,也不会报错,base-url 会被当做普通的 ip 地址,或者域名来处理,所以,后台打印如下信息不必理会!!!!!!
2019-09-27 14:27:37.863[INFO ]com.netflix.loadbalancer.BaseLoadBalancer:  197-Client: localhost instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=localhost,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
2019-09-27 14:27:37.871[INFO ]com.netflix.loadbalancer.DynamicServerListLoadBalancer:  222-Using serverListUpdater PollingServerListUpdater
2019-09-27 14:27:37.874[INFO ]com.netflix.loadbalancer.DynamicServerListLoadBalancer:  150-DynamicServerListLoadBalancer for client localhost initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=localhost,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@5161aaf1

三、「服务调用者」

这里说的「服务调用者」就是 Postman,通过 Postman 请求 annoroad-alpha 服务,annoroad-alpha 再通过请求 base-url 将请求信息推送给 Zipkin Server,最终效果如下:
在这里插入图片描述

四、Zipkin UI

这里拿一个实际的调用场景来讲一下 Zipkin UI,调用关系如下:
在这里插入图片描述
如上图,整个调用链是 postman -> annoroad-openapi -> annoroad-alpha -> annoroad-beta,这里 的 annoroad-alpha、annoroad-beta 增加了对 spring-cloud-starter-zipkin 的依赖,也就是说对着两个服务进行了调用链路跟踪。

打开 Zipkin UI,我们可以看到如下界面:
在这里插入图片描述
这里红框中的部分称为“Trace”,TA 是一系列“Span”组成的一个树状结构。我们点开 TA,将会看到如下界面:
在这里插入图片描述
这里 annoroad-alpha 为根 Span,此 Span 中 span id 和 trace id 值相同,两个子 Span 都是 annoroad-beta,一个是请求 /annoroad-beta/hello,另外一个是请求 /annoroad-beta/bizexp。Span 是基本的工作单元,TA 包括一个64位的唯一ID,一个64位 trace 码,描述信息,时间戳事件,key-value ,如下图:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cab5

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值