分佈式鏈路監控與追蹤系統Zipkin

1.分佈式鏈路監控與追蹤產生背景
2.SpringCloud Sleuth + Zipkin
3.分佈式服務追蹤實現原理
4.搭建Zipkin服務追蹤系統
5.搭建Zipkin集成RabbitMQ異步傳輸
6.SpringCloud2.x新知識介紹html

 

分佈式鏈路監控與追蹤產生背景

在微服務系統中,隨着業務的發展,系統會變得愈來愈大,那麼各個服務之間的調用關係也就變得愈來愈複雜。一個 HTTP 請求會調用多個不一樣的微服務來處理返回最後的結果,在這個調用過程當中,可能會由於某個服務出現網絡延遲太高或發送錯誤致使請求失敗,這個時候,對請求調用的監控就顯得尤其重要了。Spring Cloud Sleuth 提供了分佈式服務鏈路監控的解決方案。下面介紹 Spring Cloud Sleuth 整合 Zipkin 的解決方案。java

 

Zipkin框架介紹

Zipkin 是 Twitter 的一個開源項目,它基於 Google Dapper 實現的。咱們可使用它來收集各個服務器上請求鏈路的跟蹤數據,並經過它提供的 REST API 接口來輔助查詢跟蹤數據以實現對分佈式系統的監控程序,從而及時發現系統中出現的延遲太高問題。除了面向開發的 API 接口以外,它還提供了方便的 UI 組件來幫助咱們直觀地搜索跟蹤信息和分析請求鏈路明細,好比能夠查詢某段時間內各用戶請求的處理時間等。web

 

Zipkin 和 Config 結構相似,分爲服務端 Server,客戶端 Client,客戶端就是各個微服務應用。spring

 

微服務中,若是服務與服務之間的依賴關係很是複雜,若是某個服務出現一些問題,很難知道緣由。服務器

 

 

 Spring Cloud提供ZipKin組件網絡

 

SpringCloud Zipkin 與Sleuth
Zipkin 是一個開放源代碼分佈式的跟蹤系統,由Twitter公司開源,它致力於收集服務的定時數據,以解決微服務架構中的延遲問題,包括數據的收集、存儲、查找和展示。
每一個服務向zipkin報告計時數據,例如用戶每次請求服務的處理時間等,可方便的監測系統中存在的瓶頸。
zipkin會根據調用關係經過Zipkin UI生成依賴關係圖。架構

Spring Cloud Sleuth爲服務之間調用提供鏈路追蹤。經過Sleuth能夠很清楚的瞭解到一個服務請求通過了哪些服務,每一個服務處理花費了多長。從而讓咱們能夠很方便的理清各微服務間的調用關係。此外Sleuth能夠幫助咱們:
耗時分析: 經過Sleuth能夠很方便的瞭解到每一個採樣請求的耗時,從而分析出哪些服務調用比較耗時;
可視化錯誤: 對於程序未捕捉的異常,能夠經過集成Zipkin服務界面上看到;
鏈路優化: 對於調用比較頻繁的服務,能夠針對這些服務實施一些優化措施。
Spring Cloud Sleuth能夠結合Zipkin,將信息發送到Zipkin,利用Zipkin的存儲來存儲信息,利用Zipkin Ui來展現數據。app

  

 

搭建Zipkin服務追蹤系統

      

Spring Boot 2.0 版本以後,官方已不推薦本身搭建定製了,而是直接提供了編譯好的 jar 包。詳情能夠查看官網:https://zipkin.io/pages/quickstart.html
注意:zipkin官網已經提供定製了,使用官方jar運行便可。負載均衡

啓動方式:
默認端口號啓動zipkin服務
java –jar zipkin.jar 默認端口號; 9411
訪問地址:http://192.168.18.220:9411框架

指定端口號啓動8080啓動zipkin服務
java -jar zipkin.jar --server.port=8080
訪問地址:http://192.168.18.220:8080

指定訪問rabbitmq 啓動
java -jar zipkin.jar --zipkin.collector.rabbitmq.addresses=127.0.0.1

 

訪問:http://192.168.8.159:9411/zipkin/

 

 默認的值是在內存中  須要設置持久化到內存中哦

 

 案例展現  order  ---> member ---> msg

在Order服務、Member、Msg服務裏面引入:

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

pom:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
    </parent>
    <!-- 管理依賴 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.M7</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <!-- SpringBoot整合Web組件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- SpringBoot整合eureka客戶端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>

    </dependencies>
    <!-- 注意: 這裏必需要添加, 否者各類依賴有問題 -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

yml配置      收集方式有抽樣收集 有所有收集     收集到平臺的ip+端口號

 

 

###會員項目的端口號 server: port: 8000 ###服務別名----服務註冊到註冊中心名稱 spring: application: name: app-toov5-member zipkin: base-url: http://127.0.0.1:9411/ ###所有采集 sleuth: sampler: probability: 1.0 eureka: client: service-url: ##### 當前會員服務註冊到eureka服務地址 defaultZone: http://localhost:8100/eureka ### 須要將個人服務註冊到eureka上 register-with-eureka: true ####須要檢索服務 fetch-registry: true

 

 

底層原理:

   

服務跟蹤原理
爲了實現請求跟蹤,當請求發送到分佈式系統的入口端點時, 只須要服務跟蹤框架爲該請求建立一個惟的跟蹤標識, 同時在分佈式系統內部流轉的時候,框架始終保持傳遞該惟一標識, 直到返回給請求方爲止,這個惟一標識就是前 文中提到的Trace ID。經過Trace ID的記錄,咱們就能將全部請求過程的日誌關聯起來。
爲了統計各處理單元的時間延遲,當請求到達各個服務組件時,或是處理邏輯到達某個狀態時,也經過一個惟一 標識來標記它的開始、 具體過程以及結束,該標識就是前文中提到的Span ID。對於每一個Span來講,它必須有開始和結束兩個節點,經過記錄開始Span和結束Span的時間戳,就能統計出該Span的時間延遲,除了時間戳記錄以外,它還能夠包含一些其餘元數據, 好比事件名稱、請求信息等
SpanId記錄每一次請求, TraceID記錄整個調用鏈全局ID

 

    TraceId 和 SpanId 在微服務中傳遞追蹤

    TraceId記錄每一次請求,耗時時間、接口調用關係

    TraceId和SpanId在微服務中傳遞追蹤

  

    在微服務中,使用請求頭傳遞TraceId和SpanId,一個TraceId由多個SpanId組合起來。獲取到整個微服務調用依賴關係

    

下一級的parentId就是上一級的spanId 造成一個鏈

每次請求生成一個新的spanId

   

在微服務中,使用請求頭傳遞TraceId和SpanId,一個TraceId由多個SpanId組合起來,獲取到整個微服務調用依賴關係。 

 

 

 

案例以下:

 Eureka略

 

 Order:

   controller:

   

import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController public class OrderControler { // RestTemplate 是有SpringBoot Web組件提供 默認整合ribbon負載均衡器 // rest方式底層是採用httpclient技術
 @Autowired private RestTemplate restTemplate; /** * 在SpringCloud 中有兩種方式調用 rest、fegin(SpringCloud) * * @return
     */

    // 訂單服務調用會員服務
    @RequestMapping("/getOrder") public String getOrder() { // 有兩種方式,一種是採用服務別名方式調用,另外一種是直接調用 使用別名去註冊中心上獲取對應的服務調用地址
        String url = "http://app-itmayiedu-member/getMember"; String result = restTemplate.getForObject(url, String.class); System.out.println("訂單服務調用會員服務result:" + result); return result; } @RequestMapping("/orderToMemberMsg") public String orderToMemberMsg(HttpServletRequest request) { System.out.println( "TraceId:" + request.getHeader("X-B3-TraceId") + ",spanid:" + request.getHeader("X-B3-SpanId")); // 有兩種方式,一種是採用服務別名方式調用,另外一種是直接調用 使用別名去註冊中心上獲取對應的服務調用地址
        String url = "http://app-itmayiedu-member/memberAndMsg"; String result = restTemplate.getForObject(url, String.class); System.out.println("訂單服務調用會員服務result:" + result); return result; } }

yml:

  

###訂單服務的端口號 server: port: 8001 ###服務別名----服務註冊到註冊中心名稱 spring: application: name: app-itmayiedu-order zipkin: base-url: http://127.0.0.1:9411/ ###所有采集 sleuth: sampler: probability: 1.0 eureka: client: service-url: ##### 當前會員服務註冊到eureka服務地址 defaultZone: http://localhost:8100/eureka ### 須要將個人服務註冊到eureka上 register-with-eureka: true ####須要檢索服務 fetch-registry: true

 

啓動類:

  

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableEurekaClient public class AppOrder { public static void main(String[] args) { SpringApplication.run(AppOrder.class, args); // 若是使用rest方式以別名方式進行調用依賴ribbon負載均衡器 @LoadBalanced // @LoadBalanced就能讓這個RestTemplate在請求時擁有客戶端負載均衡的能力
 } // 解決RestTemplate 找不到緣由 應該把restTemplate註冊SpringBoot容器中 @bean
 @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } }

 

Member:

  

import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController public class MemberApiController { @Value("${server.port}") private String serverPort; @Autowired private RestTemplate restTemplate; @RequestMapping("/getMember") public String getMember(HttpServletRequest request) { return "this is member,我是會員服務,springcloud2.0版本!端口號:" + serverPort + request.getHeader("X-B3-TraceId") + ",spanid:" + request.getHeader("X-B3-SpanId"); } @RequestMapping("/memberAndMsg") public String sndMsg() { String url = "http://app-itmayiedu-msg/sndMsg"; String result = restTemplate.getForObject(url, String.class); System.out.println("會員服務調用消息服務result:" + result); return result; } }

yml:

 

###會員項目的端口號 server: port: 8000 ###服務別名----服務註冊到註冊中心名稱 spring: application: name: app-toov5-member zipkin: base-url: http://127.0.0.1:9411/ ###所有采集 sleuth: sampler: probability: 1.0 eureka: client: service-url: ##### 當前會員服務註冊到eureka服務地址 defaultZone: http://localhost:8100/eureka ### 須要將個人服務註冊到eureka上 register-with-eureka: true ####須要檢索服務 fetch-registry: true

 

啓動類:

 

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableEurekaClient public class AppMember { // @EnableEurekaClient 將當前服務註冊到eureka上
    public static void main(String[] args) { SpringApplication.run(AppMember.class, args); } // 解決RestTemplate 找不到緣由 應該把restTemplate註冊SpringBoot容器中 @bean
 @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } }

 

Msg

 

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @RestController public class MsgController { @RequestMapping("/sndMsg") public String sndMsg() { try { Thread.sleep(5000); } catch (Exception e) { // TODO: handle exception
 } return "我是消息服務平臺"; } public static void main(String[] args) { SpringApplication.run(MsgController.class, args); } }

啓動類:

 

###訂單服務的端口號 server: port: 8003 ###服務別名----服務註冊到註冊中心名稱 spring: application: name: app-toov5-msg zipkin: base-url: http://127.0.0.1:9411/
 ###所有采集 sleuth: sampler: probability: 1.0 eureka: client: service-url: ##### 當前會員服務註冊到eureka服務地址 defaultZone: http://localhost:8100/eureka
 ### 須要將個人服務註冊到eureka上 register-with-eureka: true ####須要檢索服務 fetch-registry: true

 

 

 

 

 

 Eureka:

 

 訪問: http://127.0.0.1:8001/orderToMemberMsg

 

點擊上面的實際三5.024s

  

相關文章
相關標籤/搜索