Spring Cloud :4 . Hystrix 降级、熔断、隔离

简介

在项目上线后,微服务之间相互调用,不可能一点问题都不出。如果出了问题,请求超时,应该怎么去解决?

首先请求超时可能会发生在两个阶段:

  1. 在客户端和服务器端建立连接的时候。
  2. 服务器端在处理业务逻辑的时候。

超时的时候,客户端不可能一直无限等待,这个时候如果有其他Client调用该服务,由于当前provider处理过慢,导致请求的淤积,久而久之这个服务的资源占用就会达到瓶颈而Down掉,微服务和微服务之间调用,其中一个微服务Down可能会导致整个服务链不可用,就会引起严重的服务雪崩。

Hystrix 就是解决微服务 与 微服务 之间互相调用的时候出现问题的解决方案,包含降级,熔断,和限流(隔离)!

  • 降级:因为网络抖动,发生异常等原因,对连接或业务逻辑处理的超时,返回一个 可以接受 的结果!(服务调用方发起的自我保护机制,为了保证主业务不受影响,跳过调用持续报错,返回一个可以接受的结果,可以把这动态开关配置在配置中心)

降级的另外一种解释:在高并发期间主动下线那些非核心的流程,给主业务让路。

  • 熔断:在一个时间窗内,多次请求一个服务的连续失败次数达到阈值,就会触发熔断,关闭对该服务的访问,直接调用降级方法。(服务提供方,发起的一个自我保护机制。触发机制可以是访问人数,错误次数,超时时间等)
  • 限流:一个服务可能是有多个子服务组成,对每个子服的调用进行限流(限制线程数量 -> 线程池/信号量),避免了某个子服务占用了太多的资源而影响其他子服务的调用。

降级的目的不是快速 返回服务不可用,而是返回一个 兜底数据(凑合能用,服务可用)

自己写一个Hystrix的思路

	 /**
     *
     *  try{
     *
     *      1.发起向服务方的请求
     *          1.1 判断是否超时
     *              ——> 这次请求记录到服务里(一个时间片内,feign不会再请求这个服务)
     *          1.2 尝试向其他服务器发送请求
     *          其他服务器依然没有成功     -> 抛出异常(降级代码)
     *
     *
     *      限流:(使用在provider端,对每个服务限流,一个服务的爆满 不会 影响其他服务,对服务进行隔离)
     * 				调用http请求会消耗线程,每个http请求调动服务都会开启一个线程,容易引起服务淤积导致服务雪崩。
     *         		 可以使用两种方式:   1.使用map(URI,线程数量)       2.线程池(线程数)
     *               if(线程数满了){
     *                   throw exception; 降级(及快速的失败)
     *               }
     *
     *      熔断: 对请求失败做计数( count++ )
     *                if(count>阈值){
     * 						熔断状态:开|关|半开	-> 半开:设置时间片,请求成功则重置count
     *                    throw exception;降级(及快速的失败)
     *                }
     *
     *  }catch(Exception e){
     *
     *      降级方案:
     *          1.返回一个友好的页面。  -> 好看点的页面,重试按钮
     *          2.返回另一个东西       -> 写到 mq 里
     *      return " 客户端稍后再来"
     *  }
     *
     *
     */

如果要把try…catch升级,可以使用aop来做,对RestTemplate进行代理包装,更方便的方式是包装成注解的方式。

降级解决了什么问题? 释放资源,不影响其他服务

Hystrix整合Feign搭建

Hystrix整合Feign有两种方式搭建:

在Consumer端 引入hystrix包:

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

配置文件开启对Hystrix的支持:

#对 hystrix 的支持
feign.hystrix.enabled=true
fallback方式

@FeignClient注解上添加CallBack属性:

//FeignProviderCallBack类要交给SpringIOC管理,不然无法加载到
@FeignClient(name = "open-feign-provider",fallback = FeignProviderCallBack.class)	
public interface UesrApiProxy extends UserAPI {		//UserAPI 为公共接口,可看上一张Feign的搭建
}

创建 FeignProviderCallBack 类,并实现UesrApiProxy 接口:

@Component	//交给SpringIOC
public class FeignProviderCallBack implements UesrApiProxy{ //这里踩坑了,实现的是标有@FeignClient的接口,而不是UserAPI 

    @Override
    public String alive() {
        return "降级了";
    }

    @Override
    public String post(String name) {
        return null;
    }
}

触发降级,可能是连接超时,也有可能是服务处理超时异常.
如果想根据不同的异常对前端返回不同的信息,可以使用 fallbackFactory 的方式来实现。

fallbackFactory方式

修改@FeignClient注解的属性:

//@FeignClient(name = "open-feign-provider",fallback = FeignProviderCallBack.class)
@FeignClient(name = "open-feign-provider",fallbackFactory = FeignProviderCallBackFactory.class)
public interface UesrApiProxy extends UserAPI {
}

创建FeignProviderCallBackFactory类,并实现 FallbackFactory 接口

@Component		//在实现FallbackFactory接口的同时要给出泛型,@FeignClient的标记类
public class FeignProviderCallBackFactory implements FallbackFactory<UesrApiProxy> { 
    @Override		//这里会获取错误信息(包含本地和远端的异常),降级时,此方法会被回调
    public UesrApiProxy create(Throwable throwable) {	
        return new UesrApiProxy() {
            @Override
            public String alive() {
                System.out.println(throwable.getMessage());
                return "使用FallbackFactory降级";
            }

            @Override
            public String post(String name) {
                return null;
            }
        };
    }
}

Hystrix整合RestTemplate搭建

首先再启动类上添加注解 @EnableCircuitBreaker ,并且把RestTemplate注入到 IOC 容器:

@SpringBootApplication
@EnableFeignClients     //如果需要使用feign发起远程调用,需要添加这个注解
@EnableCircuitBreaker	//Hystrix整合RestTemplate需要添加此注解才能正常使用
public class OpenFeignConsumer90Application {

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

    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

建立Service层里添加 @HystrixCommand注解指定降级,虽然也可以把降级代码直接写到Controller层,但是不建议这样做:

@Service
public class RestService {

    @Autowired
    private RestTemplate restTemplate;

    private final String URL_USER_PROVIDER="http://open-feign-provider/";
	//指定降级方法
    @HystrixCommand(fallbackMethod = "aliveFallBack")
    public String alive(){

        return restTemplate.getForObject(URL_USER_PROVIDER+"alive",String.class);
    }
	//降级方法
    public String aliveFallBack(){
        return "RestTemplate整合Hystrix降级了";
    }
}

Controller层调用:

    @Autowired		//注入之前建立的Service
    private RestService restService;
    @GetMapping("/restHystrix")
    public String restHystrix(){
        return restService.alive();
    }

provider端代码:

    @Override
    public String alive() {
		//除0异常
        int j= 5/0;

        int i = count.getAndIncrement();
        System.out.println("====坏的第:" + i + "次调用");
        return "port:" + port;
    }

访问结果:

在这里插入图片描述

线程池隔离与信号量隔离

Hystrix 对每个URI 进行限流 达到隔离的效果,一共有两种方式:

  • 线程池隔离(官方推荐)
  • 信号量隔离 Semaphore

在这里插入图片描述

线程池隔离技术,是用 Hystrix 自己的线程去执行调用;而信号量隔离技术,是直接让 tomcat 线程去调用依赖服务。信号量隔离,只是一道关卡,信号量有多少,就允许多少个 tomcat 线程通过它,然后去执行。

信号量隔离主要维护的是Tomcat的线程,不需要内部线程池,更加轻量级。

线程池方式的优点:

  1. 失败策略更灵活。
  2. 可以做异步,让Tomcat的worker线程可以做更多的事情。
  3. 线程池内部的,异常的隔离

适合IO密集型,并发异步执行,可以提高效率

信号量什么时候使用?

  1. 代码健壮,几乎没有bug。
  2. 计算密集型,响应特别快

在以上两种情况中,如果使用线程池,反而需要增加维护线程池的成本

# thread 通过线程数量来限制并发请求数,可以提供额外的保护,但有一定的延迟。一般用于网络调用
# semaphore 通过semaphore count来限制并发请求数,适用于无网络的高并发请求
# 隔离策略,默认是Thread, 可选Thread|Semaphore
hystrix.command.default.execution.isolation.strategy

# 命令执行超时时间,默认1000ms
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds

# 执行是否启用超时,默认启用true
hystrix.command.default.execution.timeout.enabled

# 发生超时是是否中断,默认true
hystrix.command.default.execution.isolation.thread.interruptOnTimeout 

# 最大并发请求数,默认10,该参数当使用ExecutionIsolationStrategy.SEMAPHORE策略时才有效。如果达到最大并发请求数,请求会被拒绝。理论上选择semaphore size的原则和选择thread size一致,但选用semaphore时每次执行的单元要比较小且执行速度快(ms级别),否则的话应该用thread。

#semaphore应该占整个容器(tomcat)的线程池的一小部分。
hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests 

dashboard监控

添加依赖:

        <!--图形界面-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>
                spring-cloud-starter-netflix-hystrix-dashboard
            </artifactId>
        </dependency>
        <!--actuator监控-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

配置文件:

management.endpoints.web.exposure.include=*

在启动类上添加@EnableHystrixDashboard注解:

@SpringBootApplication
@EnableFeignClients     //如果需要使用feign发起远程调用,需要添加这个注解
@EnableCircuitBreaker       //开启熔断
@EnableHystrixDashboard   //开启Hystrix整合Dashboard
public class OpenFeignConsumer90Application {

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

    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

健康检查:

localhost:90/actuator/hystrix.stream

dashboard图形化界面:

在这里插入图片描述
点击 Monitor Stream :

在这里插入图片描述


这篇文章是本人的个人理解,不保证准确性,如果有错误的地方希望大家留言指正,一起学习共同进步!
如果转载请标明出处。谢谢

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Cloud Hystrix是一个开源的熔断器框架,它能够帮助开发者有效地处理服务依赖中的延迟和故障。熔断器的主要目的是在出现故障时提供一种优雅的降级机制,以避免整个系统的崩溃。 熔断降级Hystrix中两个重要的概念。 熔断(Circuit Breaker)指的是在服务出现故障或错误率过高时,自动地切换到指定的备用服务或返回事先定义好的错误结果,起到保护系统免受故障传播的影响的作用。当服务不可用或响应时间过长时,熔断器会打开,拒绝后续请求的访问,并尝试通过执行降级逻辑来快速响应客户端。一旦后续请求不再出现故障,熔断器将会进入半开状态,允许少量的请求通过以检测服务是否恢复正常。 降级(Degradation)指的是在系统资源不足或者高访问量时,服务降级会关闭一些不重要的功能,以保证系统核心功能的可用性和稳定性。降级可以通过阻止非必要的调用、减少资源的消耗以及返回默认值或缓存结果来实现。降级需要提前定义好一些备用的逻辑,一旦系统资源紧张,就可以立即启用降级逻辑来保障系统的可用性。 总而言之,熔断降级都是为了保护系统免受故障的影响。熔断主要是针对服务故障和错误率过高的情况,通过切换到备用服务或返回错误结果来保护系统。降级主要是在系统资源紧张或高访问量的情况下,关闭一些不重要的功能来保证核心功能的可用性和稳定性。两者都是通过提前定义备用逻辑来保障系统的正常运行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值