4-Spring Cloud微服务快速搭建-Hystrix&Sentinel熔断降级(解决熔断雪崩)

修订日期 内容
2021-2-22 初稿

简述

什么是雪崩?

在微服务架构中服务之间会相互调用,如果一个服务不能及时响应,将会导致其他服务阻塞,若此时大量请求涌入将会导致容器的线程资源耗尽,导致服务瘫痪。服务与服务之前的依赖性将会造成连锁反应,造成严重后果,这种故障称之为”雪崩“。

什么时熔断降级?

类似家庭电路中的保险丝,当电流过大时,保险丝会熔化(这就是我们说到的跳闸,小时候电压不稳,家里用到大功率电器时常常会遇到),而不会影响到其他家庭的用电。这种为了保护整体服务可用性而做出的局部牺牲叫做”熔断降级“。

Hystrix如何实现熔断降级?

主要通过如下几点实现熔断降级

  1. 跳闸机制:当错误率达到一定的阈值时,自动跳闸,停止该请求一段时间。
  2. 回退机制:当断路时,执行回退逻辑,回退逻辑由开发人员自己定义,如返回一个默认值。
  3. 自我修复:当断路一段时间后,自动”半开"状态,尝试让一部分请求进入。

Hystrix项目整合

在RestTemplate中使用Hystrix

整合步骤

1.引入maven依赖

<!-- 引入hystrix-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

2.注解激活hystrix@EnableCircuitBreaker

@SpringBootApplication
// 激活客户端 ,新版本可以省略
//@EnableEurekaClient,@EnableDiscoveryClient
// 激活feign调用
@EnableFeignClients
@EnableCircuitBreaker
public class OrderServiceApplication {
    
    

    public static void main(String[] args) {
    
    
        new SpringApplicationBuilder(OrderServiceApplication.class).run(args);
    }

	//创建restTemplate,注入springbean容器
    @Bean
    @LoadBalanced  //开启负载均衡
    public RestTemplate restTemplate(){
    
    
        return new RestTemplate();
    }
}

3.开发回退代码逻辑,注意方法参数与返回值与正常方法保持一致

//回退代码逻辑,方法参数与返回值保持一致
public Object queryRollback(Long id){
    
    
        return "触发熔断回退";
}

4.在正常调用的方法中使用注解@HystrixCommand指定回退方法

	@RequestMapping(value = "/query/{id}")
    @HystrixCommand(fallbackMethod = "queryRollback")
    public Object query(@PathVariable Long id){
    
    

		Object obj = restTemplate.getForObject("http://express-service/express/query/"+1, String.class);

        return "查询成功订单ID:"+id+"物流信息:"+obj;
    }

5.其他设置

  • 修改熔断超时时间

    通过以上4步即完成,我们还可以修改hystrix的超时时间,(默认1s)


#指定hystrix熔断方法超时时间,默认1s
hystrix:
  command.default.execution.isolation.thread.timeoutInMilliseconds: 2000

# feign调用超时时间
ribbon:
  ReadTimeout: 3000
  SocketTimeout: 3000
  • 配置统一的降级方法
  1. 删除@HystrixCommand(fallbackMethod = "queryRollback")中指定的fallbackMethod方法,直接使用@HystrixCommand即可
  2. 创建一个统一的降级方法(方法参数与返回值无要求)
public Object defaultFallBack(){
    
    
        return "指定的统一默认defaultFallback方法";
    }
  1. 在类中使用注解@DefaultProperties(defaultFallback = "defaultFallBack")
@RequestMapping("/order2")
@RestController
// 指定统一的降级方法,@HystrixCommand不需要指定降级方法,如果指定将会覆盖默认的降级方法
@DefaultProperties(defaultFallback = "defaultFallBack")
public class Order2Controller {
    
    

	@RequestMapping(value = "/query/{id}/{time}")
    @HystrixCommand
    public Object queryTime(@PathVariable Long id,@PathVariable Integer time){
    
    
        logger.info("queryTime-id:{}",id);

        try {
    
    
            Thread.sleep(time);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

        return "查询成功订单ID:"+id+"本地物流信息:";
    }
}

在Feign中使用Hystrix

关于feign的整合请参考上一篇文章:3-Spring Cloud微服务快速搭建-Feign<OpenFeign>整合

整合步骤

  1. 不需要单独引入Hystrix依赖,因为feign中已经引入hystrix
  2. 配置文件中开启feign对Hystrix的支持,默认关闭
feign:
  # 开启hystrix,默认关闭
  hystrix:
    enabled: true
  1. 在feign接口中实现一个降级的方法
@Component
public class ExpressFeignFallBack implements ExpressFeign {
    
    

    private Logger logger = LoggerFactory.getLogger(ExpressFeignFallBack.class);
    @Override
    public String query(Long id) {
    
    
        logger.info("ExpressFeign-query降级方法id:{}",id);
        return "触发降级方法";
    }
}

4.在feign接口指定降级类fallback的类,指向刚刚创建的类即可

@FeignClient(name = "express-service",fallback = ExpressFeignFallBack.class)
@RequestMapping("/express")
public interface ExpressFeign {
    
    

    @RequestMapping(value = "/query/{id}")
    String query(@PathVariable Long id);
}

测试启动报错(坑点)

测试,启动发现出现如下错误类似这个方法已存在的错误

org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘requestMappingHandlerMapping’ defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration E n a b l e W e b M v c C o n f i g u r a t i o n . c l a s s ] : I n v o c a t i o n o f i n i t m e t h o d f a i l e d ; n e s t e d e x c e p t i o n i s j a v a . l a n g . I l l e g a l S t a t e E x c e p t i o n : A m b i g u o u s m a p p i n g . C a n n o t m a p ′ o r g . c h e n g l j . o r d e r . r e s t . f e i g n . E x p r e s s F e i g n ′ m e t h o d c o m . s u n . p r o x y . EnableWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'org.chenglj.order.rest.feign.ExpressFeign' method com.sun.proxy. EnableWebMvcConfiguration.class]:Invocationofinitmethodfailed;nestedexceptionisjava.lang.IllegalStateException:Ambiguousmapping.Cannotmaporg.chenglj.order.rest.feign.ExpressFeignmethodcom.sun.proxy.Proxy80#query(Long)
to { /express/query/{id}}: There is already ‘expressFeignFallBack’ bean method

坑点解决方案

注意上面的feign接口类上使用了@RequestMapping("/express")注解,
在由熔断降级指定时不能再类上使用该注解,需要做如下调整:

@FeignClient(name = "express-service",fallback = ExpressFeignFallBack.class)
//@RequestMapping("/express") 使用熔断降级时不能子类上使用该注解,完整的注解请再方法中指定
public interface ExpressFeign {
    
    

	//将完整路径url写在方法上
    @RequestMapping(value = "/express/query/{id}")
    String query(@PathVariable Long id);
}

Hystrix替换方案Alibaba Sentinel

由于Sentinel已经不在积极维护
在这里插入图片描述

整合步骤

  • I. Sentinel 提供了两种配置限流规则的方式:代码配置 和 控制台配置。如采用控制台配置
    直接下载:官方下载 Sentinel 控制台
  • II.启动控制台,执行 Java 命令 java -jar sentinel-dashboard.jar完成 Sentinel 控制台的启动。 控制台默认的监听端口为 8080。Sentinel 控制台使用 Spring Boot 编程模型开发,如果需要指定其他端口,请使用 Spring Boot 容器配置的标准方式,详情请参考 Spring Boot 文档

启动控制台后localhost:8080访问即可,默认没有用户名密码
在这里插入图片描述

更多sentinel详细内容请参考官方文档

  1. 在父工程中引入alibaba的相关依赖

如果需要使用 Spring Cloud Hoxton 版本,请在 dependencyManagement 中添加如下内容

            <!-- 引入alibaba相关依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
    <version>2.2.5.RELEASE</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

版本依赖关系请查看官方文档:spring cloud alibaba 依赖关系
在这里插入图片描述

  1. 在子工程中引入sentinel依赖
<!--引入alibaba sentinel依赖-->
  <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  </dependency>
  1. 在配置文件中配置sentinel的控制台地址
cloud:
    # alibaba sentinel 配置控制台地址
    sentinel:
      transport:
        dashboard: localhost://8080
  1. 在调用方法上使用注解@SentinelResource(blockHandler = "",fallback = "")
  • blockHanler:熔断时的降级方法
  • fallback:抛出异常时的降级方法

对Feign的支持

# 开启对sentinel的支持
feign:
  sentinel:
    enabled: true

其他方式与Hystrix保持一致即可

启动报错

Requested bean is currently in creation: Is there an unresolvable circular reference?] with root cause
spring-cloud-starter-alibaba-sentinel:2.2.5.RELEASE

spring cloud:Hoxton.SR10(Hoxton.SR9以下都正常,Hoxton.SR10与2020.x版本都不行)存在这个Bug,看到有人已经提出issue,并且已经确认,到目前为止暂未修复(着急的可以降一下spring cloud版本)
https://github.com/alibaba/spring-cloud-alibaba/issues/1974

对restTemplate的支持

  1. 使用@SentinelRestTemplate
@Bean
    @LoadBalanced //开启负载均衡
    /**
     * 开启sentinel对RestTemplate的支持
     * blockHandler: 熔断限流
     * fallback:异常降级
     */
    @SentinelRestTemplate(blockHandler = "handleException", blockHandlerClass = ExceptionUtils.class)
    public RestTemplate restTemplate(){
    
    
        return new RestTemplate();
    }
  1. 创建异常类
import com.alibaba.cloud.sentinel.rest.SentinelClientHttpResponse;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpResponse;

public final class ExceptionUtils {
    
    
	//方法必须是静态,且参数一定要对应
    public static ClientHttpResponse handleException(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException exception) {
    
    
        return new SentinelClientHttpResponse("熔断限流降级");

    }
}

猜你喜欢

转载自blog.csdn.net/weixin_48470176/article/details/113872819