1. 程式人生 > >【SpringCloud Greenwich版本】第九章鏈路追蹤(Sleuth)

【SpringCloud Greenwich版本】第九章鏈路追蹤(Sleuth)

一、SpringCloud版本

本文介紹的Springboot版本為2.1.1.RELEASE,SpringCloud版本為Greenwich.RC1,JDK版本為1.8,整合環境為IntelliJ IDEA

二、Spring Cloud Sleuth介紹

Spring Cloud Sleuth為Spring Cloud實現分散式跟蹤解決方案。

微服務架構上通過業務來劃分服務的,通過REST呼叫,對外暴露的一個介面,可能需要很多個服務協同才能完成這個介面功能,如果鏈路上任何一個服務出現問題或者網路超時,都會形成導致介面呼叫失敗。隨著業務的不斷擴張,服務之間互相呼叫會越來越複雜,在專案中引入sleuth可以方便程式進行除錯。

sleuth中的一些術語

Spring Cloud Sleuth借用了Dapper的術語。

  • Span:基本工作單元,例如,在一個新建的span中傳送一個RPC等同於傳送一個迴應請求給RPC,span通過一個64位ID唯一標識,trace以另一個64位ID表示,span還有其他資料資訊,比如摘要、時間戳事件、關鍵值註釋(tags)、span的ID、以及進度ID(通常是IP地址)
    span在不斷的啟動和停止,同時記錄了時間資訊,當你建立了一個span,你必須在未來的某個時刻停止它。

通俗點理解Span相當於各個子系統的服務,註冊到Zipkin中,統一管理從而實現各服務之間的鏈路追蹤。也可以理解跟服務註冊中心Eureka類似

  • 跟蹤:一系列spans組成的一個樹狀結構,例如,如果你正在跑一個分散式大資料工程,你可能需要建立一個trace。
  • 註釋:用於及時記錄事件的存在。用於定義請求的開始和停止的一些核心註釋是:
  • cs - Client Sent -客戶端發起一個請求,這個annotion描述了這個span的開始
  • sr - Server Received -服務端獲得請求並準備開始處理它,如果將其sr減去cs時間戳便可得到網路延遲
  • ss - Server Sent -註解表明請求處理的完成(當請求返回客戶端),如果ss減去sr時間戳便可得到服務端需要的處理請求時間
  • cr - Client Received-表明span的結束,客戶端成功接收到服務端的回覆,如果cr減去cs時間戳便可得到客戶端從服務端獲取回覆的所有所需時間

注:本文分三部分搭建
第一步:搭建鏈路追蹤服務端(Zipkin服務端)
第二部:子系統配置鏈路追蹤
第三部:訪問測試

三、建立Sleuth服務

  • 3.1建立Zipkin服務端

建立一個module,取名問cloudzipkin,手動匯入pom檔案,這裡沒有引用父pom檔案

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.jthao</groupId>
    <artifactId>cloudzipkin</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>cloudzipkin</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.RC1</spring-cloud.version>
    </properties>

    <dependencies>

        <!--引入的zipkinServer依賴-->
        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-server</artifactId>
            <version>2.9.4</version>
        </dependency>

        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-autoconfigure-ui</artifactId>
            <version>2.9.4</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>

</project>

啟動類上增加@EnableZipkinServer註解,標識為zipkin服務端

package com.jthao.cloudzipkin;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import zipkin.server.internal.EnableZipkinServer;

@EnableZipkinServer
@SpringBootApplication
public class CloudzipkinApplication {

    public static void main(String[] args) {
        SpringApplication.run(CloudzipkinApplication.class, args);
    }

}

修改配置檔案

server.port=8201
spring.main.allow-bean-definition-overriding=true
management.metrics.web.server.auto-time-requests=false

通過瀏覽器訪問http://localhost:8201/zipkin/,稍後會詳細介紹這個頁面
在這裡插入圖片描述

  • 3.2建立子系統

建立兩個module,取名為servicea和serviceb,選擇Cloud Tracing,再勾選上Zipkin Client,完成
在這裡插入圖片描述建立完成的pom檔案,可以看到spring-cloud-starter-zipkin依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.jthao</groupId>
    <artifactId>servicea</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>servicea</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.RC1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>

</project>

servicea啟動類和配置檔案,埠分別為8202,8203。spring.zipkin.base-url為配置zipkin服務端地址

package com.jthao.servicea;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@SpringBootApplication
public class ServiceaApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceaApplication.class, args);
    }

    @Autowired
    private RestTemplate restTemplate;

    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }

    @RequestMapping("/serviceAInfo")
    public String serviceAInfo() {
        System.out.println("serviceAInfo start");
        return "serviceA  被呼叫了";
    }

    @RequestMapping("/getServiceB")
    public String getServiceB() {
        System.out.println("開始訪問serviceb");
        return restTemplate.getForObject("http://localhost:8203/serviceBInfo", String.class);
    }

}
server.port=8202
spring.application.name=servicea
spring.zipkin.base-url=http://localhost:8201

serviceb啟動類和配置檔案

package com.jthao.serviceb;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@SpringBootApplication
public class ServicebApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServicebApplication.class, args);
    }

    @Autowired
    private RestTemplate restTemplate;

    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }

    @RequestMapping("/serviceBInfo")
    public String serviceBInfo() {
        System.out.println("serviceBInfo  start");
        return "serviceB  被呼叫了";
    }

    @RequestMapping("/getServiceA")
    public String getServiceA() {
        System.out.println("開始訪問servicea");
        return restTemplate.getForObject("http://localhost:8202/serviceAInfo", String.class);
    }

}
server.port=8203
spring.application.name=serviceb
spring.zipkin.base-url=http://localhost:8201

通過瀏覽器分別訪問http://localhost:8202/getServiceBhttp://localhost:8203/getServiceA
在這裡插入圖片描述在這裡插入圖片描述到這,zipkin服務端和兩個子系統鏈路追蹤均已搭建完成

  • 3.3測試

這時我們在看zipkin服務端訪問頁面依賴分析,可以看到servicea和serviceb互相依賴呼叫(這裡只有serviea和serviceb互相呼叫後才可以看到)
在這裡插入圖片描述
查詢呼叫鏈中,可以看到Service name中有兩個子系統的註冊服務,類似於服務註冊中心,Span name可以查到各個服務的所有方法,下面的訪問情況藍色代表網路通暢,紅色代表訪問失敗
在這裡插入圖片描述