Hystrix服务雪崩
分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务。如下图
如果各个服务正常运行,那大家齐乐融融,高高兴兴的,但是如果其中一个服务崩坏掉会出现什么样的情况呢?如下图,
引起雪崩的原因和服务雪崩的三个阶段
第一个是:硬件故障
第二个是:程序Bug;
第三个是:缓存击穿(用户大量访问缓存中没有的键值,导致大量请求查询数据库,使数据库压力过大);
第四个是:硬件故障
首先需要在消费端的pom文件引入
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
开启熔断
在启动类 ConsumerApplication 上添加注解:@EnableCircuitBreaker
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class ConsumerApplication {
// ...
}
可以看到,我们类上的注解越来越多,在微服务中,经常会引入上面的三个注解,于是Spring就提供了一个组合注解:@SpringCloudApplication
编写降级逻辑
当目标服务的调用出现故障,我们希望快速失败,给用户一个友好提示。因此需要提前编写好失败时的降级处理逻辑,要使用HystrixCommand来完成。
@RestController
@RequestMapping("/consumer")
@Slf4j
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("{id}")
@HystrixCommand(fallbackMethod = "queryByIdFallback")
public String queryById(@PathVariable Long id) {
String url = "http://user-service/user/" + id;
return restTemplate.getForObject(url, String.class);
}
public String queryByIdFallback(Long id) {
log.error("查询用户信息失败。id:{}", id);
return "对不起,网络太拥挤了!";
}
}
当 生产者正常提供服务时,访问与以前一致。但是当将 生产者 停机时,会发现页面返回了降级处理信息
超时设置
Hystrix的默认超时时长为1,我们可以通过配置application.yml来改变超时时间
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 2000
熔断原理
在服务熔断中,使用的熔断器,也叫断路器,其英文单词为:Circuit Breaker 熔断机制与家里使用的电路熔断原理类似;当如果电路发生短路的时候能立刻熔断电路,避免发生灾难。在分布式系统中应用服务熔断后;服务调用方可以自己进行判断哪些服务反应慢或存在大量超时,可以针对这些服务进行主动熔断,防止整个系统被拖垮。Hystrix的服务熔断机制,可以实现弹性容错;当服务请求情况好转之后,可以自动重连。通过断路的方式,将后续请求直接拒绝,一段时间(默认5秒)之后允许部分请求通过,如果调用成功则回到断路器关闭状态,否则继续打开,拒绝请求的服务。
Hystrix的熔断状态机模型
状态机有3个状态
1.Closed:关闭状态(断路器关闭),所有请求都正常访问。
2.Open:打开状态(断路器打开),所有请求都会被降级。Hystrix会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全打开。默认失败比例的阈值是50%,请求次数最少不低于20次。
3.Half Open:半开状态,不是永久的,断路器打开后会进入休眠时间(默认是5S)。随后断路器会自动进入半开状态。此时会释放部分请求通过,若这些请求都是健康的,则会关闭断路器,否则继续保持打开,再次进行休眠计时
我们可以通过配置YML来改变
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 2000 #服务降级超时时间
circuitBreaker:
errorThresholdPercentage: 50 # 触发熔断错误比例阈值,默认值50%
sleepWindowInMilliseconds: 10000 # 熔断后休眠时长,默认值5秒
requestVolumeThreshold: 10 # 熔断触发最小请求次数,默认值是20
Feign
在消费者中
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
开启Feign功能
在 ConsumerApplication 启动类上,添加注解,开启Feign功能
@SpringCloudApplication
@EnableFeignClients //开启feign功能
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
负载均衡
Feign中本身已经集成了Ribbon依赖和自动配置:
Fegin内置的ribbon默认设置了请求超时时长,默认是1000,我们可以通过手动配置来修改这个超时时长
ribbon:
ReadTimeout: 2000 # 读取超时时长
ConnectTimeout: 1000 # 建立链接的超时时长
或者为某一个具体service指定
user-service
ribbon:
ReadTimeout: 2000 # 读取超时时长
ConnectTimeout: 1000 # 建立链接的超时时长
因为ribbon内部有重试机制,一旦超时,会自动重新发起请求。如果不希望重试,可以添加配置:
ribbon:
ConnectTimeout: 1000 # 连接超时时长
ReadTimeout: 2000 # 数据通信超时时长
MaxAutoRetries: 0 # 当前服务器的重试次数
MaxAutoRetriesNextServer: 0 # 重试多少次服务
OkToRetryOnAllOperations: false # 是否对所有的请求方式都重试
Gateway网关
简介
Spring Cloud Gateway是Spring官网基于Spring 5.0、 Spring Boot 2.0、Project Reactor等技术开发的网关服务。
Spring Cloud Gateway基于Filter链提供网关基本功能:安全、监控/埋点、限流等。
Spring Cloud Gateway为微服务架构提供简单、有效且统一的API路由管理方式。
Spring Cloud Gateway是替代Netflix Zuul的一套解决方案。
Spring Cloud Gateway组件的核心是一系列的过滤器,通过这些过滤器可以将客户端发送的请求转发(路由)到对应的微服务。 Spring Cloud Gateway是加在整个微服务最前沿的防火墙和代理器,隐藏微服务结点IP端口信息,
从而加强安全保护。Spring Cloud Gateway本身也是一个微服务,需要注册到Eureka服务注册中心
核心概念
路由(route) 路由信息的组成:由一个ID、一个目的URL、一组断言工厂、一组Filter组成。如果路由断言为真,说明请求URL和配置路由匹配。
断言(Predicate) Spring Cloud Gateway中的断言函数输入类型是Spring 5.0框架中的
ServerWebExchange。Spring Cloud Gateway的断言函数允许开发者去定义匹配来自于HTTP Request中的任何信息比如请求头和参数。
过滤器(Filter) 一个标准的Spring WebFilter。 Spring Cloud Gateway中的Filter分为两种类型的Filter,分别是Gateway Filter和Global Filter。过滤器Filter将会对请求和响应进行修改处理
穿件一个新得工程
在pom文件中导入
<?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">
<parent>
<artifactId>lxs-springcloud</artifactId>
<groupId>com.lxs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lxs-gateway</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project>
编写GatewayApplication启动类
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
编写配置YML
server:
port: 10010
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
# 路由id,可以随意写
- id: user-service-route
# 代理的服务地址
# uri: HTTP://127.0.0.1:9091
uri: lb://user-service
# 路由断言,可以配置映射路径
predicates:
- Path=/user/**
eureka:
client:
service-url:
defaultZone: HTTP://127.0.0.1:10086/eureka
instance:
prefer-ip-address: true
启动测试
在日志中就能看见负载均衡器: