Spring Cloud版——電影售票系統<八>使用 Spring Sleuth 實現微服務追蹤

 

                GitHub地址:https://github.com/leebingbin/SpringCloud.MovieTicketinghtml

 

1、爲何要實現微服務追蹤

        監控微服務的方式有不少,例如使用 Spring Boot Actuator 監控微服務實例,使用 Hystrix 監控 Hystrix Command 等。談到微服務追蹤,就不得不提一下 Peter Deutsch 的文章 The Eight Fallacies of Distributed Computing ( 分佈式計算的八大誤區 ) , 內容大體以下:java

        · 網絡可靠git

        · 延遲爲零github

        · 帶寬無限spring

        · 網絡絕對安全docker

        · 網絡拓撲不會改變json

        · 必須有一名管理員後端

        · 傳輸成本爲零安全

        · 網絡同質化 (由 Java 之父 Golsing 補充) bash

        不難能夠看出,該文章不少點都在描述一個問題 —— 網絡問題。網絡經常很脆弱,同時, 網絡資源也是有限的。

        微服務之間經過網絡進行通訊。若是可以追蹤每一個請求,瞭解請求通過那些微服務 (從而瞭解信息是如何在服務之間流動),請求耗費時間、網絡延遲、業務邏輯耗費時間等指標,那麼就能更好地分析系統瓶頸、解決系統問題。所以,微服務追蹤頗有必要。

    1.1    Spring Cloud Sleuth 簡介

        Spring Cloud Sleuth 爲 Spring Cloud 提供了分佈式追蹤的解決方案,它大量借用了 Google Dapper 、Twitter Zipkin 和 Apache HTrace 的設計。

        Sleuth 的術語:

        · span(跨度):基本工做單元。span 用一個 64 位的 id 惟一標識。除了ID外,span 還包含其餘數據,例如描述、時間戳事件、鍵值對的註解(標籤),spanID、span父ID等。

        · trace(追蹤):一組共享「root span」 的 span 組成的樹狀結構稱爲 trace 。trace 也用一個 64 位的 ID 惟一標識,trace 中的全部 span 都共享該 trace 的ID 。

        · annotation(標註): annotation 用來記錄事件的存在,其中,核心 annotation 用來定義請求的開始和結束。

        - CS ( Client Sent 客戶端發送 ):客戶端發起一個請求,該 annotation 描述了 span 的開始。

        - SR ( Server Received 服務器端接收 ): 服務器端得到請求並準備處理它。若是用 SR 減去 CS 時間戳,就能獲得網絡延遲。

        - SS ( Server Sent 服務器端發送 ):該 annotation 代表完成請求處理( 當響應發回客戶端時 )。若是用 SS 減去 SR 時間戳,就能獲得服務器端處理請求所需時間。

        - CR( Client Received 客戶端接收):span 結束標識。客戶端成功接收到服務器端的響應。若是 CR 減去 CS 時間戳,就能獲得從客戶端發送請求到服務器響應的所需的時間。

2、整合 Spring Cloud Sleuth 與 ELK 配合使用

        2.1 爲項目添加依賴

# spring-cloud-starter-sleuth

# spring-cloud-starter-sleuth
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-sleuth -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
    <version>1.3.1.RELEASE</version>
</dependency>

# logback

# logback
<!-- https://mvnrepository.com/artifact/net.logstash.logback/logstash-logback-encoder -->
<dependency>
    <groupId>net.logstash.logback</groupId>
    <artifactId>logstash-logback-encoder</artifactId>
    <version>4.11</version>
</dependency>

 

        2.2 新建 logback-spring.yml , 添加如下內容:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <include resource="org/springframework/boot/logging/logback/defaults.xml" />
  ​
  <springProperty scope="context" name="springAppName" source="spring.application.name" />
  <!-- Example for logging into the build folder of your project -->
  <property name="LOG_FILE" value="${BUILD_FOLDER:-build}/${springAppName}" />
  ​
  <property name="CONSOLE_LOG_PATTERN"
    value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr([${springAppName:-},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-B3-ParentSpanId:-},%X{X-Span-Export:-}]){yellow} %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}" />

  <!-- Appender to log to console -->
  <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
      <!-- Minimum logging level to be presented in the console logs -->
      <level>DEBUG</level>
    </filter>
    <encoder>
      <pattern>${CONSOLE_LOG_PATTERN}</pattern>
      <charset>utf8</charset>
    </encoder>
  </appender>

  <!-- Appender to log to file -->
  <appender name="flatfile" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${LOG_FILE}</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.gz</fileNamePattern>
      <maxHistory>7</maxHistory>
    </rollingPolicy>
    <encoder>
      <pattern>${CONSOLE_LOG_PATTERN}</pattern>
      <charset>utf8</charset>
    </encoder>
  </appender>
  ​
  <!-- Appender to log to file in a JSON format -->
  <appender name="logstash" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${LOG_FILE}.json</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>${LOG_FILE}.json.%d{yyyy-MM-dd}.gz</fileNamePattern>
      <maxHistory>7</maxHistory>
    </rollingPolicy>
    <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
      <providers>
        <timestamp>
          <timeZone>UTC</timeZone>
        </timestamp>
        <pattern>
          <pattern>
            {
              "severity": "%level",
              "service": "${springAppName:-}",
              "trace": "%X{X-B3-TraceId:-}",
              "span": "%X{X-B3-SpanId:-}",
              "parent": "%X{X-B3-ParentSpanId:-}",
              "exportable": "%X{X-Span-Export:-}",
              "pid": "${PID:-}",
              "thread": "%thread",
              "class": "%logger{40}",
              "rest": "%message"
            }
          </pattern>
        </pattern>
      </providers>
    </encoder>
  </appender>
  ​
  <root level="INFO">
    <appender-ref ref="console" />
    <appender-ref ref="logstash" />
    <!--<appender-ref ref="flatfile"/> -->
  </root>
</configuration>

        2.3 ELK 搭建

        ELK 的搭建比較簡單,參考官方文檔(或個人博客)便可:

        http://www.elastic.co/guide/index.html        

        

 

        Docker 搭建 ELK:

        http://elk-docker.readthedocs.io/ 

        

        2.4 編寫 Logstash 文件,命名爲 logstash.conf 

        使用 logstash.conf 啓動 Logstash 。Logstash是一款輕量級的日誌蒐集處理框架,能夠方便的把分散的、多樣化的日誌蒐集起來,並進行自定義的處理,而後傳輸到指定的位置,好比某個服務器或者文件。

        官方參考:https://www.elastic.co/products/logstash

        

# logstash.conf

input {
	file {
		codec => json
		path => "/opt/build/*.json"		# 改爲你項目打印的json日誌文件
	}
}
filter {
	grok {
		math => { "message" => "%{TIMESTAMP_ISO08601:timestamp}\s+%{LOGLEVEL:
			severity}\s+\[%{DATA:service},%{DATA:trace},%{DATA:span},%{DATA:exportable}\]\s+%{DATA:pid}---\s+
			\[%{DATA:thread}\]\s+%{DATA:class}\s+:\s+%{GREEDYDATA:rest}" }
	}
}
output {
	elasticsearch {
		hosts => "elasticsearch:9222"	# 改爲你的 Elasticsearch 地址
	}
}

3、Spring Cloud Sleuth 與 Zipkin 配合使用

        1.1 Zipkin 簡介

        Zipkin 是 Twitter 開源的分佈式跟蹤系統,基於 Dapper 的論文設計而來。它的主要功能是收集系統的時序數據,從而追蹤微服務架構的系統延時等問題。Zipkin 還提供了一個很是友好的界面,來幫助分析追蹤數據。

        1.2 Zipkin 官網

            Zipkin 官方網站:https://zipkin.io/

        

        1.3 引入依賴

<dependencies>
    <dependency>
      <groupId>io.zipkin.java</groupId>
      <artifactId>zipkin-autoconfigure-ui</artifactId>
    </dependency>
    <dependency>
      <groupId>io.zipkin.java</groupId>
      <artifactId>zipkin-server</artifactId>
    </dependency>
  </dependencies>

        1.4  編寫啓動類,使用 @EnableZipkinServer 註解,聲明一個 Zipkin Server

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import zipkin.server.EnableZipkinServer;

@SpringBootApplication
@EnableZipkinServer
public class ZipkinServerApplication {
  public static void main(String[] args) {
    SpringApplication.run(ZipkinServerApplication.class, args);
  }
}

4、使用消息中間件收集數據

        上面介紹的使用 HTTP 直接收集跟蹤數據。相比 HTTP 的方式來講,使用消息中間件有如下優勢:

        · 微服務與 Zipkin Server 解耦,微服務無須知道 Zipkin Server 的網絡地址。

        · 一些場景下,Zipkin Server 與微服務網絡可能不通,使用 HTTP 直接收集的方式沒法工做,此時可藉助消息中間件實現數據收集

        1.1 添加依賴

        首先,確定要安裝 RabbitMQ 做爲消息中間件進行演示,RabbitMQ 的安裝能夠參考個人博客或者官方文檔。

<dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-sleuth-zipkin-stream</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-sleuth</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
    </dependency>
    <dependency>
      <groupId>io.zipkin.java</groupId>
      <artifactId>zipkin-autoconfigure-ui</artifactId>
    </dependency>
  </dependencies>

        1.2 修改啓動類註解

        修改啓動類,將註解 @EnableZipkinServer 修改成 @EnableZipkinStreamServer 。而後修改配置文件 application.yml ,添加 rabbitmq 配置。

spring:  
  rabbitmq:
    host: localhost
    port: 6666
    username: guest
    password: guest

5、存儲追蹤數據       

        按照上面的配置,Zipkin Server 是將數據存儲在內存中。這種方式通常不適用於生產環境,由於一旦 Zipkin Server 重啓或發生崩潰,就會致使歷史數據的丟失。

        Zipkin Server 支持多種後端存儲,如 MySQL, Elasticsearch, Cassanda 等。在這塊以如何將數據存儲在 Elasticsearch 中,讓其使用 RabbitMQ 收集跟蹤數據並使用 Elasticsearch 做爲後端存儲。

        1.1 添加依賴

<dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-sleuth-zipkin-stream</artifactId>
    </dependency>
    <dependency>
      <groupId>io.zipkin.java</groupId>
      <artifactId>zipkin-autoconfigure-ui</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
    </dependency>
    <dependency>
      <groupId>io.zipkin.java</groupId>
      <artifactId>zipkin-autoconfigure-storage-elasticsearch-http</artifactId>
      <version>1.16.2</version>
    </dependency>
  </dependencies>

        1.2 修改配置文件 application.yml 

zipkin:
  storage:
    type: elasticsearch
    elasticsearch:
      cluster: elasticsearch
      hosts: http://localhost:9200
      index: zipkin
      index-shards: 5
      index-replicas: 1

        1.3 Elasticsearch 官網

        Elasticsearch 官網:https://www.elastic.co/cn/

        

 

        

 

        參考資料:

        · 分佈式計算的八大誤區原文:https://blogs.oracle.com/jag/resource/Fallacies.html

        · Zipkin 官方網站:https://zipkin.io/

        · 消息隊列-ActiveMQ:http://www.javashuo.com/article/p-swnnoefi-nb.html

        · RabbitMQ 官網 : https://www.rabbitmq.com/ 

        · Elasticsearch 官方文檔:https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html

        · Elasticsearch 官網:https://www.elastic.co/cn/

        · ELK 官方文檔:https://www.elastic.co/guide/index.html

 

 

本文爲博主原創文章,轉載請註明出處!

https://my.oschina.net/u/3375733/blog/

相關文章
相關標籤/搜索