⑦SpringCloud 實戰:引入Sleuth組件,完善服務鏈路跟蹤

這是SpringCloud實戰系列中第7篇文章,瞭解前面第兩篇文章更有助於更好理解本文內容:
①SpringCloud 實戰:引入Eureka組件,完善服務治理
②SpringCloud 實戰:引入Feign組件,發起服務間調用
③SpringCloud 實戰:使用 Ribbon 客戶端負載均衡
④SpringCloud 實戰:引入Hystrix組件,分佈式系統容錯
⑤SpringCloud 實戰:引入Zuul組件,開啓網關路由
⑥SpringCloud 實戰:引入gateway組件,開啓網關路由功能html

背景

近年來,隨着微服務架構的流行,不少公司都走上了微服務拆分之路。從而使系統變得愈來愈複雜,本來單體的系統被拆成不少個服務,每一個服務之間經過輕量級的 HTTP 協議進行交互。java

單體架構時,一個請求的調用鏈路很是清晰,通常由負載均衡器,好比 Nginx。將調用方的請求轉發到後端服務,後端服務進行業務處理後返回給調用方。而當架構變成微服務架構時,可能帶來一系列的問題,好比下面三個問題:spring

  1. 接口響應慢,怎麼排查?
  2. 服務間的依賴關係如何查看?
  3. 請求貫穿多個微服務,如何將每一個請求的日誌串起來?

分佈式鏈路跟蹤

分佈式鏈路跟蹤原理在於如何能將請求通過的服務節點都關聯起來。當一個請求從客戶端到達網關後,至關因而第一個入口,這時就須要生成一個惟一的請求 ID,做爲此次請求的標識。從網關到達服務 A 後,確定是須要將請求 ID 傳遞到服務 A 中的,這樣才能將網關到服務 A 的請求關聯起來,依次類推,後面會通過多層服務,都須要將信息一層層傳遞。固然在每一層都須要將數據進行上報、統一存儲、展現等操做。後端

從咱們對這個需求的理解來看,鏈路跟蹤並非很複雜,而複雜的點在於如何實現這一套跟蹤框架,就拿請求信息傳遞這件事來講,服務之間交互,有的用的是 Feign 調用接口,有的用的是 RestTemplate 調用接口,要想將信息傳遞到下游服務,那麼必須得擴展這些調用的框架才能夠。bash

1

核心概念

  • Span服務器

    基本工做單元,例如,發送 RPC 請求是一個新的 Span,發送 HTTP 請求是一個新的 Span,內部方法調用也是一個新的 Span。網絡

  • Trace架構

    一次分佈式調用的鏈路信息,每次調用鏈路信息都會在請求入口處生成一個 TraceId負載均衡

  • Annotation框架

    用於記錄事件的信息。在 Annotation 中會有 CS、SR、SS、CR 這些信息,前面的C表示客戶端,S表示服務器端; 後面的S表示sent,也就是發起請求時的動做,R表示Received,也就是接受到請求時的動做;下面分別介紹下這些信息的做用。

    • CS
      也就是 Client Sent,客戶端發起一個請求,這個 Annotation 表示 Span 的開始。
    • CR
      也就是 Client Received,表示 Span 的結束,客戶端已成功從服務器端收到響應,用 CR 的時間戳減去 CS 的時間戳就能夠知道客戶端從服務器接收響應所需的所有時間。
    • SS
      也就是 Server Sent,在請求處理完成時將響應發送回客戶端,用 SS 的間戳減去 SR 的時間戳會顯示服務器端處理請求所需的時間。
    • SR
      也就是 Server Received,服務器端得到請求並開始處理它,用 SR 的時間戳減去 CS 的時間戳會顯示網絡延遲時間。

請求追蹤過程分解

2

  1. 首先當一個請求訪問 SERVICE1 時,這時是沒有 Trace 和 Span 的,而後會生成 Trace 和 Span,如圖所示生成的 Trace ID 是 X,Span ID 是 A。
  2. 接着 SERVICE1 請求 SERVICE2,這是一次遠程請求,會生成一個新的 Span,Span ID 爲 B,Trace ID 不變仍是 X。Span B 處於 CS 狀態。
  3. 當請求到達 SERVICE2 後,Trade ID 和 Span ID 就被傳遞過來了,這時,SERVICE2 有內部操做,又生成了一個新的 Span,Span ID 爲 C,Trace ID 不變仍是 X。
  4. SERVICE2 處理完後向 SERVICE3 發起請求,同時產生新的 Span,Span ID 爲 D,Span D 處於 CS 狀態,SERVICE3 接收到請求後,Span D 處於 SR 狀態,同時 SERVICE3 內部操做也會產生新的 Span,Span ID 爲 E。
  5. 當 SERVICE3 處理完後,須要將結果響應給調用方,這時 Span D 就處於 SS 的狀態,當 SERVICE2 收到響應後,Span ID 爲 D 的 Span 就是 CR 狀態,表示 Span 已經結束了。

Zipkin 介紹

ZipkinTwitter 的一個開源項目,是一個致力於收集全部服務監控數據的分佈式跟蹤系統,它提供了收集數據和查詢數據兩大接口服務。有了 Zipkin 咱們就能夠很直觀地查看調用鏈,而且可能很方便看出服務之間的調用關係,以及調用耗費的時間。

Zipkin還提供了可插拔數據存儲方式:In-Memory、MySql、Cassandra以及Elasticsearch。測試方即可直接採用In-Memory方式進行存儲,生產推薦使用Elasticsearch。

安裝 Zipkin

若是使用了 Java 8 或者更高的版本,能夠獲取最新的可執行 jar 包來進行啓動。

  1. 下載jar包:

    curl -sSL https://zipkin.io/quickstart.sh | bash -s

    若是下載太慢,能夠直接訪問Maven地址進行下載最新的jar。

    其餘方式安裝,能夠查看官網的quickstart

  2. 啓動服務

    java -jar zipkin.jar
  3. 訪問Zipkin

    成功啓動服務後,訪問http://127.0.0.1:9411/zipkin/便可。

    3

Sleuth 介紹

Spring Cloud Sleuth 是一種分佈式的服務鏈路跟蹤解決方案,經過使用 Spring Cloud Sleuth 可讓咱們快速定位某個服務的問題,以及釐清服務間的依賴關係。

Sleuth 能夠添加鏈路信息到日誌中,這樣的好處是能夠統一將日誌進行收集展現,而且能夠根據鏈路的信息將日誌進行串聯。

Sleuth 中的鏈路數據可直接上報給 Zipkin,在 Zipkin 中就能夠直接查看調用關係和每一個服務的耗時狀況.

Sleuth 中內置了不少框架的埋點,好比:Zuul、Feign、Hystrix、RestTemplate 等。正由於有了這些框架的埋點,鏈路信息才能一直往下傳遞。

經過 Http 結合Zipkin

  1. 在咱們的微服務項目中添加Zipkin依賴

    <dependency> 
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zipkin</artifactId>
    </dependency>
  2. 配置Zipkin地址

    spring.zipkin.base-url=http://127.0.0.1:9411/
  3. 配置採樣比例
    實際使用中可能調用了 10 次接口,可是 Zipkin 中只有一條數據,這是由於收集信息是有必定比例的,Zipkin 中的數據條數與調用接口次數默認比例是 10:1,經過下面的配置來改變這個比例值:

    spring.sleuth.sampler.probability=1.0
  4. 驗證
    啓動咱們的微服務,訪問 http://localhost:9000/eureka-client/sayHello 接口,接口由網關路由到eureka-client 服務,eureka-client 服務再調用eureka-provider服務,接口返回eureka-provider服務的端口等信息。
    而後訪問 http://127.0.0.1:9411/zipkin ,點擊查詢,便可查看到相關訪問記錄
    4

    點擊菜單上面的依賴,能夠查看項目的依賴關係

    5

使用 RabbitMQ or Kafka 代替 HTTP 發送調用鏈數據

數據的發送若是採用 HTTP 對性能仍是有影響的。若是Zipkin 的服務端在重啓或者掛掉時,那麼將丟失部分採集數據。爲了解決這些問題,咱們能夠集成 RabbitMQ 或者Kafka 來發送採集數據,利用消息隊列來提升發送性能,保證數據不丟失;

  1. 若是要使用RabbitMQ或Kafka而不是HTTP,須要引入spring-rabbit or spring-kafka 相關依賴。

    <dependency> 
        <groupId>org.springframework.amqp</groupId>
        <artifactId>spring-rabbit</artifactId>
    </dependency>
  2. 而後在配置文件修改相關配置:

    # WEB、KAFKA、RABBIT、ACTIVEMQ
    spring.zipkin.sender.type=kafka
  3. 刪除以前配置的 spring.zipkin.base-url

  4. 配置kafka、rabbit

自定義 Zipkin 配置

每一個跟蹤系統都須要具備Reporter <Span>Sender,若是要覆蓋提供的bean,則須要給它們指定一個特定的名稱 ZipkinAutoConfiguration.REPORTER_BEAN_NAME and ZipkinAutoConfiguration.SENDER_BEAN_NAME

下面是示例:

@Configuration
protected static class MyConfig {

    @Bean(ZipkinAutoConfiguration.REPORTER_BEAN_NAME)
    Reporter<zipkin2.Span> myReporter() {
        return AsyncReporter.create(mySender());
    }

    @Bean(ZipkinAutoConfiguration.SENDER_BEAN_NAME)
    MySender mySender() {
        return new MySender();
    }

    static class MySender extends Sender {

        private boolean spanSent = false;

        boolean isSpanSent() {
            return this.spanSent;
        }

        @Override
        public Encoding encoding() {
            return Encoding.JSON;
        }

        @Override
        public int messageMaxBytes() {
            return Integer.MAX_VALUE;
        }

        @Override
        public int messageSizeInBytes(List<byte[]> encodedSpans) {
            return encoding().listSizeInBytes(encodedSpans);
        }

        @Override
        public Call<Void> sendSpans(List<byte[]> encodedSpans) {
            this.spanSent = true;
            return Call.create(null);
        }

    }

}
相關文章
相關標籤/搜索