Hystrix (一)降级

一、Hystrix介绍

1、简介

Hystrix是一个容错和限流工具组件。Hystrix主要具备服务降级、服务熔断和服务监控等的功能。

其中容错是依靠降级,限流是通过熔断。

2、原理

当某个服务单元发生故障之后,通过断路器的故障监控,向调用方返回一个错误相应,而不是长时间等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中蔓延。

3、降级介绍

如果请求后台服务出错,就会执行另一段代码,向客户端返回结果。降级的响应结果可以是错误信息,也可以是缓存数据。

4、熔断介绍

当服务压力过大,或者错误比例过多时,熔断所有请求,所有请求直接降级。一台服务器故障,可能造成雪崩效应。熔断可以快速断开故障服务,保护其他服务不受影响。

二、Hystrix降级

1、项目准备

创建一个maven项目模块

整个项目结构大致为两个商品模块(集群),一个用户模块,一个订单模块,并且分别将其注册到两个Eureka服务器中。

Hystrix (一)降级_第1张图片

 

 

2、配置ribbon

由于ribbon和hystrix一般会同时出现,所以这里全都单独使用

Hystrix (一)降级_第2张图片

 

首先配置ribbon环境,可以参考Ribbon(一)和Ribbon(二)两篇文章

Ribbon(一)远程调用RestTemplate_바 보71的博客-CSDN博客

Ribbon(二)负载均衡和重试_바 보71的博客-CSDN博客

以下单独提出配置Ribbon的部分

(1)添加依赖

分别添加Eureka依赖、Ribbon依赖和retry依赖



	org.springframework.cloud
	spring-cloud-starter-netflix-eureka-client




	org.springframework.cloud
	spring-cloud-starter-netflix-ribbon




	org.springframework.retry
	spring-retry

由于Eureka中已经包含了Ribbon的负载均衡,所以Ribbon的依赖可以不添加

(2)编辑yml

服务名称先为ribbon,后续修改为hystrix

并且配置retry


spring:
  application:
    name: ribbon
    
server:
  port: 3001
  
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka


ribbon:
  #单台服务器的重试次数
  MaxAutoRetries: 1
  #更换服务器次数
  MaxAutoRetriesNextServer: 2
  OkToRetryOnAllOperations: true
  #OkToRetryOnAllOperations 是否对所有类型请求都重试,默认只对GET重试
 

(3)编辑主程序

添加@EnableDiscoveryClient注解

添加RestTemplate实例,并且设置超时时间等属性

在RestTemplate实例上添加注解@LoadBalanced


package cn.tedu.sp06;
 
...
 
@EnableDiscoveryClient //都是能够让注册中心能够发现,扫描到改服务
@SpringBootApplication
public class Sp06RibbonApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(Sp06RibbonApplication.class, args);
    }
 
    //创建 RestTemplate 实例,并存入 spring 容器
    @LoadBalanced
    //@LoadBalanced 负载均衡注解,会对 RestTemplate 实例进行封装,创建动态代理对象,并切入(AOP)负载均衡代码,把请求分发到集群中的服务器
    @Bean
    public RestTemplate restTemplate() {
        SimpleClientHttpRequestFactory f = new SimpleClientHttpRequestFactory();
        //设置超时时间1s
        //连接已建立并发送请求,等待响应结果的超时时间
        f.setReadTimeout(1000);
        //建立连接等待超时时间为1s
        f.setConnectTimeout(1000);
        return new RestTemplate(f);
 
 
        //RestTemplate 中默认的 Factory 实例中,两个超时属性默认是 -1,
        //未启用超时,也不会触发重试
        //return new RestTemplate();
    }
}

(4)编辑RibbonController


package cn.tedu.sp06.controller;
 
...
 
@RestController
public class RibbonController {
	@Autowired
	private RestTemplate rt;
	
	@GetMapping("/item-service/{orderId}")
	public JsonResult> getItems(@PathVariable String orderId) {
	    //这里服务器路径用 service-id 代替,ribbon 会向服务的多台集群服务器分发请求
		return rt.getForObject("http://item-service/{1}", JsonResult.class, orderId);
	}
 
	@PostMapping("/item-service/decreaseNumber")
	public JsonResult decreaseNumber(@RequestBody List items) {
		return rt.postForObject("http://item-service/decreaseNumber", items, JsonResult.class);
	}
 
	//
	
	@GetMapping("/user-service/{userId}")
	public JsonResult getUser(@PathVariable Integer userId) {
		return rt.getForObject("http://user-service/{1}", JsonResult.class, userId);
	}
 
	@GetMapping("/user-service/{userId}/score") 
	public JsonResult addScore(
			@PathVariable Integer userId, Integer score) {
		return rt.getForObject("http://user-service/{1}/score?score={2}", JsonResult.class, userId, score);
	}
	
	//
	
	@GetMapping("/order-service/{orderId}")
	public JsonResult getOrder(@PathVariable String orderId) {
		return rt.getForObject("http://order-service/{1}", JsonResult.class, orderId);
	}
 
	@GetMapping("/order-service")
	public JsonResult addOrder() {
		return rt.getForObject("http://order-service/", JsonResult.class);
	}
}

3、配置Hystrix

(1)修改pom.xml

将上一步创建的项目名称改为hystrix (可选)

Hystrix (一)降级_第3张图片

添加hystrix的依赖


	org.springframework.cloud
	spring-cloud-starter-netflix-hystrix

(2)编辑yml

修改服务名称为hystrix

添加hystrix超时设置

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds

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
  #OkToRetryOnAllOperations 是否对所有类型请求都重试,默认只对GET重试
  

#hystrix等待超时后, 会执行降级代码, 快速向客户端返回降级结果, 默认超时时间是1000毫秒
#为了测试 hystrix 降级,我们把 hystrix 等待超时设置得非常小(500毫秒)
#此设置一般应大于 ribbon 的重试超时时长,例如 10 秒
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 500

(3)修改主程序

添加@EnableCircuitBreaker注解

通过@EnableCircuitBreaker注解可以启用hystrix容器

当主程序中同时存在@EnableCircuitBreaker、@EnableDiscoveryClient、和@SpringBootApplication三个注解时,可以通过@SpringCloudApplication注解代替

package cn.tedu.sp06;

import ...;

//@EnableCircuitBreaker  //启用 hystrix 断路器
//@EnableDiscoveryClient //都是能够让注册中心能够发现,扫描到改服务
//@SpringBootApplication

@SpringCloudApplication //可以使用 @SpringCloudApplication 注解代替三个注解
public class Sp06RibbonApplication {

    public static void main(String[] args) {
        SpringApplication.run(Sp06RibbonApplication.class, args);
    }

    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        SimpleClientHttpRequestFactory f = new SimpleClientHttpRequestFactory();
        //设置超时时间1s
        f.setReadTimeout(1000);
        f.setConnectTimeout(1000);
        return new RestTemplate(f);


    }
}

(4)RibbonController中添加降级方法

为其中的方法添加@HystrixCommand注解,指定降级方法,格式为:

@HystrixCommand(fallBackMethod="降级方法名称")

添加具体的降级方法,例如getItems()的降级方法为getItemsFB()

方法名称可以随意,这里为了区分两种方法,并且返回结果为错误信息

package cn.tedu.sp06.controller;

import ...;


@RestController
@Slf4j
public class RibbonController {

    @Autowired
    private RestTemplate rt;

    //为每个方法添加降级方法:方法名FB()
    //添加@HystrixCommand 注解,指定降级方法名


    
    @GetMapping("/item-service/{orderId}")
    @HystrixCommand(fallbackMethod = "getItemsFB") //指定降级方法的方法名
    public JsonResult> getItems(@PathVariable String orderId) {
        // 调用远程 02项目,获取商品列表

        //{1},{2}是RestTamplate提供的一种占位符

        //RestTemplate必须给出具体的服务器地址
        //Ribbon对RestTemplate进行了增强,提供负载均衡的功能
        //根据注册表的主机地址列表,做负载均衡访问
        return rt.getForObject(
                "http://item-service/{1}",//给出具体服务器的地址
                JsonResult.class,
                orderId);
    }

    
    @PostMapping("/item-service/decreaseNumber")
    @HystrixCommand(fallbackMethod ="decreaseNumberFB")
    public JsonResult decreaseNumber(@RequestBody List items) {
        return rt.postForObject(
                "http://item-service/decreaseNumber",
                items,
                JsonResult.class);
    }

    //

    
    @GetMapping("/user-service/{userId}")
    @HystrixCommand(fallbackMethod ="getUserFB")
    public JsonResult getUser(@PathVariable Integer userId) {
        return rt.getForObject(
                "http://user-service/{1}",
                JsonResult.class,
                userId);
    }

    
    @GetMapping("/user-service/{userId}/score")
    @HystrixCommand(fallbackMethod ="addScoreFB")
    public JsonResult addScore(@PathVariable Integer userId, Integer score) {
        return rt.getForObject(
                "http://user-service/{1}/score?score={2}",
                JsonResult.class,
                userId, score);
    }

    //

    
    @GetMapping("/order-service/{orderId}")
    @HystrixCommand(fallbackMethod ="getOrderFB")
    public JsonResult getOrder(@PathVariable String orderId) {
        return rt.getForObject(
                "http://order-service/{1}",
                JsonResult.class,
                orderId);
    }

    
    @GetMapping("/order-service")
    @HystrixCommand(fallbackMethod ="addOrder")
    public JsonResult addOrder() {
        return rt.getForObject("http://order-service/",
                JsonResult.class);
    }

    //

    //降级方法的参数和返回值,需要和原始方法一致,方法名任意
    public JsonResult> getItemsFB(String orderId) {
        return JsonResult.err("获取订单商品列表失败");
    }
    public JsonResult decreaseNumberFB(List items) {
        return JsonResult.err("更新商品库存失败");
    }
    public JsonResult getUserFB(Integer userId) {
        return JsonResult.err("获取用户信息失败");
    }
    public JsonResult addScoreFB(Integer userId, Integer score) {
        return JsonResult.err("增加用户积分失败");
    }
    public JsonResult getOrderFB(String orderId) {
        return JsonResult.err("获取订单失败");
    }
    public JsonResult addOrderFB() {
        return JsonResult.err("添加订单失败");
    }



}

(5)项目结构图

Hystrix (一)降级_第4张图片

(6)测试项目

将user-serivce和order-service服务断开,访问会执行对应的降级方法

Hystrix (一)降级_第5张图片 

 在item-service中编写了可能会超时的代码,所以两种结果,成功访问会获取商品信息,失败则执行降级方法

Hystrix (一)降级_第6张图片

 

你可能感兴趣的:(Hystrix,java,spring,cloud,开发语言)