SpringCloud —— Sleuth 分布式请求链路跟踪
文章目录概述为什么会出现这个技术?需要解决哪些问题?什么是 Sleuth ?概述为什么会出现这个技术?需要解决哪些问题?在微服务框架中,一个由客户端发起的请求在后端系统中会经过多个不同的服务节点调用来协同产生最后的请求结果,每一个前端请求会形成一条复杂的分布式服务调用链路,链路中的任何一环节出现高延时或错误都会引起整个请求最后的失败什么是 Sleuth ?SpringCloud Sleuth 提供
前文
SpringCloud —— 服务注册进 Eureka 集群
SpringCloud —— SpringCloud Consul 实现服务注册中心
SpringCloud —— HystrixDashboard 服务监控
文章目录
概述
为什么会出现这个技术?需要解决哪些问题?
在微服务框架中,一个由客户端发起的请求在后端系统中会经过多个不同的服务节点调用来协同产生最后的请求结果,每一个前端请求会形成一条复杂的分布式服务调用链路,链路中的任何一环节出现高延时或错误都会引起整个请求最后的失败
什么是 Sleuth ?
SpringCloud Sleuth 提供了一套完整的服务跟踪的解决方案,在分布式系统中提供追踪解决方案并且兼容支持了 zipkin
搭建链路监控步骤
zipkin
下载
SpringCloud F 版开始已不需要自己构建 Zipkin Server 了,只需要调用 jar 包即可
Zipkin jar 下载地址 https://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/
本文使用的是 2.12.9 版本
运行 jar
这是下载的 jar 包
运行 jar 包非常简单,只需要运行以下命令即可
java -jar zipkin.jar
这图案有点意思啊
运行控制台
运行 jar 之后就可以访问 Zipkin 的控制台了,访问地址 http://localhost:9411/zipkin/
服务提供者
pom.xml 依赖
<dependencies>
<!--包含了sleuth+zipkin-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!--mysql-connector-java-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
application.yml
server:
port: 8001
spring:
application:
name: demo-provider-payment
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
# 采样率值介于 0 到 1 之间,则表示全部采集
probability: 1
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
driver-class-name: com.mysql.jdbc.Driver # MySQL 驱动包
url: jdbc:mysql://localhost:3306/数据库名?useSSL=false
username: 用户名
password: 密码
eureka:
client:
# 表示是否将自己注册进 EurekaServer 默认为 true
register-with-eureka: true
# 是否从 EurekaServer 抓取已有的注册信息,默认为 true,单节点无所谓,集群必须设置为 true 才能配合 Ribbon 使用负载均衡
fetchRegistry: true
service-url:
# 注册地址
# defaultZone: http://localhost:7001/eureka
# 集群版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
instance:
instance-id: payment8001
perfer-ip-address: true
server:
# 关闭自我保护机制,保证不可用服务被及时剔除
enable-self-preservation: false
mybatis:
mapperLocations: classpath:mapper/*.xml
type-aliases-package: com.java.springcloud.entity # 所有 entity 别名类所在包
主要新增以下配置
业务类
package com.java.springcloud.controller;
import com.java.springcloud.entity.CommonResult;
import com.java.springcloud.entity.Payment;
import com.java.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
/**
* @author Woo_home
* @create 2020/3/24 12:11
*/
@RestController
@Slf4j
public class PaymentController {
@Resource
private PaymentService paymentService;
@Resource
private DiscoveryClient discoveryClient;
@Value("${server.port}")
private String serverPort;
private Logger logger = Logger.getLogger("log");
@PostMapping(value = "/payment/create")
public CommonResult create(@RequestBody Payment payment) {
int result = paymentService.create(payment);
logger.info("***** 插入结果 :" + result);
if (result > 0) {
return new CommonResult(200,"插入数据库成功,serverPort: " + serverPort,result);
} else {
return new CommonResult(404,"插入数据失败",null);
}
}
@GetMapping(value = "/payment/get/{id}")
public CommonResult getPaymentById(@PathVariable("id") Long id) {
Payment payment = paymentService.getPaymentById(id);
logger.info("***** 查询结果 :" + payment + " " +serverPort);
// 如果不为 null 表示有数据,查询成功
if (payment != null) {
return new CommonResult(200,"查询成功,serverPort:" + serverPort,payment);
} else {
return new CommonResult(404,"没有对应记录,查询ID:" + id,null);
}
}
@GetMapping(value = "/payment/discovery")
public Object discovery() {
List<String> services = discoveryClient.getServices();
for (String service : services) {
logger.info("******element: " + service);
}
List<ServiceInstance> instances = discoveryClient.getInstances("DEMO-PROVIDER-PAYMENT");
for (ServiceInstance instance : instances) {
logger.info(instance.getServiceId() + "\t" + instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri());
}
return this.discoveryClient;
}
@GetMapping(value = "/payment/lb")
public String getPaymentLB() {
return serverPort;
}
@GetMapping(value = "/payment/feign/timeout")
public String paymentFeignTimeout() {
// 暂停几秒钟线程
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return serverPort;
}
@GetMapping("/payment/zipkin")
public String paymentZipkin() {
return "hi, i am payment zipkin server fall back, welcome to Woo_home 哈哈";
}
}
主要新增以下代码
服务消费者(调用方)
pom.xml 依赖
<dependencies>
<!--包含了sleuth+zipkin-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
application.yml
server:
port: 80
spring:
application:
# 服务名称
name: demo-order-service
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
# 采样率值介于 0 到 1 之间,则表示全部采集
probability: 1
eureka:
client:
# 表示是否将自己注册进 EurekaServer 默认为 true
register-with-eureka: true
# 是否从 EurekaServer 抓取已有的注册信息,默认为 true。单节点无所谓,集群必须设置为 true 才能配合 Ribbon 使用负载均衡
fetch-registry: true
service-url:
# 注册地址
# defaultZone: http://localhost:7001/eureka
# 集群版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
主要新增以下配置
业务类
package com.java.springcloud.controller;
import com.java.springcloud.entity.CommonResult;
import com.java.springcloud.entity.Payment;
import com.java.springcloud.lb.LoadBalancer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.net.URI;
import java.util.List;
/**
* @author Woo_home
* @create 2020/3/24 14:11
*/
@RestController
@Slf4j
public class OrderController {
//public static final String PAYMENT_URL = "http://localhost:8001";
public static final String PAYMENT_URL = "http://DEMO-PROVIDER-PAYMENT";
@Resource
private RestTemplate restTemplate;
@Resource
private DiscoveryClient discoveryClient;
// 引入自定义的负载均衡算法
@Resource
private LoadBalancer loadBalancer;
@GetMapping("/consumer/payment/create")
public CommonResult<Payment> create(Payment payment) {
return restTemplate.postForObject(PAYMENT_URL + "/payment/create",payment,CommonResult.class);
}
@GetMapping("/consumer/payment/get/{id}")
public CommonResult<Payment> getPayment(@PathVariable("id") Long id) {
return restTemplate.getForObject(PAYMENT_URL + "/payment/get/" + id,CommonResult.class);
}
@GetMapping("/consumer/payment/getForEntity/{id}")
public CommonResult<Payment> getPayment2(@PathVariable("id") Long id) {
ResponseEntity<CommonResult> forEntity = restTemplate.getForEntity(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);
if (forEntity.getStatusCode().is2xxSuccessful()) {
return forEntity.getBody();
} else {
return new CommonResult<>(404,"操作失败");
}
}
@GetMapping("/consumer/payment/postForEntity/create")
public CommonResult<Payment> create2(Payment payment) {
return restTemplate.postForEntity(PAYMENT_URL + "/payment/create", payment, CommonResult.class).getBody();
}
@GetMapping(value = "/consumer/payment/lb")
public String getPaymentLB() {
List<ServiceInstance> instances = discoveryClient.getInstances("DEMO-PROVIDER-PAYMENT");
if (instances == null || instances.size() <= 0) {
return null;
}
ServiceInstance serviceInstance = loadBalancer.instances(instances);
URI uri = serviceInstance.getUri();
return restTemplate.getForObject(uri + "/payment/lb",String.class);
}
@GetMapping("/consumer/payment/zipkin")
public String paymentZipkin() {
String result = restTemplate.getForObject("http://localhost:8001" + "/payment/zipkin/", String.class);
return result;
}
}
主要新增以下代码
依次启动 7001/8001/80
依次启动这三个服务
测试
访问 http://localhost/consumer/payment/zipkin
再次刷新 zipkin 控制台的时候,就会出现两个服务名称
选择订单服务点击查找
会显示该服务响应的时长,依赖哪个服务
继续点击该服务进去可以查看该服务调用的链路
还可以查看具体的类、请求方法、地址、路径
点击依赖选项还可以对依赖进行分析
代码已上传至码云 代码下载地址,感兴趣的朋友可以下载运行下
SpringCloud 相关文章阅读
SpringCloud —— 服务注册进 Eureka 集群
SpringCloud —— SpringCloud Consul 实现服务注册中心
更多推荐
所有评论(0)