随着业务的不断发展,应用系统变得越来越大,逐渐由单体应用发展为分布式应用,这使得应用系统的维护变得越来越困难,原因之一就是微服务的拆分使得服务之间的调用链路变得越来越复杂。例如,一个前端请求到达后端服务时,可能需要调用多个服务才能完成业务处理,而当整个请求变慢甚于不可用时,我们很难知道这是由哪些服务引起的,因此,就需要快速定位并找出导致这种状态的的服务。幸运的是,已经有很多优秀的分布式服务调用跟踪链的解决方案,而最常用的就是Twitter 开源实现是Zipkin。
使用Sleuth + Zipkin实现服务链路跟踪,并通过Zipkin-UI查看服务调用的层次关系以及服务调用的时间等详细信息,方便对Spring Cloud微服务项目的运行情况进行掌握以及服务异常进行定位。
如果想要使用RabbitMQ发送日志消息,并使用ElasticSearch存储日志,请查看笔者的另外一篇文章:
Spring Cloud分布式服务链路追踪实战(Sleuth + Zipkin + RabbitMQ + ElasticSearch)
pom.xml文件如下所示:
<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.0modelVersion>
<groupId>com.cloud.sleuthgroupId>
<artifactId>eurekaartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>eurekaname>
<description>服务注册中心description>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.0.8.RELEASEversion>
<relativePath/>
parent>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
<spring-cloud.version>Finchley.SR2spring-cloud.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
application.yml配置文件如下:
server:
port: 8010
eureka:
instance:
hostname: ${spring.cloud.client.ip-address}
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
spring:
application:
name: eurka
启动类EurekaApplication代码如下所示:
package com.cloud.sleuth.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
pom.xml文件如下所示:
<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.0modelVersion>
<groupId>com.cloud.sleuthgroupId>
<artifactId>zuulartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>zuulname>
<description>网关description>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.0.8.RELEASEversion>
<relativePath/>
parent>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
<spring-cloud.version>Finchley.SR2spring-cloud.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-zuulartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-zipkinartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
application.yml配置文件如下所示:
server:
port: 8020
spring:
application:
name: zuul
sleuth:
web:
client:
enabled: true
sampler:
probability: 1.0 # 将采样比例设置为1.0,也就是全部都需要。默认是0.1
zipkin:
base-url: http://localhost:9411/ # 指定了 Zipkin 服务器的地址
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8010/eureka/
instance:
prefer-ip-address: true
instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}
zuul:
prefix: /api
routes:
order:
path: /provider/order/**
service-id: provider-order
user:
path: /provider/user/**
service-id: provider-user
goods:
path: /provider/goods/**
service-id: provider-goods
启动类ZuulApplication代码如下所示:
package com.cloud.sleuth.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@EnableZuulProxy
@EnableEurekaClient
@SpringBootApplication
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
pom.xml文件如下所示:
<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.0modelVersion>
<groupId>com.cloud.sleuthgroupId>
<artifactId>provider-userartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>provider-username>
<description>用户服务提供者description>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.0.8.RELEASEversion>
<relativePath/>
parent>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
<spring-cloud.version>Finchley.SR2spring-cloud.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-zipkinartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
application.yml配置文件如下所示:
server:
port: 8030
spring:
application:
name: provider-user
sleuth:
web:
client:
enabled: true
sampler:
probability: 1.0 # 将采样比例设置为1.0,也就是全部都需要。默认是0.1
zipkin:
base-url: http://localhost:9411/ # 指定了 Zipkin 服务器的地址
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8010/eureka/
instance:
prefer-ip-address: true
instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}
启动类ProviderUserApplication代码如下所示:
package com.cloud.sleuth.provider.user;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableEurekaClient
@SpringBootApplication
public class ProviderUserApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderUserApplication.class, args);
}
}
UserController类代码如下所示:
package com.cloud.sleuth.provider.user.controlller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@GetMapping(value = "/getUser")
public String getUser() {
String user = "JavaBigData1024";
return user;
}
}
pom.xml文件如下所示:
<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.0modelVersion>
<groupId>com.cloud.sleuthgroupId>
<artifactId>provider-goodsartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>provider-goodsname>
<description>商品服务提供者description>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.0.8.RELEASEversion>
<relativePath/>
parent>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
<spring-cloud.version>Finchley.SR2spring-cloud.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-zipkinartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
application.yml配置文件如下所示:
server:
port: 8040
spring:
application:
name: provider-goods
sleuth:
web:
client:
enabled: true
sampler:
probability: 1.0 # 将采样比例设置为1.0,也就是全部都需要。默认是0.1
zipkin:
base-url: http://localhost:9411/ # 指定了 Zipkin 服务器的地址
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8010/eureka/
instance:
prefer-ip-address: true
instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}
启动类ProviderGoodsApplication代码如下所示:
package com.cloud.sleuth.provider.goods;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableEurekaClient
@SpringBootApplication
public class ProviderGoodsApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderGoodsApplication.class, args);
}
}
GoodsController类代码如下所示:
package com.cloud.sleuth.provider.goods.contoller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GoodsController {
@GetMapping(value = "/getGoods")
public String getGoods() {
String goods = "Think in Java";
return goods;
}
}
pom.xml文件如下所示:
<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.0modelVersion>
<groupId>com.cloud.sleuthgroupId>
<artifactId>provider-orderartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>provider-ordername>
<description>定单服务提供者description>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.0.8.RELEASEversion>
<relativePath/>
parent>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
<spring-cloud.version>Finchley.SR2spring-cloud.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-zipkinartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
application.yml配置文件如下所示:
server:
port: 8050
spring:
application:
name: provider-order
sleuth:
web:
client:
enabled: true
sampler:
probability: 1.0 # 将采样比例设置为1.0,也就是全部都需要。默认是0.1
zipkin:
base-url: http://localhost:9411/ # 指定了 Zipkin 服务器的地址
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8010/eureka/
instance:
prefer-ip-address: true
instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}
启动类ProviderOrderApplication代码如下所示:
package com.cloud.sleuth.provider.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients
@EnableEurekaClient
@SpringBootApplication
public class ProviderOrderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderOrderApplication.class, args);
}
}
OrderController类代码如下所示:
package com.cloud.sleuth.provider.order.controller;
import com.cloud.sleuth.provider.order.service.GoodsService;
import com.cloud.sleuth.provider.order.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OrderController {
@Autowired
private UserService userService;
@Autowired
private GoodsService goodsService;
@GetMapping(value = "/createOrder")
public String createOrder() {
String user = userService.getUser();
String goods = goodsService.getGoods();
String order = "User = " + user + "; Goods = " + goods + ";";
return order;
}
}
UserService类代码如下所示:
package com.cloud.sleuth.provider.order.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient(value = "provider-user")
public interface UserService {
@GetMapping(value = "/getUser")
String getUser();
}
GoodsService类代码如下所示:
package com.cloud.sleuth.provider.order.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient(value = "provider-goods")
public interface GoodsService {
@GetMapping(value = "/getGoods")
String getGoods();
}
curl -sSL https://zipkin.io/quickstart.sh | bash -s #下载Zipkin的jar包到本地
java -jar zipkin.jar #启动Zipkin
至此,一个Sleuth整合Zipkin并基于HTTP进行微服务链路跟踪的完整项目案例就分享完成了,但项目中也还有很多不够完善甚至不够规范的地方,欢迎聪明的Java猿们留言指出。
如果觉得本文对您有帮助,请关注博主的微信公众号,会经常分享一些Java和大数据方面的技术案例!