Hystrix是一个用于处理分布式系统的延迟和容错的开源库,可以保证一个服务出现故障时,不会导致整个系统出现雪崩效应,以提高分布式系统弹性;
作为“断路器”,在一个服务出现故障时,可以通过短路器监控,返回一个可以处理的响应结果,保证服务调用线程不会长时间被占用,避免故障蔓延。
雪崩
当一个服务器中要同时处理多个请求时,当一个请求无法正确响应,请求超时。会将请求阻塞到该服务的线程池中,当线程池爆满出现故障,会导致整个服务中所有请求都无法正确响应,导致所有请求故障,出现雪崩。
服务出现故障时,给故障服务降级到事先准备好的故障处理结果,将此结果返回给服务消费者,如:状态码 错误页面等
Hystrix为每一个请求分配一个线程池,当小线程池爆满的话会立刻被拒绝进行服务降级。
会导致请求失败,但是不会导致线程阻塞,最多影响这个依赖的线程池,不会影响其他线程池的正常工作。
触发服务降级的情况:
线程池满,请求超时,服务宕机
案例:
是服务的消费者担心请求服务时返回异常,所以要在消费者一方配置自己的降级处理,我们在消费方操作。例如:order请求user,在order方操作。
1,依赖导入
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
2,Order启动类编写 添加熔断器注解
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker//开启熔断注解
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class,args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
3,控制器编写 设置请求超时 降级熔断
@GetMapping("/{id}")
@HystrixCommand(fallbackMethod="aa")//降级调用方法设置
public Order getById(@PathVariable Long id){
//order请求设置睡眠超时
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Order order = this.orderService.getById(id);
/**
* http://user-service/user/ 其中user-service为动态表填写的应用名称
* 会从注册中心拉取该名称的列表 为一个集合 会走负载策略 轮询等 访问不同服务
*/
User user = restTemplate.getForObject("http://user-service/user/" + order.getUserId(), User.class);
order.setUser(user);
return order;
}
//降级方法
public Order aa(@PathVariable Long id){
return new Order();
}
4,请求时 请求时间过长 进行降级熔断 走降级方法 不会阻塞,会返回错误数据
5,当Order请求成功,order调用user时出现调用请求超时 进行降级处理
@GetMapping("/{id}")
@HystrixCommand(fallbackMethod="bb")
public User getById(@PathVariable Long id){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return this.userService.getById(id);
}
//降级方法
public User bb(@PathVariable Long id){
return new User();
}
6,请求结果
服务熔断也称服务隔离,是服务降级的隔离措施。
在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。
开启熔断时机:
当一个规定时间窗口内,请求超时故障比率达到一个阈值,会开启熔断。
熔断恢复:
当过了设置的休眠期后,进入半开状态,允许一定的请求通过。
熔断器有三个状态:open 状态说明打开熔断,也就是服务调用方执行本地降级策略,不进行远程调用。closed 状态说明关闭了熔断,这时候服务调用方直接发起远程调用。half-open 状态,则是一个中间状态,当熔断器处于这种状态时候,直接发起远程调用。
案例:
请求方法设置
@GetMapping("/{id}")
@HystrixCommand(fallbackMethod="aa",
commandProperties = {
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),//请求阈值
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),//休眠时间
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60")//降级百分比
})//降级调用方法设置 熔断设置
public Order getById(@PathVariable Long id) {
Order order = this.orderService.getById(id);
/**
* http://user-service/user/ 其中user-service为动态表填写的应用名称
* 会从注册中心拉取该名称的列表 为一个集合 会走负载策略 轮询等 访问不同服务
*/
if(id==101){
throw new RuntimeException("降级");
}
User user = restTemplate.getForObject("http://user-service/user/" + order.getUserId(), User.class);
order.setUser(user);
return order;
}
当请求编号102时,显示正确数据。
当请求101时,会进行降级,返回null数据。
重复请求101次数为请求阈值的降级百分比次数(10*60%)时,会进行休眠。
请求102时,也为null数据。
休眠10秒结束后,重新请求,数据为正确数据。
Feign 可以把 Rest 的请求进行隐藏,伪装成类似 SpringMVC 的 Controller 一样。你不用再自己拼接url,拼接参数等等操作,一切都交给 Feign 去做。
使用Feign之前
@GetMapping("/{id}")
public Order getById(@PathVariable Long id) {
Order order = this.orderService.getById(id);
if(id==101){
throw new RuntimeException("降级");
}
User user = restTemplate.getForObject("http://user-service/user/" + order.getUserId(), User.class);
order.setUser(user);
return order;
}
使用之后
@Autowired
private UserFeignApi userFeignApi;
@GetMapping("/{id}")
public Order getById(@PathVariable Long id) {
Order order = this.orderService.getById(id);
User user = userFeignApi.getById(order.getUserId());
order.setUser(user);
return order;
}
依赖导入
org.springframework.cloud
spring-cloud-starter-openfeign
新建一个子项目,用来管理feign组件
将该组件进行pom依赖导入需要该组件的pom中,其他子项目即可使用该项目组件。
com.zbx
cloud_demo_comms
1.0-SNAPSHOT
feign子项目中客户端接口编写
//配置请求地址 从注册中心中拉取order-service
@FeignClient(value = "order-service")
public interface OrderFeignApi {
@GetMapping("/order/{id}")
public Order getById(@PathVariable Long id);
}
相当于请求的地址通过feign去请求,只需要编写客户端接口,给定设置请求地址,从注册中心去拉取服务,然后再需要的地方注入该接口,调用方法即可。
案例:请求Order之后请求User,请求user时通过Feign进行服务降级与服务熔断。
1,user与order导入openFeign依赖
org.springframework.cloud
spring-cloud-starter-openfeign
2,Order启动类
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker//开启熔断注解
@EnableFeignClients//开启Feign
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class,args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
3,user启动类
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
@EnableFeignClients//开启Feign
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class,args);
}
}
4,order配置文件application.yaml
feign:
hystrix:
enabled: true # 开启Feign的熔断功能
user-service: #配置负载均衡
ribbon: # 改默认轮询为随机
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
5,user配置文件application.yaml
feign:
hystrix:
enabled: true # 开启Feign的熔断功能
6,orderController
@Autowired
private UserFeignApi userFeignApi;
@GetMapping("/{id}")
public Order getById(@PathVariable Long id) {
Order order = this.orderService.getById(id);
User user = userFeignApi.getById(order.getUserId());
order.setUser(user);
return order;
}
7,userFeignApi
//配置请求地址 从注册中心中拉取user-service value为服务实例id
@FeignClient(value = "user-service",fallback = UserFeignApiCallBack.class)
public interface UserFeignApi {
//user为controller映射地址
@GetMapping("/user/{id}")
public User getById(@PathVariable Long id);
}
8,UserFeignApiCallBack
@Component
@Log4j2
public class UserFeignApiCallBack implements UserFeignApi {
@Override
public User getById(Long id) {
log.warn("降级");
return new User();
}
}
9,访问user id为1
访问其他