- 1. Spring Cloud
- 2. 微服务
- 3. Spring Cloud 与 Dubbo 对比
- 4. 服务治理
- 5. Ribbon 负载均衡
- 6. Feign 声明式服务调用
- 7. Hystrix 熔断器
- 网关配置
- 路由配置: 转发规则
- http://localhost:8001/ # 转发路径 服务提供方访问路径">uri: http://localhost:8001/ # 转发路径 服务提供方访问路径
- http://localhost:9000/ # 转发路径 服务提供方访问路径">uri: http://localhost:9000/ # 转发路径 服务提供方访问路径
- username: #如果是私有仓库则需要配置git的账号和密码
- password:
- 10. Bus 消息总线
- 11. Stream 消息驱动
- 12. Sleuth+Zipkin 链路追踪
1. Spring Cloud
Spring Cloud是一系列框架的有序集合
通过 Spring Boot 风格进行再封装屏蔽掉了复杂的配置和实现原理 最终给开发者留出了一套简单易懂 易部署 易维护的分布式系统开发工具包
2. 微服务
微服务它将一个原本独立的系统 拆分成为多个小型服务 并且这些小型服务都可以独立运行 服务之间可以进行通信协作
3. Spring Cloud 与 Dubbo 对比
- Dubbo只是实现了服务治理 而spring cloud子项目分别覆盖了微服务架构下的众多部件
- Dubbo使用 RPC 通信协议 Spring Cloud 使用 RESTful 完成通信 Dubbo 效率略高于 Spring Cloud
4. 服务治理
4.1. Eureka
Eureka 是 Netflix 公司开源的一个服务注册与发现的组件
Eureka 和 其他Netflix 公司的服务组件(如负载均衡 熔断器 网关等) 一起 被spring cloud 社区整合为 Spring-Cloud-Netflix 模块
Eureka 包含 Eueka Server(注册中心) 和 Eureka Client(服务提供者 服务器消费者)
4.1.1. server
引入eureka-server 和 spring web
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
application
server:
port: 8761
# eureka 配置
#1.dashboard :eureka的web控制台配置
#2.server :eureka的服务端配置
#3.client :eureka的客户端配置
#4.instance :eureka的实例配置
eureka:
instance:
hostname: localhost # 主机名
dashboard:
enabled: true # 是否启用web控制台 默认为开启
path: / # 默认路径为/ 访问http://localhost:8761/即可
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka # eureka服务端地址 客户端用于访问服务端的地址
register-with-eureka: false # 是否将自己的路径 注册到eureka上 默认为true 一般情况下只有provider client需要
fetch-registry: false # 是否需要从eureka中抓取路径 默认为true 一般只有consumer client需要
启动类
package com.itheima.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
//启用EurekaServer
@EnableEurekaServer
public class EurekaApp {
public static void main(String[] args) {
SpringApplication.run(EurekaApp.class, args);
}
}
4.1.2. provider
引入 eureka-client 和 spring web
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
application
server:
port: 8000
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://localhost:8761/eureka # eureka服务端地址 客户端用于访问服务端的地址
spring:
application:
name: eureka-provider # 设置当前应用的名称 将来在eureka的web控制台Application显示为该名称 将来需要该名称来获取路径
启动类
package com.itheima.provider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
//标记为 Eureka 客户端 在新版本中自动标记
@EnableEurekaClient
public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class, args);
}
}
并编写对应的dao层 domian对象 service层 controller层
并且能够远程调用获取数据 此时为了在Eureka上注册为应用使其他应用能够远程调用该服务
4.1.3. consumer
引入 eureka-client 和 spring web
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
application
server:
port: 9000
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://localhost:8761/eureka # eureka服务端地址 客户端用于访问服务端的地址
spring:
application:
name: eureka-consumer # 设置当前应用的名称 将来在eureka的web控制台Application显示为该名称 将来需要该名称来获取路径
启动类
package com.itheima.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient //激活DiscoveryClient 新版本可以忽略 自动激活
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class, args);
}
}
RestTemplateConfig类
package com.itheima.consumer.cnfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
controller层
package com.itheima.consumer.controller;
import com.itheima.consumer.domain.Goods;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/goods/{id}")
public Goods findGoodsById(@PathVariable("id") int id) {
/*
远程调用goods服务中的findone接口
使用RestTemplate
1.定义bean
2.注入bean
3.调用方法
*/
/*
动态从 Eureka server 中获取provide 的 ip 和端口
1. 注入 DiscoveryClient 并在启动类注解激活
2. 调用方法
*/
List<ServiceInstance> instances = discoveryClient.getInstances("EUREKA-PROVIDER"); //根据应用名在Eureka服务端中获取应用集合
if (instances == null || instances.size() == 0) { //判断是否为空
return null;
}
ServiceInstance instance = instances.get(0); //此处只有一个所以使用第一个
String host = instance.getHost(); //获取ip
int port = instance.getPort(); //获取端口
System.out.println(host);
System.out.println(port);
String url = "http://" + host + ":" + port + "goods/findOne/" + id;
Goods goods = restTemplate.getForObject(url, Goods.class);
return goods;
}
}
4.1.4. 配置属性
4.1.4.1. instance
eureka:
instance:
hostname: localhost # 主机名
prefer-ip-address: true # 以ip地址形式注册到eureka server中 默认为false 注册为主机名
instance-id: ${eureka.instance.prefer-ip-address}:${spring.application.name}:${server.port} #设置在web控制台中应用id的名称
4.1.1. server
4.1.5. 高可用
每个server都是镜像相同的注册应用 如果其中一个宕机了 另外一个server仍然存活
设置多个eureka server 相互注册
server:
port: 8762
eureka:
instance:
hostname: eureka-server2 # 主机名
dashboard:
enabled: true # 是否启用web控制台 默认为开启
path: / # 默认路径为/ 访问http://localhost:8761/即可
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka # 两个eureka相互注册
register-with-eureka: true # 是否将自己的路径 注册到eureka上 默认为true 一般情况下只有provider client需要
fetch-registry: true # 是否需要从eureka中抓取路径 默认为true 一般只有consumer client需要
spring:
application:
name: eureka-server-ha
在client中在多个server注册应用
server:
port: 8000
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka # eureka服务端地址 客户端用于访问服务端的地址
spring:
application:
name: eureka-provider # 设置当前应用的名称 将来在eureka的web控制台Application显示为该名称 将来需要该名称来获取路径
4.2. Consul
Consul 是 由 HashiCorp 基于 Go 语言开发 支持多数据中心 分布式高可用的服务发布和注册服务软件
这里我们使用windows中的exe执行程序
启动
.\consul agent -dev
打开web管理界面
- 搭建provider 和 Consumer 服务
- 并配置好 RestTemplate 完成远程调用
consul客户端坐标 必须导入actuator组件
<!-- consul-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
不需要在启动类中标价
只需要在application配置好consul属性
provider配置
server:
port: 8000
spring:
cloud:
consul:
host: localhost # consul服务端 ip
port: 8500 # 端口
discovery:
service-name: ${spring.application.name} # 应用名称
prefer-ip-address: true # 以ip注册
application:
name: consul-provider # 应用名称
consumer配置
server:
port: 9000
spring:
cloud:
consul:
host: localhost # consul服务端 ip
port: 8500 # 端口
discovery:
service-name: ${spring.application.name} # 应用名称
prefer-ip-address: true # 以ip注册
application:
name: consul-consumer # 应用名称
consumer的controller层还是一致
package com.itheima.consumer.controller;
import com.itheima.consumer.domain.Goods;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/goods/{id}")
public Goods findGoodsById(@PathVariable("id") int id) {
/*
远程调用goods服务中的findone接口
使用RestTemplate
1.定义bean
2.注入bean
3.调用方法
*/
/*
动态从 Eureka server 中获取provide 的 ip 和端口
1. 注入 DiscoveryClient 并在启动类注解激活
2. 调用方法
*/
List<ServiceInstance> instances = discoveryClient.getInstances("consul-provider"); //根据应用名在Eureka服务端中获取应用集合
if (instances == null || instances.size() == 0) { //判断是否为空
return null;
}
ServiceInstance instance = instances.get(0); //此处只有一个所以使用第一个
String host = instance.getHost(); //获取ip
int port = instance.getPort(); //获取端口
System.out.println(host);
System.out.println(port);
String url = "http://" + host + ":" + port + "goods/findOne/" + id;
Goods goods = restTemplate.getForObject(url, Goods.class);
return goods;
}
}
consumer的controller层还是一致
4.3. Nacos
Nacos 是阿里巴巴的开源项目 专注于服务发现和配置管理微服务
Nacos = Spring Cloud 注册中心 + Spring Cloud配置中心
4.3.1. 启动
在bin目录下 以单机形式运行
启动命令(standalone代表着单机模式运行,非集群模式):
startup.cmd -m standalone
web管理页面
默认用户密码 为nacos
4.3.2. 入门案例
nacos坐标
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>0.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>2.0.3</version>
</dependency>
provider配置
server:
port: 8000
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # 配置nacos服务端地址和端口
application:
name: nacos-provider # 服务名称
consumer配置
server:
port: 9000
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # 配置nacos服务端地址和端口
application:
name: nacos-consumer # 服务名称
consumer启动类
package com.itheima.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class, args);
}
}
5. Ribbon 负载均衡
5.1. 简化ResTemplate调用
之前我们Eureka通过ResTemplate获取一个应用集合, 获取一个应用对象 的 地址 和端口,并拼接成一个url调用服务方的应用 使用Ribbon只需要将ip:端口换成应用名称即可以远程调用 应用
- 在ResTemplate的Bean绑定中加上 @LoadBalanced 注解 ```java package com.itheima.consumer.cnfig;
import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate;
@Configuration public class RestTemplateConfig {
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
2.
将url中的ip:端口 换成应用名称
```java
/*
使用 Ribbon 简化调用
1.在声明restTemplate的Bean时 添加一个@LoadBalanced 注解
2.在使用在声明restTemplate 发请求时 需要定义url时 host:port可以换成 服务端提供的应用名称
*/
@GetMapping("/goods2/{id}")
public Goods findGoodsById2(@PathVariable("id") int id) {
String url = "http://EUREKA-PROVIDER/goods/findOne/" + id;
Goods goods = restTemplate.getForObject(url, Goods.class);
return goods;
}
5.2. 负载均衡
通过在ResTemplate的Bean绑定中加上 @LoadBalanced 注解后,如果当前用于有个多个服务提供方,则Ribbon会自动帮我们负载均衡,默认为轮询策略,策略配置在消费者一端 即客户端负载均衡
5.2.1. 配置类形式配置负载策略
- 定义配置类 使用Bean绑定并返回一个IRule接口的实现类 ```java package com.itheima.consumer.cnfig;
import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Configuration public class MyRule {
@Bean
public IRule rule(){
return new RandomRule();
}
}
2.
在启动类中 使用[@RibbonClient ](/RibbonClient ) 定义应用名称和配置类
```java
package com.itheima.consumer;
import com.itheima.consumer.cnfig.MyRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient //激活DiscoveryClient 新版本可以忽略 自动激活
/*
配置Ribbon 负载均衡策略
name :设置服务提供方的 应用名称
configuration : 设置负载均衡的Bean
*/
@RibbonClient(name ="EUREKA-PROVIDER",configuration = MyRule.class)
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class, args);
}
}
5.2.2. 配置方式设置
在application中设置该属性
EUREKA-PROVIDER: # 应用名称
ribbon:
NFloadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡策略实现类的引用路径
6. Feign 声明式服务调用
Feign 是一个声明式的REST客户端 它基于接口的注解方式 很方便实现客户端配置
- 在消费者端导入坐标
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 消费者启动类中加上 @EnableFeignClients 启用Feign ```java package com.itheima.consumer;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableDiscoveryClient // 激活DiscoveryClient @EnableEurekaClient @SpringBootApplication
@EnableFeignClients //开启Feign的功能 public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
}
3.
在消费者中定义一个feign声明接口
```java
package com.itheima.consumer.feign;
import com.itheima.consumer.domain.Goods;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* feign声明式接口 发起远程调用的
* 1.定义接口
* 2.接口上添加 @FeignClient value属性为 应用名称
* 3.编写调用接口 接口的声明规则 和 提供方接口保持一致
* 4.注入该接口对象 调用接口方法完成远程调用
*/
@FeignClient(value = "feign-provider")
public interface GoodsFeignClient {
@GetMapping("/goods/findOne/{id}")
Goods findGoodsById(@PathVariable("id") int id);
}
- 注入 声明接口对象 调用接口方法 ```java package com.itheima.consumer.controller;
import com.itheima.consumer.domain.Goods; import com.itheima.consumer.feign.GoodsFeignClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate;
@RestController @RequestMapping(“/order”) public class OrderController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private GoodsFeignClient goodsFeignClient;
@GetMapping("/goods/{id}")
public Goods findGoodsById(@PathVariable("id") int id){
/*String url = "http://FEIGN-PROVIDER/goods/findOne/"+id;
// 3. 调用方法
Goods goods = restTemplate.getForObject(url, Goods.class);*/
Goods goods = goodsFeignClient.findGoodsById(id);
return goods;
}
}
<a name="3e58adf8"></a>
## 6.1. 超时设置
Feign 底层依赖于 Ribbon 实现负载均衡和远程调用
Ribbon默认1秒超时
在consumer的配置文件中配置
```yaml
ribbon:
ConnectTimeout: 1000 # 设置连接超时时间 默认为1000毫秒
ReadTimeout: 3000 # 逻辑处理的超时时间 默认为1000毫秒
6.2. 日志记录
Feign 只能记录 debug 级别的日志信息
- 设置consumer的日志级别 为该路径下所有的类为debug级别
logging:
level:
com.itheima: debug # 键位类路径
- 在consumer中定义配置类 ```java package com.itheima.consumer.config;
import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Configuration public class FeignLogConfig {
@Bean
public Logger.Level level(){
/**
* NONE 不记录
* BASIC 记录基本的请求行 响应状态码数据
* HEADERS 记录基本的请求行 响应状态码数据 响应头信息
* FULL 记录完整的信息
*/
return Logger.Level.FULL;
}
}
3.
在声明式接口中的@FeignClient注解 引入配置类
```java
package com.itheima.consumer.feign;
import com.itheima.consumer.config.FeignLogConfig;
import com.itheima.consumer.domain.Goods;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* feign声明式接口 发起远程调用的
* 1.定义接口
* 2.接口上添加 @FeignClient value属性为 应用名称 configuration 为日志配置类
* 3.编写调用接口 接口的声明规则 和 提供方接口保持一致
* 4.注入该接口对象 调用接口方法完成远程调用
*/
@FeignClient(value = "feign-provider",configuration = FeignLogConfig.class)
public interface GoodsFeignClient {
@GetMapping("/goods/findOne/{id}")
Goods findGoodsById(@PathVariable("id") int id);
}
7. Hystrix 熔断器
Hystrix 是Netflix 开源的一个延迟和容错库 用于隔离访问远程服务 第三方库 防止出现级联失败(雪崩)
雪崩: 一个服务失败 导致整条链路的服务都失败的情况
隔离
- 线程池隔离 默认值
- 信号量隔离
- 降级
- 熔断
- 限流
7.1. 服务方降级
当服务发生异常或调用超时,返回默认数据
- 在服务方导入坐标
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
- 在服务方启动类中加上@EnableCircuitBreaker注解 ```java package com.itheima.provider;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
- 启动类 */
@EnableEurekaClient //该注解 在新版本中可以省略 @SpringBootApplication
@EnableCircuitBreaker //开启Hystrix功能 public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class,args);
}
}
3.
在服务方controller层 中定降级方法(降级方法需要与原方法参数返回值一致),并且在原方法中加上注解[@HystrixCommand(fallbackMethod ](/HystrixCommand(fallbackMethod ) = "降级方法名")
```java
/**
*降级
*1.出现异常
* 2.服务调用超时
*/
@GetMapping("/findOne/{id}")
@HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
//设置Hystrix的超时时间默认为1000毫秒
@HystrixProperty(name = "execution.isolation.thread.interruptOnTimeout",value = "3000")
}) //指定降级后调用的方法 commandProperties为设置指定规则
public Goods findOne(@PathVariable("id") int id){
Goods goods = goodsService.findOne(id);
goods.setTitle(goods.getTitle() + ":" + port);//将端口号,设置到了 商品标题上
return goods;
}
/**
* 定义降级方法
* 1. 方法的返回值和参数要与原方法一致
*/
public Goods findOne_fallback(@PathVariable("id") int id){
Goods goods = new Goods();
goods.setTitle("降级了");
return goods;
}
7.2. 消费方降级
Feign已经提供了Hystrix 无需导入 Hystrix 坐标
- 在消费方配置文件中开启Hystrix
feign:
hystrix:
enabled: true
# 开启 feign对hystrix的支持 默认为false
- 定义声明式接口的实现类 ```java package com.itheima.consumer.feign;
import com.itheima.consumer.domain.Goods; import org.springframework.stereotype.Component; /* 降级处理类 1.定义类实现feign客户端接口 2.使用@Component注解 加入IOC容器中
*/ @Component public class GoodsFeignClientFallback implements GoodsFeignClient{ @Override public Goods findGoodsById(int id) { Goods goods = new Goods(); goods.setTitle(“降级了”); return goods; } }
3.
在声明式接口@FeignClient注解 设置fallback属性为降级类的字节码
```java
package com.itheima.consumer.feign;
import com.itheima.consumer.domain.Goods;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value = "HYSTRIX-PROVIDER",fallback = GoodsFeignClientFallback.class)
public interface GoodsFeignClient {
@GetMapping("/goods/findOne/{id}")
public Goods findGoodsById(@PathVariable("id") int id);
}
7.3. 熔断机制
当降级的情况情况达到预定的阈值(默认为5秒20次),则会打开断路器,拒绝所有请求,直到服务恢复正常为止
@HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
//设置Hystrix的超时时间默认为1000毫秒
@HystrixProperty(name = "execution.isolation.thread.interruptOnTimeout",value = "3000"),
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "5000"), //监控时间 默认为5000毫秒
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "20"), //失败次数 默认20次
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50"), //失败率 默认为百分之50
}) //指定降级后调用的方法 commandProperties为设置指定规则
7.4. Turbine 熔断监控
Hystrix 提供了 Hystrix-dashboard功能 用于实时监控微服务运行状态 Hystrix-dashboard 只能监控一个微服务
Netflix 提供了Turbine 进行聚合监控
新建模块并导入坐标 ```xml
org.springframework.cloud spring-cloud-starter-netflix-hystrix-dashboard org.springframework.cloud spring-cloud-starter-netflix-turbine org.springframework.boot spring-boot-starter-actuator org.springframework.cloud spring-cloud-starter-netflix-eureka-client org.springframework.boot spring-boot-starter-test test
2.
创建application.yml
```yaml
spring:
application.name: hystrix-monitor
server:
port: 8769
turbine:
combine-host-port: true
# 配置需要监控的服务名称列表
app-config: hystrix-provider,hystrix-consumer
cluster-name-expression: "'default'"
aggregator:
cluster-config: default
#instanceUrlSuffix: /actuator/hystrix.stream
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
- 创建启动类 ```java package com.itheima;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; import org.springframework.cloud.netflix.turbine.EnableTurbine;
@SpringBootApplication @EnableEurekaClient
@EnableTurbine //开启Turbine 很聚合监控功能 @EnableHystrixDashboard //开启Hystrix仪表盘监控功能 public class HystrixMonitorApp {
public static void main(String[] args) {
SpringApplication.run(HystrixMonitorApp.class, args);
}
}
4.
修改被监控的模块 需要分别修改 hystrix-provider 和 hystrix-consumer 模块
1.
导入坐标
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</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-netflix-hystrix-dashboard</artifactId>
</dependency>
- 配置Bean
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/actuator/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
- 在启动类上添加注解@EnableHystrixDashboard ```java package com.itheima.provider;
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; import org.springframework.context.annotation.Bean;
/**
- 启动类 */
@EnableEurekaClient //该注解 在新版本中可以省略 @SpringBootApplication
@EnableCircuitBreaker //开启Hystrix功能 @EnableHystrixDashboard public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class, args);
}
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/actuator/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
5.
启动服务
- eureka-server
- hystrix-provider
- hystrix-consumer
- hystrix-monitor
6.
访问 [http://localhost:8769/hystrix/](http://localhost:8769/hystrix/)
<br />监控Url地址为 [http://localhost:8769/turbine.stream](http://localhost:8769/turbine.stream)
<br />记得访问一次 接口否则没有数据
![](https://cdn.jsdelivr.net/gh/Iekrwh/images/md-images/image-20211003161914781.png#alt=image-20211003161914781)
<a name="04fe42f9"></a>
# 8. Gateway 网关
网关是为微服务架构提供一种简单而有效的统一的API路由管理方式
<a name="a7f91198"></a>
## 8.1. 入门案例
1.
创建gateway模块 导入坐标
```xml
<dependencies>
<!--引入gateway 网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
- 创建启动类 ```java package com.itheima.gateway;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication @EnableEurekaClient public class ApiGatewayApp { public static void main(String[] args) { SpringApplication.run(ApiGatewayApp.class, args); } }
3.
编写application.yml
```yml
server:
port: 80
spring:
application:
name: api-geteway-server
cloud:
# 网关配置
gateway:
# 路由配置: 转发规则
routes: # 集合
- id: gateway-provider # 唯一标识 默认为随机UUID
uri: http://localhost:8001/ # 转发路径 服务提供方访问路径
predicates: # 条件 用于请求网关路径的匹配规则
- Path=/goods/**
- 启动模块和服务治理 服务提供方 消费方 只要访问http://localhost:80/goods/* 地址则转发为
8.2. 静态路由
通过routes转发规则 配置多个集合对象
server:
port: 80
spring:
application:
name: api-geteway-server
cloud:
# 网关配置
gateway:
# 路由配置: 转发规则
routes: # 集合
- id: gateway-provider # 唯一标识 默认为随机UUID
uri: http://localhost:8001/ # 转发路径 服务提供方访问路径
predicates: # 条件 用于请求网关路径的匹配规则
- Path=/goods/**
- id: gateway-consumer # 转发规则2
uri: http://localhost:9000/ # 转发路径 服务提供方访问路径
predicates: # 条件 用于请求网关路径的匹配规则
- Path=/order/**
但不推荐此方法配置
8.3. 动态路由
从eureka 动态获取
引入eureka client 并在启动类中加上@EnableEurekaClient注解
配置eureka服务地址 并将Gateway的uri 改成 lb://应用名称 ```yaml server: port: 80 spring: application: name: api-geteway-server cloud:
网关配置
gateway:
路由配置: 转发规则
routes: # 集合
id: gateway-provider # 唯一标识 默认为随机UUID
uri: http://localhost:8001/ # 转发路径 服务提供方访问路径
uri: lb://gateway-provider predicates: # 条件 用于请求网关路径的匹配规则
- Path=/goods/**
id: gateway-consumer # 转发规则2
uri: http://localhost:9000/ # 转发路径 服务提供方访问路径
uri: lb://gateway-consumer predicates: # 条件 用于请求网关路径的匹配规则
- Path=/order/**
eureka: client: service-url: defaultZone: http://localhost:8761/eureka
<a name="63755a99"></a>
## 8.4. 微服务名称配置
Gateway网关中 默认不启用由Eureka应用名拼接的URL转发访问
我们通过 sping.cloud.discovery.locator.enabled 开启之后
可以通过 [http://localhost/gateway-consumer/order/goods/2](http://localhost/gateway-consumer/order/goods/2) 来转发访问 方便我们更好的区分应用 当然http://localhost/order/goods/2 不加应用名称拼接也是可以转发访问
```yml
server:
port: 80
spring:
application:
name: api-geteway-server
cloud:
# 网关配置
gateway:
# 路由配置: 转发规则
routes: # 集合
- id: gateway-provider # 唯一标识 默认为随机UUID
# uri: http://localhost:8001/ # 转发路径 服务提供方访问路径
uri: lb://gateway-provider
predicates: # 条件 用于请求网关路径的匹配规则
- Path=/goods/**
- id: gateway-consumer # 转发规则2
# uri: http://localhost:9000/ # 转发路径 服务提供方访问路径
uri: lb://gateway-consumer
predicates: # 条件 用于请求网关路径的匹配规则
- Path=/order/**
discovery:
locator:
enabled: true # 开启微服务发现功能
lower-case-service-id: true # 请求路径上的应用名称允许小写
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
8.5. 网关过滤器
过滤器 对请求或响应进行拦截 完成一些通用操作
Gateway 提供 两种过滤器方式 pre 和 post
- pre 过滤器 在转发之前执行 可以做参数校验 权限校验 流量监控 日志输出 协议转换等
- post过滤器 在响应之前执行 可以用对响应内容 响应头的修改 日志的输出 流量监控等
同时还提供了两种类型过滤器
- GatewayFilter 局部过滤器 针对单个路由
- GlobalFilter 全局过滤器 针对所有路由
8.5.1. 局部过滤器
过滤器工厂 | 作用 | 参数 |
---|---|---|
AddRequestHeader | 为原始请求添加Header | Header的名称及值 |
AddRequestParameter | 为原始请求添加请求参数 | 参数名称及值 |
AddResponseHeader | 为原始响应添加Header | Header的名称及值 |
DedupeResponseHeader | 剔除响应头中重复的值 | 需要去重的Header名称及去重策略 |
Hystrix | 为路由引入Hystrix的断路器保护 | HystrixCommand 的名称 |
FallbackHeaders | 为fallbackUri的请求头中添加具体的异常信息 | Header的名称 |
PrefixPath | 为原始请求路径添加前缀 | 前缀路径 |
PreserveHostHeader | 为请求添加一个preserveHostHeader=true的属性,路由过滤器会检查该属性以决定是否要发送原始的Host | 无 |
RequestRateLimiter | 用于对请求限流,限流算法为令牌桶 | keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus |
RedirectTo | 将原始请求重定向到指定的URL | http状态码及重定向的url |
RemoveHopByHopHeadersFilter | 为原始请求删除IETF组织规定的一系列Header | 默认就会启用,可以通过配置指定仅删除哪些Header |
RemoveRequestHeader | 为原始请求删除某个Header | Header名称 |
RemoveResponseHeader | 为原始响应删除某个Header | Header名称 |
RewritePath | 重写原始的请求路径 | 原始路径正则表达式以及重写后路径的正则表达式 |
RewriteResponseHeader | 重写原始响应中的某个Header | Header名称,值的正则表达式,重写后的值 |
SaveSession | 在转发请求之前,强制执行WebSession::save 操作 |
无 |
secureHeaders | 为原始响应添加一系列起安全作用的响应头 | 无,支持修改这些安全响应头的值 |
SetPath | 修改原始的请求路径 | 修改后的路径 |
SetResponseHeader | 修改原始响应中某个Header的值 | Header名称,修改后的值 |
SetStatus | 修改原始响应的状态码 | HTTP 状态码,可以是数字,也可以是字符串 |
StripPrefix | 用于截断原始请求的路径 | 使用数字表示要截断的路径的数量 |
Retry | 针对不同的响应进行重试 | retries、statuses、methods、series |
RequestSize | 设置允许接收最大请求包的大小。如果请求包大小超过设置的值,则返回 413 Payload Too Large |
请求包大小,单位为字节,默认值为5M |
ModifyRequestBody | 在转发请求之前修改原始请求体内容 | 修改后的请求体内容 |
ModifyResponseBody | 修改原始响应体的内容 | 修改后的响应体内容 |
Default | 为所有路由添加过滤器 | 过滤器工厂名称及值 |
在配置文件中通过 sping.cloud.gateway.routes.filters 设置
spring:
application:
name: api-geteway-server
cloud:
# 网关配置
gateway:
# 路由配置: 转发规则
routes: # 集合
- id: gateway-provider # 唯一标识 默认为随机UUID
# uri: http://localhost:8001/ # 转发路径 服务提供方访问路径
uri: lb://gateway-provider
predicates: # 条件 用于请求网关路径的匹配规则
- Path=/goods/**
filters:
- AddRequestHeader=username,zhansan
8.5.2. 全局过滤器
全局过滤器不需要在配置文件中配置 系统初始化时加载 并作用在每个路由上
- 在gateway模块中 编写自定义过滤器类 并实现 GlobalFilter, Ordered 接口 ```java package com.itheima.gateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono;
@Component
public class MyFilter implements GlobalFilter, Ordered {
@Override
public Mono
/**
* 过滤器排序
* @return 数值越小 越先执行
*/
@Override
public int getOrder() {
return 0;
}
}
<a name="c49af0cf"></a>
# 9. Config 分布式配置中心
Config 解决了在分布式场景下多环境配置文件的管理和维护
1.
在github或者gitee创建一个存放config配置的仓库
2.
创建config-server 模块 并导入坐标
```xml
<!-- config-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
- 创建启动类并使用 @EnableConfigServer 注解启用 config server ```java package com.itheima.config;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication @EnableConfigServer //启用config server功能 public class ConfigServerApp { public static void main(String[] args) { SpringApplication.run(ConfigServerApp.class,args); } }
4.
配置application.yml
```yaml
server:
port: 8888
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://gitee.com/Iekrwh/configs.git # 仓库地址
# username: #如果是私有仓库则需要配置git的账号和密码
# password:
default-label: master # 分支配置
- 在服务提供方中 导入 config client坐标
<!-- config client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
- 在创建配置文件 bootstrap.yml 优先级高于application.yml
spring:
cloud:
config:
uri: http://localhost:8888 # 配置config server地址
name: config # 文件名称
label: master # 分支
profile: dev # -后面的版本名称
- 此时在服务提供方中 可以读取config 配置文件提供的值
9.1. 客户端刷新
当远程仓库中的配置文件发生改变事 我们的config server 会自动更新
但我们的config client并不会自动更新内容
- 客户端引入actuator依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
获取配置信息的类上 加上@RefreshScope 注解
在bootstrap.yml 添加 management.endpoints.web.exposure.include
spring:
cloud:
config:
uri: http://localhost:8888 # 配置config server地址
name: config # 文件名称
label: master # 分支
profile: dev # -后面的版本名称
management:
endpoints:
web:
exposure:
include: '*'
- 在cmd中 向http://localhost:8001/actuator/refresh 发送post请求
curl -X POST http://localhost:8001/actuator/refresh
但是每次更新 需要发送一次请求 后面结合bus才能解决此问题
9.2. 集成Eureka
通过上面例子 我们发现 config客户端访问服务端 地址是固定写死 非常不灵活
我们可以通过Eureka 使服务端在上面注册应用 自动获取应用的地址
- config-server 导入Eureka坐标
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- config-server 配置 加上Eureka的地址 ```yml server: port: 8888
spring: application: name: config-server
cloud: config: server: git: uri: https://gitee.com/Iekrwh/configs.git # 仓库地址
username: #如果是私有仓库则需要配置git的账号和密码
password:
default-label: master # 分支配置
eureka: client: service-url: defaultZone: http://localhost:8761/eureka
3.
在config serve 启动类加上 [@EnableEurekaClient ](/EnableEurekaClient ) 注解
4.
在config client 配置文件中 将 config uri 改为 Eurka服务地址
```yaml
spring:
cloud:
config:
# uri: http://localhost:8888 # 配置config server地址
name: config # 文件名称
label: master # 分支
profile: dev # -后面的版本名称
discovery:
enabled: true # 从注册中心寻找config server 地址
service-id: config-server # config server 注册的应用名
management:
endpoints:
web:
exposure:
include: '*'
10. Bus 消息总线
Spring Cloud 是用轻量的消息中间件将分布式的节点连接起来 用于广播配置文件的更改或者服务的监控管理
Spring Cloud Bus 可选的消息中间件包括RabbitMQ和 Kafka
- 在config-server 和 config-client中 引入 bus依赖
<!-- bus -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
- 在config-server 和 config-client中 分别配置RabbitMQ
spring:
rabbitmq:
host: 192.168.130.124 # mq服务器地址
port: 5672
username: iekr
password: iekr
virtual-host: /itcast
- 在config-server 中 设置暴露监控断电 bus-refresh
management:
endpoints:
web:
exposure:
include: 'bus-refresh' # 暴露bus的刷新端点
- 更新则发送指令 curl -X post config-server地址:端口/actuator/bus-refresh
curl -X post http://localhost:8888/actuator/bus-refresh
11. Stream 消息驱动
Spring Clou Stream 是一个构建消息驱动微服务应用的框架
Stream 对消息中间件的进一步封装 可以做到代码层面对中间件的无感知 甚至动态切换中间件
Stream 构建的应用程序与消息中间件之间是通过绑定器 Binder 相关联的
11.1. 消息生产者
- 创建生产者模块 导入坐标
```xml
<!--spring boot web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- stream -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
2.
编写配置文件
```yaml
server:
port: 8000
spring:
cloud:
stream:
# 定义绑定器,绑定到哪个消息中间件上
binders:
itheima_binder: # 自定义的绑定器名称
type: rabbit # 绑定器类型
environment: # 指定mq的环境
spring:
rabbitmq:
host: 192.168.130.124
port: 5672
username: guest
password: guest
virtual-host: /
bindings:
output: # channel名称
binder: itheima_binder #指定使用哪一个绑定器(自定义的绑定器名称)
destination: itheima_exchange # 消息目的地
- 定义发送消息类 并在类上开启Binding绑定为配置文件 ```java package com.itheima.stream.producer;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.stream.annotation.EnableBinding; import org.springframework.cloud.stream.messaging.Source; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.support.MessageBuilder; import org.springframework.stereotype.Component;
@Component @EnableBinding(Source.class) public class MessageProducer {
@Autowired
private MessageChannel output;
public void send(){
String msessage = "hello stream~~~";
//发送消息
output.send(MessageBuilder.withPayload(msessage).build());
System.out.println("消息发送成功~~~");
}
}
4.
创建一个接口用于测试 是否能发送消息给mq
```java
package com.itheima.stream.producer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ProducerController {
@Autowired
private MessageProducer producer;
@RequestMapping("/send")
public String sendMsg(){
producer.send();
return "success";
}
}
11.2. 消息消费者
- 创建消费者模块 导入坐标
```xml
<!--spring boot web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- stream -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
2.
编写配置文件 主要把端口和 bindings设置为输出还是输入模式
```yaml
server:
port: 9000
spring:
cloud:
stream:
# 定义绑定器,绑定到哪个消息中间件上
binders:
itheima_binder: # 自定义的绑定器名称
type: rabbit # 绑定器类型
environment: # 指定mq的环境
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
bindings:
input: # channel名称
binder: itheima_binder #指定使用哪一个binder
destination: itheima_exchange # 消息目的地
- 创建消息接收类 在类开启binding注解 并在接收方法中定义 @StreamListener(Sink.INPUT) ```java package com.itheima.stream.consumer;
import org.springframework.cloud.stream.annotation.EnableBinding; import org.springframework.cloud.stream.annotation.StreamListener; import org.springframework.cloud.stream.messaging.Sink; import org.springframework.messaging.Message; import org.springframework.stereotype.Component;
/**
消息接收类 */ @EnableBinding({Sink.class}) @Component public class MessageListener {
@StreamListener(Sink.INPUT) public void receive(Message message){
System.out.println(message);
System.out.println(message.getPayload());
} } ```
12. Sleuth+Zipkin 链路追踪
Spring Cloud Sleuth 它在分布式中能跟踪一个用户请求的过程 捕获这些跟踪数据 就能构建微服务的整个调用链的视图 它是调试和监控微服务的关键工具
- 安装启动zipkin 访问http://localhost:9411/
java -jar zipkin.jar
- 在服务提供方和消费方法 引入 zipkin 坐标
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
- 配置文件 ```yaml server: port: 8001
eureka: client: service-url: defaultZone: http://localhost:8761/eureka spring: application: name: feign-provider zipkin: base-url: http://localhost:9411/ # 设置zipkin的服务端路径
sleuth: sampler: probability: 1 # 采集率 默认 0.1 百分之十。 ```