Sluth-分布式服务跟踪(入门)
随着业务的发展,我们的系统规模也会变得越来越大,各微服务间的调用关系也变得越来越错综复杂。通常一个由客户端发起的请求在后端系统中会经过多个不同的微服务调用来协同产生最后的请求结果,在复杂的微服务架构系统中,几乎每一个前端请求都会形成一条复杂的分布式服务调用链路,在每条链路中任何一个依赖服务出现延迟过高或错误的时候都有可能引起请求最后的失败。这时候对于每个请求全链路调用的跟踪就变得越来越重要,通过实现对请求调用的跟踪可以帮助我们快速的发现错误根源以及监控分析每条请求链路上的性能瓶颈等好处。
针对上面所述的分布式服务跟踪问题,Spring Cloud Sleuth提供了一套完整的解决方案。在本章中,我们将详细介绍如何使用Spring Cloud Sleuth来为我们的微服务架构增加分布式服务跟踪的能力。
本案例一共有4个工程。
- eureka-server:工程作为服务注册中心
- zipkin-server:作为链路追踪服务中心,负载存储链路数据
- zuul-service:作为服务网关工程,负责请求的转发,同时作为链路追踪客户端,负责产生链路数据,并上传给zipkin-server
- user-service:作为服务提供者,对外暴露API,同时作为链路追踪客户端,负责产生链路数据,并上传给zipkin-server
1. 构建eureka-server
配置文件如下所示:
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
instance:
hostname: 127.0.0.1
server:
enable-self-preservation: false
eviction-interval-timer-in-ms: 5000
其它略......
2.构建Zipkin Server
关于 Zipkin 的服务端,在使用 Spring Boot 2.x 版本后,官方就不推荐自行定制编译了,反而是直接提供了编译好的 jar 包来给我们使用,详情请看 upgrade to Spring Boot 2.0 NoClassDefFoundError UndertowEmbeddedServletContainerFactory · Issue #1962 · openzipkin/zipkin · GitHub
并且以前的@EnableZipkinServer
也已经被打上了@Deprecated
If you decide to make a custom server, you accept responsibility for troubleshooting your build or configuration problems, even if such problems are a reaction to a change made by the OpenZipkin maintainers. In other words, custom servers are possible, but not supported.
EnableZipkinServer.javagithub.com/openzipkin/zipkin/blob/master/zipkin-server/src/main/java/zipkin/server/EnableZipkinServer.java
简而言之就是:私自改包,后果自负。
所以官方提供了一键脚本
curl -sSL https://zipkin.io/quickstart.sh | bash -s
java -jar zipkin.jar
如果用 Docker 的话,直接
docker run -d -p 9411:9411 openzipkin/zipkin
任一方式启动后,访问 http://localhost:9411/zipkin/ 就能看到如下界面,嗯还有汉化看起来不错
3.构建 User Servie
user-service作为服务提供者,对外暴露API接口。引入了Eureka的起步依赖spring-cloud-starter-netflix-eureka-client、Web的起步依赖spring-boot-starter-web、以及Zipkin的起步依赖spring-cloud-starter-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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>userservice</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>userservice</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<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-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
在程序的配置文件application.yml中,指定程序名为user-service,端口号为8762,服务注册地址http://localhost:8761/eureka,Zipkin Server地址为http://localhost:9411。spring.sleuth.sampler.probability为1,即以100%的概率将链路的数据上传给Zipkin Server,在默认情况下该值为0.1。配置文件代码如下:
server:
port: 8763
eureka:
client:
serviceUrl:
defaultZone: http://127.0.0.1:8761/eureka/
spring:
application:
name: user-service
sleuth:
sampler:
probability: 1
zipkin:
base-url: http://localhost:9411
在UserController类新建一个“/user/hi”的API接口,对外提供服务,代码如下:
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/hi")
public String hi()
{
return "I am yang";
}
}
4. 构建Zuul Service
新建zuul service工程,这个工程作为服务网关,将请求转发到user-service。作为Zipkin客户端,需要将链路数据上传到Zipkin Server,同时它也作为Eureka Client。在工程的文件中添加相关依赖,代码如下:
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>zuuldemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>zuuldemo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<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-netflix-zuul</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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
在application.yml配置文件添加Eureka、Zuul、Zipkin相关配置信息,代码如下:
server:
port: 8762
eureka:
client:
serviceUrl:
defaultZone: http://127.0.0.1:8761/eureka/
spring:
application:
name: zuul-service
sleuth:
sampler:
probability: 1
zipkin:
base-url: http://localhost:9411
zuul:
routes:
api-a:
path: /user/**
service-id: user-service
在程序的启动类上添加@EnableEurekaClient注解开启Eurek Client和 @EnableZuulProxy注解开启Zuul代理功能,代码如下:
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZuuldemoApplication {
public static void main(String[] args) {
SpringApplication.run(ZuuldemoApplication.class, args);
}
}
项目演示
依次启动eureka-server、zipkin-server、user-service和zuul-service。在浏览器上访问http://127.0.0.1:8762/user/user/hi,浏览器显示:
I am yang
访问http://localhost:9411,即访问Zipkin的展示界面,界面显示如图所示:
选择服务名点击查找后可以知道请求调用情况,例如调用时间、消耗时间,以及请求调用的链路情况。