目录
配置启动参数 --spring.profiles.active 和 --server.port
主程序添加 @EnableCircuitBreaker 启用 hystrix 断路器
主程序添加 @EnableHystrixDashboard 和 @EnableDiscoveryClient
主程序添加 @EnableDiscoveryClient 和 @EnableFeignClients
application.yml 配置 ribbon 超时和重试
配置 actuator,暴露 hystrix.stream 监控端点
application.yml 暴露 hystrix.stream 端点
主程序添加 @EnableConfigServer 和 @EnableDiscoveryClient
UserServiceImpl 添加 @RefreshScope 注解
config bus + rabbitmq 消息总线配置刷新
需要动态更新配置的微服务,添加 spring cloud bus 依赖,并添加 rabbitmq 连接信息
config-server 暴露 bus-refresh 刷新端点
把配置文件保存到 sp12-config 项目的 resources/config 目录下
修改 application.yml 激活 native profile,并指定配置文件目录
介绍
spring cloud 是一系列框架的集合。它利用 spring boot 的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用 spring boot 的开发风格做到一键启动和部署。spring cloud 并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过 spring boot 风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
spring cloud 技术组成
eureka
微服务治理,服务注册和发现
ribbon
负载均衡、请求重试
hystrix
断路器,服务降级、熔断
feign
ribbon + hystrix 集成,并提供声明式客户端
hystrix dashboard 和 turbine
hystrix 数据监控
zuul
API 网关,提供微服务的统一入口,并提供统一的权限验证
config
配置中心
bus
消息总线, 配置刷新
sleuth+zipkin
链路跟踪
Spring Cloud 对比 Dubbo
-
Dubbo
- Dubbo只是一个远程调用(RPC)框架
- 默认基于长连接,支持多种序列化格式
-
Spring Cloud
- 框架集
- 提供了一整套微服务解决方案(全家桶)
- 基于http调用, Rest API
Spring MVC 接收参数的几个注解
eureka 注册与发现
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
配置文件
spring:
application:
name: eureka-server
server:
port: 2001
eureka:
server:
enable-self-preservation: false
instance:
hostname: eureka1
client:
register-with-eureka: false
fetch-registry: false
eureka 集群服务器之间,通过 hostname 来区分
eureka.server.enable-self-preservation
eureka 的自我保护状态:心跳失败的比例,在15分钟内是否超过85%,如果出现了超过的情况,Eureka Server会将当前的实例注册信息保护起来,同时提示一个警告,一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据。也就是不会注销任何微服务
eureka.client.register-with-eureka=false
不向自身注册
eureka.client.fetch-registry=false
不从自身拉取注册信息
eureka.instance.lease-expiration-duration-in-seconds
最后一次心跳后,间隔多久认定微服务不可用,默认90
注解 @EnableEurekaServer
主启动类上添加@EnableEurekaServer注解
修改 hosts 文件,添加 eureka 域名映射
C:\Windows\System32\drivers\etc\hosts
127.0.0.1 eureka1
127.0.0.1 eureka2
服务注册到eureka服务器
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置文件
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka
eureka.instance.lease-renewal-interval-in-seconds
心跳间隔时间,默认 30 秒
defaultZone,默认位置,可以修改为具体地理位置,比如:beiJing, shangHai, shenZhen 等,表示 eureka 服务器的部署位置, 需要云服务器提供
eureka.client.registry-fetch-interval-seconds
拉取注册信息间隔时间,默认 30 秒
主程序启用服务注册发现客户端
主程序添加 @EnableDiscoveryClient
注解
eureka 高可用
配置文件
eureka:
instance:
hostname: eureka1
client:
register-with-eureka: true #profile的配置会覆盖公用配置
fetch-registry: true #profile的配置会覆盖公用配置
service-url:
defaultZone: http://eureka2:2002/eureka #eureka1启动时向eureka2注册
eureka:
instance:
hostname: eureka2
client:
register-with-eureka: true #profile的配置会覆盖公用配置
fetch-registry: true #profile的配置会覆盖公用配置
service-url:
defaultZone: http://eureka1:2001/eureka #eureka2启动时向eureka1注册
配置启动参数 --spring.profiles.active
和 --server.port
--spring.profiles.active=eureka1 --server.port=2001
--spring.profiles.active=eureka2 --server.port=2002
eureka客户端注册时,向多个服务器注册
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
当一个 eureka 服务宕机时,仍可以连接另一个 eureka 服务
ribbon服务消费者
ribbon 提供了负载均衡和重试功能, 它底层是使用 RestTemplate 进行 Rest api 调用
依赖
-
eureka-client 中已经包含 ribbon 依赖
RestTemplate
RestTemplate 是SpringBoot提供的一个Rest远程调用工具
它的常用方法:
- getForObject() - 执行get请求
- postForObject() - 执行post请求
创建 RestTemplate
实例
//创建 RestTemplate 实例,并存入 spring 容器
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
ribbon 负载均衡和重试
Ribbon 负载均衡
添加 ribbon 起步依赖(可选)
- eureka 依赖中已经包含了 ribbon
RestTemplate 设置 @LoadBalanced
@LoadBalanced
负载均衡注解,会对 RestTemplate
实例进行封装,创建动态代理对象,并切入(AOP)负载均衡代码,把请求分发到集群中的服务器
@LoadBalanced //负载均衡注解
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
访问路径设置为服务id
@GetMapping("/item-service/{orderId}")
public JsonResult<List<Item>> getItems(@PathVariable String orderId) {
//这里服务器路径用 service-id 代替,ribbon 会向服务的多台集群服务器分发请求
return rt.getForObject("http://item-service/{1}", JsonResult.class, orderId);
}
ribbon 重试
依赖
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
配置文件
spring:
application:
name: ribbon
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
ribbon:
MaxAutoRetriesNextServer: 2
MaxAutoRetries: 1
OkToRetryOnAllOperations: true
ConnectionTimeout
ReadTimeout
OkToRetryOnAllOperations=true
默认只对GET请求重试, 当设置为true时, 对POST等所有类型请求都重试
MaxAutoRetriesNextServer
更换实例的次数
MaxAutoRetries
当前实例重试次数,尝试失败会更换下一个实例
主程序设置 RestTemplate 的请求工厂的超时属性
@LoadBalanced
@Bean
public RestTemplate getRestTemplate() {
SimpleClientHttpRequestFactory f = new SimpleClientHttpRequestFactory();
f.setConnectTimeout(1000);
f.setReadTimeout(1000);
return new RestTemplate(f);
//RestTemplate 中默认的 Factory 实例中,两个超时属性默认是 -1,
//未启用超时,也不会触发重试
//return new RestTemplate();
}
通过 ribbon 访问 service,当超时,ribbon 会重试请求集群中其他服务器
ribbon的重试机制,在 feign 和 zuul 中进一步进行了封装,后续可以使用feign或zuul的重试机制
Hystrix 断路器
微服务宕机时,ribbon 无法转发请求
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
配置文件
spring:
application:
name: hystrix
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
ribbon:
MaxAutoRetries: 1
MaxAutoRetriesNextServer: 2
OkToRetryOnAllOperations: true
主程序添加 @EnableCircuitBreaker
启用 hystrix 断路器
启动断路器,断路器提供两个核心功能:
-
降级,超时、出错、不可到达时,对服务降级,返回错误信息或者是缓存数据
-
熔断,当服务压力过大,错误比例过多时,熔断所有请求,所有请求直接降级
@SpringCloudApplication
可以使用 @SpringCloudApplication
注解代替三个注解
RibbonController 中添加降级方法
注解
添加 @HystrixCommand
注解,指定降级方法名
@GetMapping("/item-service/{orderId}")
@HystrixCommand(fallbackMethod = "getItemsFB") //指定降级方法的方法名
public JsonResult<List<Item>> getItems(@PathVariable String orderId) {
return rt.getForObject("http://item-service/{1}", JsonResult.class, orderId);
}
hystrix 超时设置
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds
hystrix等待超时后, 会执行降级代码, 快速向客户端返回降级结果, 默认超时时间是1000毫秒
为了测试 hystrix 降级,我们把 hystrix 等待超时设置得非常小(500毫秒)
spring:
application:
name: hystrix
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
ribbon:
MaxAutoRetriesNextServer: 2
MaxAutoRetries: 1
OkToRetryOnAllOperations: true
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 500
hystrix dashboard 断路器仪表盘
hystrix 对请求的降级和熔断,可以产生监控信息,hystrix dashboard可以实时的进行监控
添加 actuator,并暴露 hystrix 监控端点
actuator 是 spring boot 提供的服务监控工具,提供了各种监控信息的监控端点
management.endpoints.web.exposure.include
配置选项,
可以指定端点名,来暴露监控端点
如果要暴露所有端点,可以用 “*”
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
修改配置文件
spring:
application:
name: hystrix
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
ribbon:
MaxAutoRetriesNextServer: 1
MaxAutoRetries: 1
OkToRetryOnAllOperations: true
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 500
management:
endpoints:
web:
exposure:
include: hystrix.stream
Hystrix dashboard 仪表盘
依赖
<?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 https://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.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.tedu</groupId>
<artifactId>sp08-hystrix-dashboard</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sp08-hystrix-dashboard</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<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-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</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>
配置文件
spring:
application:
name: hystrix-dashboard
server:
port: 4001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
hystrix:
dashboard:
proxy-stream-allow-list: localhost
主程序添加 @EnableHystrixDashboard
和 @EnableDiscoveryClient
@EnableDiscoveryClient
@EnableHystrixDashboard
@SpringBootApplication
public class Sp08HystrixDashboardApplication {
public static void main(String[] args) {
SpringApplication.run(Sp08HystrixDashboardApplication.class, args);
}
}
访问 hystrix dashboard
填入 hystrix 的监控端点,开启监控
通过 hystrix 访问服务多次,观察监控信息
hystrix 熔断
整个链路达到一定的阈值,默认情况下,10秒内产生超过20次请求,则符合第一个条件。
满足第一个条件的情况下,如果请求的错误百分比大于阈值,则会打开断路器,默认为50%。
Hystrix的逻辑,先判断是否满足第一个条件,再判断第二个条件,如果两个条件都满足,则会开启断路器
断路器打开 5 秒后,会处于半开状态,会尝试转发请求,如果仍然失败,保持打开状态,如果成功,则关闭断路器
使用 apache 的并发访问测试工具 ab
用 ab 工具,以并发50次,来发送20000个请求
ab -n 20000 -c 50 http://localhost:3001/item-service/35
断路器状态为 Open,所有请求会被短路,直接降级执行 fallback 方法
hystrix 配置
Configuration · Netflix/Hystrix Wiki · GitHubhttps://github.com/Netflix/Hystrix/wiki/Configuration
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds
请求超时时间,超时后触发失败降级
hystrix.command.default.circuitBreaker.requestVolumeThreshold
10秒内请求数量,默认20,如果没有达到该数量,即使请求全部失败,也不会触发断路器打开
hystrix.command.default.circuitBreaker.errorThresholdPercentage
失败请求百分比,达到该比例则触发断路器打开
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds
断路器打开多长时间后,再次允许尝试访问(半开),仍失败则继续保持打开状态,如成功访问则关闭断路器,默认 5000
feign 声明式客户端接口
微服务应用中,ribbon 和 hystrix 总是同时出现,feign 整合了两者,并提供了声明式消费者客户端
用 feign 代替 hystrix+ribbon
依赖
配置文件
spring:
application:
name: feign
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
主程序添加 @EnableDiscoveryClient
和 @EnableFeignClients
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class Sp09FeignApplication {
public static void main(String[] args) {
SpringApplication.run(Sp09FeignApplication.class, args);
}
}
feign 声明式客户端
feign 利用了我们熟悉的 spring mvc 注解来对接口方法进行设置,降低了我们的学习成本。
通过这些设置,feign可以拼接后台服务的访问路径和提交的参数
例如
@GetMapping("/{userId}/score")
JsonResult addScore(@PathVariable Integer userId, @RequestParam Integer score);
当这样调用该方法:
service.addScore(7, 100);
那么 feign 会向服务器发送请求:
http://用户微服务/7/score?score=100
注意:如果 score 参数名与变量名不同,需要添加参数名设置:
@GetMapping("/{userId}/score")
JsonResult addScore(@PathVariable Integer userId, @RequestParam("score") Integer s);
注解 @FeignClient
package cn.tedu.sp09.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import cn.tedu.sp01.pojo.User;
import cn.tedu.web.util.JsonResult;
@FeignClient("user-service")
public interface UserFeignService {
@GetMapping("/{userId}")
JsonResult<User> getUser(@PathVariable Integer userId);
// 拼接路径 /{userId}/score?score=新增积分
@GetMapping("/{userId}/score")
JsonResult addScore(@PathVariable Integer userId, @RequestParam Integer score);
}
注意,如果请求参数名与方法参数名不同,@RequestParam
不能省略,并且要指定请求参数名:@RequestParam("score") Integer s
调用流程
feign + ribbon 负载均衡和重试
无需额外配置,feign 默认已启用了 ribbon 负载均衡和重试机制。可以通过配置对参数进行调整
重试的默认配置参数:
ConnectTimeout=1000
ReadTimeout=1000
MaxAutoRetries=0
MaxAutoRetriesNextServer=1
application.yml 配置 ribbon 超时和重试
ribbon.xxx
全局配置item-service.ribbon.xxx
对特定服务实例的配置
spring:
application:
name: feign
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
ribbon:
ConnectTimeout: 1000
ReadTimeout: 1000
item-service:
ribbon:
MaxAutoRetries: 1
MaxAutoRetriesNextServer: 2
ConnectTimeout: 1000
ReadTimeout: 500
feign + hystrix 降级
feign 启用 hystrix
feign 默认没有启用 hystrix,添加配置,启用 hystrix
feign.hystrix.enabled=true
feign:
hystrix:
enabled: true
默认1秒会快速失败,没有降级方法时,会显示白板页
可以添加配置,暂时减小降级超时时间,以便后续对降级进行测试
......
feign:
hystrix:
enabled: true
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 500
feign 远程接口中指定降级类
远程调用失败, 会执行降级类中的代码.例如
...
@FeignClient(name="item-service", fallback = ItemFeignServiceFB.class)
public interface ItemFeignService {
...
降级类
降级类需要实现远程接口
@Component
public class ItemFeignServiceFB implements ItemFeignService {
feign + hystrix 监控和熔断测试
添加 hystrix 起步依赖
feign 没有包含完整的 hystrix 依赖
编辑起步依赖,添加hystrix依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
主程序添加 @EnableCircuitBreaker
@EnableCircuitBreaker
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class Sp09FeignApplication {
public static void main(String[] args) {
SpringApplication.run(Sp09FeignApplication.class, args);
}
}
配置 actuator,暴露 hystrix.stream
监控端点
actuator 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
application.yml 暴露 hystrix.stream
端点
management:
endpoints:
web:
exposure:
include: hystrix.stream
启动 hystrix dashboard 服务,填入 feign 监控路径,开启监控
熔断测试
用 ab 工具,以并发50次,来发送20000个请求
ab -n 20000 -c 50 http://localhost:3001/item-service/35
断路器状态为 Open,所有请求会被短路,直接降级执行 fallback 方法
hystrix + turbine 集群聚合监控
hystrix dashboard 一次只能监控一个服务实例,使用 turbine 可以汇集监控信息,将聚合后的信息提供给 hystrix dashboard 来集中展示和监控
依赖
配置文件
spring:
application:
name: turbin
server:
port: 5001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
turbine:
app-config: order-service
cluster-name-expression: new String("default")
主程序
添加 @EnableTurbine
和 @EnableDiscoveryClient
注解
zuul API网关
zuul API 网关,为微服务应用提供统一的对外访问接口。
zuul 还提供过滤器,对所有微服务提供统一的请求校验。
依赖
配置文件
zuul 路由配置可以省略,缺省以服务 id 作为访问路径
spring:
application:
name: zuul
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
zuul:
routes:
item-service: /item-service/**
user-service: /user-service/**
order-service: /order-service/**
主程序
添加 @EnableZuulProxy
和 @EnableDiscoveryClient
注解
zuul + ribbon 负载均衡
zuul 已经集成了 ribbon,默认已经实现了负载均衡
zuul + ribbon 重试
pom.xml 添加 spring-retry 依赖
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
配置 zuul 开启重试,并配置 ribbon 重试参数
需要开启重试,默认不开启
spring:
application:
name: zuul
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
zuul:
retryable: true
# routes:
# item-service: /item-service/**
# user-service: /user-service/**
# order-service: /order-service/**
ribbon:
ConnectTimeout: 1000
ReadTimeout: 1000
MaxAutoRetriesNextServer: 1
MaxAutoRetries: 1
zuul + hystrix 降级
getRoute() 方法中指定应用此降级类的服务id,星号或null值可以通配所有服务
例如
package cn.tedu.sp11.fallback;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import cn.tedu.web.util.JsonResult;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public class ItemServiceFallback implements FallbackProvider {
@Override
public String getRoute() {
//当执行item-service失败,
//应用当前这个降级类
return "item-service";
//星号和null都表示所有微服务失败都应用当前降级类
//"*"; //null;
}
//该方法返回封装降级响应的对象
//ClientHttpResponse中封装降级响应
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return response();
}
private ClientHttpResponse response() {
return new ClientHttpResponse() {
//下面三个方法都是协议号
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return HttpStatus.OK.value();
}
@Override
public String getStatusText() throws IOException {
return HttpStatus.OK.getReasonPhrase();
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
log.info("fallback body");
String s = JsonResult.err().msg("后台服务错误").toString();
return new ByteArrayInputStream(s.getBytes("UTF-8"));
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
}
修改配置降低 hystrix 超时时间,以便测试降级
spring:
application:
name: zuul
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
zuul:
retryable: true
ribbon:
ConnectTimeout: 1000
ReadTimeout: 2000
MaxAutoRetriesNextServer: 1
MaxAutoRetries: 1
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 500
zuul + hystrix 数据监控
暴露 hystrix.stream 监控端点
zuul 已经包含 actuator 依赖
management:
endpoints:
web:
exposure:
include: hystrix.stream
开启监控
启动 shystrix-dashboard,填入 zuul 的监控端点路径,开启监控
必须通过zuul网关访问后台服务才会长生监控数据
zuul + turbine 聚合监控
修改 turbine 项目,聚合 zuul 服务实例
配置文件修改
spring:
application:
name: turbin
server:
port: 5001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
turbine:
app-config: order-service, zuul
cluster-name-expression: new String("default")
使用hystrix仪表盘, 对 turbine 监控端点进行监控, 此端点聚合了订单服务和zull网关服务的监控数据
熔断测试
ab -n 20000 -c 50 http://localhost:3001/order-service/123abc
zuul 请求过滤
定义过滤器,继承 ZuulFilter
package cn.tedu.sp11.filter;
import javax.servlet.http.HttpServletRequest;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import cn.tedu.web.util.JsonResult;
@Component
public class AccessFilter extends ZuulFilter{
@Override
public boolean shouldFilter() {
//对指定的serviceid过滤,如果要过滤所有服务,直接返回 true
RequestContext ctx = RequestContext.getCurrentContext();
String serviceId = (String) ctx.get(FilterConstants.SERVICE_ID_KEY);
if(serviceId.equals("item-service")) {
return true;
}
return false;
}
@Override
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest req = ctx.getRequest();
String token = req.getParameter("token");
if (token == null) {
//此设置会阻止请求被路由到后台微服务
ctx.setSendZuulResponse(false);
//向客户端的响应
ctx.setResponseStatusCode(200);
ctx.setResponseBody(JsonResult.err().code(JsonResult.NOT_LOGIN).toString());
}
//zuul过滤器返回的数据设计为以后扩展使用,
//目前该返回值没有被使用
return null;
}
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
//该过滤器顺序要 > 5,才能得到 serviceid
return FilterConstants.PRE_DECORATION_FILTER_ORDER+1;
}
}
zuul Cookie过滤
zuul 会过滤敏感 http 协议头,默认过滤以下协议头:
- Cookie
- Set-Cookie
- Authorization
可以设置 zuul 不过滤这些协议头
zuul:
sensitive-headers:
config 配置中心
yml 配置文件保存到 git 服务器,例如 github.com 或 gitee.com
微服务启动时,从服务器获取配置文件
github 上存放配置文件
禁止配置中心的配置信息覆盖客户端配置
默认配置中心配置优先级高,配置中心配置会覆盖客户端的所有配置,包括命令行参数配置,这样我们在item-service和order-service中配置的端口号启动参数会无效.我们可以设置禁止配置中心的配置将客户端配置覆盖掉.在配置文件中添加下面的配置
spring:
......
cloud:
config:
override-none: true
将 config 项目上传到 github
config 服务器
config 配置中心从 git 下载所有配置文件。
而其他微服务启动时从 config 配置中心获取配置信息。
依赖
配置文件
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://github.com/你的个人路径/sp-config
searchPaths: config
#username: your-username
#password: your-password
server:
port: 6001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
主程序添加 @EnableConfigServer
和 @EnableDiscoveryClient
从配置中心获取配置信息的服务添加 config 客户端依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
添加 bootstrap.yml
bootstrap.yml
,引导配置文件,先于 application.yml 加载
spring:
cloud:
config:
discovery:
enabled: true
service-id: config-server
name: item-service
profile: dev
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
配置刷新
spring cloud 允许运行时动态刷新配置,可以重新从配置中心获取新的配置信息
以 user-service
为例演示配置刷新
user-service 的 pom.xml 中添加 actuator 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
yml 配置文件中暴露 refresh 端点
修改 config 项目中的 user-service-dev.yml
,并提交推送到远程仓库
sp:
user-service:
users: "[{\"id\":7, \"username\":\"abc\",\"password\":\"123\"},{\"id\":8, \"username\":\"def\",\"password\":\"456\"},{\"id\":9, \"username\":\"ghi\",\"password\":\"789\"}]"
spring:
application:
name: user-service
cloud:
config:
override-none: true
server:
port: 8101
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
management:
endpoints:
web:
exposure:
include: refresh
UserServiceImpl 添加 @RefreshScope
注解
只允许对添加了 @RefreshScope
或 @ConfigurationProperties
注解的 Bean 刷新配置,可以将更新的配置数据注入到 Bean 中
config bus + rabbitmq 消息总线配置刷新
post 请求消息总线刷新端点,服务器会向 rabbitmq 发布刷新消息,接收到消息的微服务会向配置服务器请求刷新配置信息
需要动态更新配置的微服务,添加 spring cloud bus 依赖,并添加 rabbitmq 连接信息
依赖
bus
、rabbitmq
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-bus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
配置文件中添加 rabbitmq 连接信息
- 连接信息请修改成你的连接信息
- config项目需要提交
spring:
......
rabbitmq:
host: 192.168.64.140
port: 5672
username: admin
password: admin
config-server 暴露 bus-refresh 刷新端点
修改 sp12-config 项目的 application.yml, 暴露bus-refresh
端点
management:
endpoints:
web:
exposure:
include: bus-refresh
config 本地文件系统
可以把配置文件保存在配置中心服务的 resources 目录下,直接访问本地文件
把配置文件保存到 sp12-config 项目的 resources/config 目录下
修改 application.yml 激活 native profile,并指定配置文件目录
必须配置 spring.profiles.active=native
来激活本地文件系统
本地路径默认:[classpath:/, classpath:/config, file:./, file:./config]
spring:
application:
name: config-server
profiles:
active: native
cloud:
config:
server:
native:
search-locations: classpath:/config
# git:
# uri: https://github.com/你的用户路径/sp-config
# searchPaths: config
# username: your-username
# password: your-password
rabbitmq:
host: 192.168.64.140
port: 5672
username: admin
password: admin
server:
port: 6001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
management:
endpoints:
web:
exposure:
include: bus-refresh
sleuth 链路跟踪
随着系统规模越来越大,微服务之间调用关系变得错综复杂,一条调用链路中可能调用多个微服务,任何一个微服务不可用都可能造整个调用过程失败
spring cloud sleuth 可以跟踪调用链路,分析链路中每个节点的执行情况
微服务中添加 spring cloud sleuth 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
在控制台查看链路跟踪日志
通过 zuul 网关,访问 service
微服务的控制台日志中,可以看到以下信息:[服务id,请求id,span id,是否发送到zipkin]
- 请求id:请求到达第一个微服务时生成一个请求id,该id在调用链路中会一直向后面的微服务传递
- span id:链路中每一步微服务调用,都生成一个新的id
sleuth + zipkin 链路分析
zipkin 可以收集链路跟踪数据,提供可视化的链路分析
链路数据抽样比例
默认 10% 的链路数据会被发送到 zipkin 服务。可以配置修改抽样比例
spring:
sleuth:
sampler:
probability: 0.1
zipkin 服务
下载 zipkin 服务器
https://github.com/openzipkin/zipkinhttps://github.com/openzipkin/zipkin
启动 zipkin 时,连接到 rabbitmq
java -jar zipkin-server-2.12.9-exec.jar --zipkin.collector.rabbitmq.uri=amqp://admin:admin@192.168.64.140:5672
http://localhost:9411/zipkin![zipkin](https://img-blog.csdnimg.cn/201910311528043.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zODMwNTQ0MA==,size_16,color_FFFFFF,t_70)
微服务添加 zipkin 起步依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
如果没有配置过 spring cloud bus,还需要添加 rabbitmq
依赖和连接信息
启动并访问服务,访问 zipkin 查看链路分析
-
刷新访问多次,链路跟踪数据中,默认只有 10% 会被收集到zipkin
-
访问 zipkin
向eureka注册正确的ip地址
eureka客户端向eureka注册时, 会自动选择网卡, 并可能注册主机名而不是ip地址.
下面配置可以选择正确网卡的ip向eureka进行注册.
选择正确网卡
服务器有多块网卡,要选择正确网卡的ip地址向eureka进行注册
修改 bootstrap.yml
spring:
cloud:
inetutils:
ignored-interfaces: # 忽略的网卡
- VM.*
preferred-networks: # 要是用的网卡的网段
- 192\.168\.0\..+
注册ip地址,而不是主机名
注册时,有可能自动选择主机名进行注册,而不使用ip地址. 主机名在局域网内有可能不会被正确的解析
最好使用ip地址进行注册,而不注册主机名
在应用配置application.yml
中配置:
eureka:
instance:
prefer-ip-address: true # 使用ip进行注册
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port} # 界面列表中显示的格式也显示ip