前言:
在微服務中,各個微服務之間存在着調用關系,spring cloud sleuth就是追蹤整條調用鍊的。
一些感念:
-
Span:基本工作單元,例如,在一個建立的span中發送一個RPC等同于發送一個回應請求給RPC,span通過一個64位ID唯一辨別,trace以另一個64位ID表示,span還有其他資料資訊,比如摘要、時間戳事件、關鍵值注釋(tags)、span的ID、以及進度ID(通常是IP位址)
span在不斷的啟動和停止,同時記錄了時間資訊,當你建立了一個span,你必須在未來的某個時刻停止它。
- Trace:一系列spans組成的一個樹狀結構,例如,如果你正在跑一個分布式大資料工程,你可能需要建立一個trace。
- Annotation:用來及時記錄一個事件的存在,一些核心annotations用來定義一個請求的開始和結束
- cs - Client Sent -用戶端發起一個請求,這個annotion描述了這個span的開始
- sr - Server Received -服務端獲得請求并準備開始處理它,如果将其sr減去cs時間戳便可得到網絡延遲
- ss - Server Sent -注解表明請求處理的完成(當請求傳回用戶端),如果ss減去sr時間戳便可得到服務端需要的處理請求時間
- cr - Client Received -表明span的結束,用戶端成功接收到服務端的回複,如果cr減去cs時間戳便可得到用戶端從服務端擷取回複的所有所需時間
代碼:
在springboot2.0,springcloud Finchley版本,不允許自己建zipkin server了,可以用jar包自己跑,也可以直接用docker運作,https://github.com/openzipkin/zipkin#quick-start 位址。
我就用docker了
docker run -d -p 9411:9411 --name zipkin openzipkin/zipkin
啟動後通路 http://192.168.94.151:9411/zipkin/
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5iMyIzN4Y2YyMzY0UjZlZTNzYzX4IjMwQDM1IzLcBTMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
然後建立一個eureka,和兩個有調用關系的微服務
eureka pom.xml
<?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">
<parent>
<artifactId>springcloud16-zipkin</artifactId>
<groupId>com.xhx.springcloud</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>eureka-server</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
application.yml
spring:
application:
name: eureka-server
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false
fetch-registry: false
service-url:
default-zone: http://${eureka.instance.hostname}:${server.port}/eureka
啟動類:
package com.xhx.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* xuhaixing
* 2018/6/16 16:34
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class,args);
}
}
服務提供者 user-service:
pom.xml,增加sleuth和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">
<parent>
<artifactId>springcloud16-zipkin</artifactId>
<groupId>com.xhx.springcloud</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>user-service</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
</dependencies>
</project>
application.yml,base-url指定zipkin的位址
spring:
application:
name: user-service
zipkin:
base-url: http://192.168.94.151:9411
#discovery-client-enabled: true
# service:
#name: zipkin-service
enabled: true
server:
port: 8080
eureka:
client:
service-url:
default-zone: http://locahost:8761/eureka
feign:
hystrix:
enabled: true
啟動類:
package com.xhx.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* xuhaixing
* 2018/6/16 17:04
*/
@SpringCloudApplication
@EnableFeignClients
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class,args);
}
}
提供接口的controller
package com.xhx.springcloud.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* xuhaixing
* 2018/6/16 17:09
*/
@RestController
@RequestMapping(value = "user")
public class UserController {
@RequestMapping(value = "getUserInfo",method = RequestMethod.POST)
public Map<String, String> getUserInfo(){
Map<String,String> user = new HashMap<>();
user.put("name","xuhaixing");
user.put("gender","man");
return user;
}
}
服務消費者
pom.xml和前面一樣加入sleuth和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">
<parent>
<artifactId>springcloud16-zipkin</artifactId>
<groupId>com.xhx.springcloud</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>order-service</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
</dependencies>
</project>
application.yml
probability是被zipkin收集的機率,1為全部收集,因為現在是直接用http方式發送資料并且放在記憶體中,是以會影響性能。可以用消息隊列或者mysql收集服務鍊路資訊。
spring:
application:
name: order-service
zipkin:
#discovery-client-enabled: true
#service:
#name: zipkin-service
enabled: true
base-url: http://192.168.94.151:9411
sleuth:
sampler:
probability: 1
server:
port: 8086
eureka:
client:
service-url:
default-zone: http://locahost:8761/eureka
feign:
hystrix:
enabled: true
feign
package com.xhx.springcloud.api;
import com.alibaba.fastjson.JSONObject;
import com.xhx.springcloud.hystrix.UserInfoApiHytrix;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.Map;
/**
* xuhaixing
* 2018/6/16 17:19
*/
@FeignClient(value = "user-service",path = "user",fallback = UserInfoApiHytrix.class)
public interface UserInfoApi {
@RequestMapping(value = "getUserInfo",method = RequestMethod.POST)
JSONObject getUserInfo();
}
controller
package com.xhx.springcloud.controller;
import com.alibaba.fastjson.JSONObject;
import com.xhx.springcloud.api.UserInfoApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.Optional;
/**
* xuhaixing
* 2018/6/16 17:19
*/
@RestController
@RequestMapping(value = "order")
public class OrderController {
@Autowired
private UserInfoApi userInfoApi;
@RequestMapping(value = "getUserOrder",method = RequestMethod.POST)
public JSONObject getUserOrder(){
JSONObject userInfo = userInfoApi.getUserInfo();
Optional.ofNullable(userInfo).ifPresent(user->user.put("orderMoney",999));
return userInfo;
}
}
hystrix
package com.xhx.springcloud.hystrix;
import com.alibaba.fastjson.JSONObject;
import com.xhx.springcloud.api.UserInfoApi;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* xuhaixing
* 2018/6/16 17:20
*/
@Component
public class UserInfoApiHytrix implements UserInfoApi {
@Override
public JSONObject getUserInfo() {
return null;
}
}
請求一下
打開zipkin