爲什麼需要Spring Cloud Sleuth
Spring Cloud Seleuth是SpringCloud的一個組件,它的主要功能是在分佈式系統中提供服務鏈路追蹤解決方案。
微服務架構是一個分佈式架構,微服務系統按業務劃分服務單元,一個微服務系統往往有很多個服務單元。由於服務單元數量衆多,業務的複雜性較高,如果出現了錯誤和異常,很難去定位。主要體現在一個請求可能需要調用很多個服務,而內部服務的調用複雜性決定了問題難以定位。所以在微服務架構中,必須實現分佈式鏈路追蹤,去跟進一個請求到底有哪些服務參與,參與的順序又是怎樣的,從而達到每個請求的步驟清晰可見,出了問題能夠快速定位的目的。
Google開源了Dapper 鏈路追蹤組件,並在2010 年發表了論文《Dapper, a Large-ScaleDistributed Systems Tracing Infrastructure)》,這篇論文是業內實現鏈路追蹤的標杆和理論基礎,具有很高的參考價值。
目前,常見的鏈路追蹤組件有Google 的Dapper、Twitter 的Zipkin,以及阿里的Eagleeye(鷹眼)等,它們都是非常優秀的鏈路追蹤開源組件。
基本術語
Spring Cloud Sleuth採用了Google的開源項目Dapper的專業術語。
Span
:基本工作單元,發送一個遠程調度任務就會產生一個Span,Span是用一個64位ID唯一標識的,Trace是用另一個64位ID唯一標識的。Span還包含了其他的信息,例如摘要、時間戳事件、Span的ID以及進行ID。Trace
:由一系列Span組成的,呈樹狀結構。請求一個微服務系統的API接口,這個API接口需要調用多個微服務單元,調用每個微服務單元都會產生一個新的Span,所有由這個請求產生的Span組成了這個Trace。Annotation
:用於記錄一個事件,一些核心註解用於定義一個請求的開始和結束:cs-Client Sent
:客戶端發送一個請求,這個註解描述了Span的開始;sr-Server Received
:服務端獲得請求並準備開始處理它,如果將其sr減去cs時間戳,便可得到網絡傳輸的時間;ss-Server Sent
:服務端發送響應,該註解表明請求處理的完成(當請求返回客戶端),用ss的時間戳減去sr時間戳,便可以得到服務器請求的時間。cr-Client Received
:客戶端接收響應,此時Span結束,如果cr的時間戳減去cs時間戳,便可以得到請求所消耗的時間;
簡單實例
構建Eureka Server
依賴:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
配置:
server:
port: 8761
spring:
application:
name: eureka-server
eureka:
client:
fetch-registry: false
register-with-eureka: false
service-url:
defaultZone: http://localhost:${server.port}/eureka/
啓動類:
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
構建Zipkin Server:
新建一個Module工程,取名爲zipkin-server, 工程的pom文件繼承了主Maven工程的pom文件,並引入Eureka 的起步依賴spring-cloud-starter-eureka、Zipkin Server 的依賴zipkin-server,以及Zipkin Server 的UI界面依賴zipkin-autoconfigure-ui。後兩個依賴提供了Zipkin的功能和Zipkin界面展示的功能,代碼如下:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
</dependency>
</dependencies>
在程序的啓動類ZipkinServiceApplication加上@EnableZipkinServer註解,開啓ZipkinServer 的功能,加上@EnableEurekaClient註解,啓動Eureka Client,代碼如下:
@SpringBootApplication
@EnableEurekaClient
@EnableZipkinServer
public class ZipkinServerApplication {
public static void main(String[] args) {
SpringApplication.run(ZipkinServerApplication.class, args);
}
}
配置:
server:
port: 9411
spring:
application:
name: zipkin-server
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
構建User Service:
在主Maven工程下建一個Module工程,取名爲user-service,作爲服務提供者,對外暴露API接口。
user-service 工程的pom文件繼承了主Maven工程的pom文件,並引入了Eureka的起步依賴spring-cloud-starter-eureka、Web起步依賴spring-boot- starter-web,以及Zipkin的起步起來spring-cloud-starter-zipkin。
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
<version>RELEASE</version>
</dependency>
</dependencies>
在程序的配置文件applicatiom.yml中,指定程序名爲user-service, 端口號爲8762,服務註冊地址http://localhost:8761/eurea/
,Zipkin Server地址爲http://localhost:9411
。spring.sleuth.sampler.percentage爲1.0
, 即以100%的概率將鏈路的數據上傳給Zipkin Server, 在默認情況下,該值爲0.1。配置文件代碼如下:
server:
port: 8762
spring:
application:
name: user-service
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
percentage: 1.0
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
在UserController類建一個"/user/hi"的API接口,對外提供服務:
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/hi")
public String hi() {
return "I'm forezp";
}
}
最後作爲Eureka Client,需要在程序的啓動類UserServiceApplication 加上@EnableEurekaClient註解,開啓Eureka Client的功能。
構建Gateway Service:
新建一個名爲gateway-service的工程,這個工程作爲服務網關,將請求轉發到user-service。作爲Zipkin客戶端,需要將鏈路數據上傳給Zipkin Server,同時它也作爲Eureka Client。在工程的pom文件中除了需要繼承主Maven工程的pom文件,還需引入如下的依賴,代碼清單如下:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
<version>RELEASE</version>
</dependency>
</dependencies>
在工程的配置文件application.yml中,配置程序名爲gateway-service, 端口號爲5000,服務註冊地址爲http://locahost:8761/eureka/
, Zipkin Server 地址爲http://localhost:9411, 以“/user-api/**" 開頭的Uri請求轉發到服務名爲user-service 的服務
,配置代碼如下:
server:
port: 5000
spring:
application:
name: gateway-service
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
percentage: 1.0
zuul:
routes:
api-a:
path: /user-api/**
serviceId: user-service
在程序的啓動類GatewayServiceApplication 上加@EnableEurekaClient 註解,開啓EurekaClient的功能,加上@EnableZuulProxy註解,開啓Zuul代理功能,代碼如下:
@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
public class GatewayServiceApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayServiceApplication.class, args);
}
}
測試:
完整的項目搭建完畢,依次啓動eureka-server.zipkin-serveruser service和gateway-service。在瀏覽器上訪問http:/localhost:5000/user-api/user/hi
,瀏覽器顯示如下:
訪問http://localhost:9411
,即訪問Zipkin的展示界面:
這個界面用於展示Zipkin Server收集的鏈路數據,可以根據服務名、開始時間、結束時間、請求消耗的時間等條件來查找。單擊"Find Tracks"按鈕,從圖中可知請求的調用情況,例如請求的調用時間、消耗時間,以及請求調用的鏈路情況:
單擊“Dependences"按鈕,可以查看服務的依賴關係。在本案例中,gateway-service將請求轉發到了user-service, 這兩個服務的依賴關係如圖: