前言:
在微服务中,各个微服务之间存在着调用关系,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/
然后创建一个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