zeus00456

导航

微服务架构 | 服务隔离 - [Hystrix]

@

§1 简介

Hystrix 是由 Netflix 开源的一个服务隔离组件,通过服务隔离来避免由于依赖延迟、异常,引起资源耗尽导致系统不可用的解决方案。
服务隔离是一个双端(提供方和调用方)都可进行的行为

§2 服务的熔断、降级、限流

服务雪崩
当一个比较底层的服务不可用时,所有依赖此服务的服务都可能不可用,依赖这些服务的服务也会受影响导致不可用。这种一个服务牵连一片服务不可用的情况,称为服务雪崩。

下面情况可能导致服务雪崩:

  • 使服务节点彻底不能提供服务的情况
    • 服务硬件故障,比如硬盘炸了
    • 程序 bug
  • 占用服务资源导致不能及时提供服务的情况
    • 超出系统能力的并发,比如秒杀时的海量请求并发
    • 系统资源耗尽,比如缓存击穿导致的持久化层连接池耗尽
    • 重试占用资源,因服务不稳定或用户刷新导致的业务重试占用过多系统资源

服务熔断
当服务中的服务端接口不稳定,出现频繁超时或错误时,可能会引起服务调用雪崩。服务熔断使有故障的服务端及时返回错误,并释放系统资源,提高用户体验和系统性能
熔断会在架构层级屏蔽被熔断的服务,直到满足一定条件再将其恢复

服务降级
当服务器压力剧增的情况下,根据实际业务情况及流量,对某些不重要的服务,不处理或换种简单的方式处理,从而释放服务器资源以保证核心业务正常运作或高效运作
服务降级不会使服务内部的逻辑不可访问,只是在其不能满足预期时快速响应。
服务降级是双端的,既可以在服务提供方也可以在消费方进行。
这是因为二者都有提供降级的必要:
当服务提供方因自身或其依赖服务异常导致了自身异常/超时时,可以自我限定自己提供服务的响应时长以免调用方等待
当服务消费方因自身和提供方之间的网络出现异常时,服务提供方的降级很可能不会生效(因为可能就没有成功调用,而是请求从调用方出发接着就迷路了),这可能导致消费方很长时间收不到任何响应,因此也需要自己进行降级

服务限流
只允许指定数量的事务进入系统处理,超过的部分将被拒绝服务,排队或者降级处理

什么时候要考虑服务隔离

  • 服务提供方超时
  • 服务提供方不可用
  • 服务调用方相比提供方更高的要求,比如设计上服务3秒返回,但调用方需要1秒

§3 使用

依赖

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

§3.1 服务降级(fallback)

通用配置
启动类
需要 @EnableCircuitBreaker

@SpringBootApplication
@MapperScan
@EnableEurekaClient
@EnableCircuitBreaker
public class PaymentProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(PaymentProviderApplication.class,args);
    }
}

项目全局配置
消费端可以通过如下配置快速开启 Hystrix 支持

feign:
  hystrix:
    enabled: true

但是,这样开启属于全局配置,相当于给所有 FeignClient 接口都添加了服务隔离配置
默认的全局配置绑定了一个 1 秒的超时(大坑),因此实际项目中还需要结合其他全局配置

feign:
  hystrix:
    enabled: true
  client:
    config:
      default:
        connect-timeout: 100000
        read-timeout: 100000

hystrix:
  command:
    default:  #default全局有效,service id指定应用有效
      execution:
        timeout:
          #如果enabled设置为false,则请求超时交给ribbon控制,为true,则超时作为熔断根据
          enabled: true
        isolation:
          thread:
            timeoutInMilliseconds: 10000 #断路器超时时间,默认1000ms

接口单独配置
可以在 openService(对外接口,可以理解成 controller) 上进行

@RequestMapping(value = "/wait/{time}", method = RequestMethod.GET)
@HystrixCommand(fallbackMethod = "waitTimeoutFallback",commandProperties = {
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
@ResponseBody
public CommonResult<String> waitTimeout(@PathVariable("time") Integer time) {
    try {
        inti = 0;
        if(0==time)
            i = 1/0;
        else
            TimeUnit.SECONDS.sleep(time);
    } catch (InterruptedException e) {
        log.error("等待中断 {}",time ,this.serverPort, e);
        return new CommonResult<>(400,"等待中断" + this.serverPort);
    }
}

private CommonResult<String> waitTimeoutFallback(Integer time){
    return new CommonResult<>(400,"wait ...... ......" + this.serverPort);
}

也可以在 service/FeignClient 上进行

@HystrixCommand(fallbackMethod = "waitTimeoutFallback",commandProperties = {
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
@Override
public String waitTimeout(Integer time){
    try {
        TimeUnit.SECONDS.sleep(time);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "wait success";
}

private String waitTimeoutFallback(Integer time) {return "wait ... ... ...";}

效果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意事项
fallbackMethod 需要返回值和参数表与原接口一致,方法名使用 fallbackMethod 指定标识符

服务全局配置
配置服务全局 fallback 方法

@DefaultProperties(defaultFallback = "waitTimeoutFallbackGlobal")
public class OrderFeignHystrixController {
}

@HystrixCommand(commandProperties = {
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
//@HystrixCommand
public String waitTimeout(@PathVariable("time") Integer time){
}

public String waitTimeoutFallbackGlobal(){
    return"order wait global...... ......";
}

注意:

  • 服务全局 fallback 方法必须是无参数的
  • 指定服务全局 fallback 方法后,接口的降级条件依然要进行配置,否则使用默认的(比如1秒超时)

配置服务 fallback 类
配置形式如下

@FeignClient(value = "PAYMENT-SERVICE-HYSTRIX",fallback = PaymentOpenfeignClientFallback.class)
public interface PaymentOpenfeignClient {
}

@Component
public class PaymentOpenfeignClientFallback implements PaymentOpenfeignClient{
}

需注意,配置 fallback 类需要开启 项目全局配置

feign:
  hystrix:
    enabled: true

同时,上述配置造成的问题,比如1秒的全局超时,需要其他全局配置补充

§3.2 服务熔断 (circuitBreaker)

服务熔断的状态
在这里插入图片描述

  1. 断路器默认是 closed 状态
  2. 在一定的访问阈值内,断路器不会进行判断
  3. 访问量达到阈值后,断路器会监控服务访问状态,若单位时间内访问失败达到一定比例会触发熔断
  4. 当触发熔断后,会切换到 open 状态,断路器打开后,所有访问断路器上服务的请求都会被拒绝
  5. 一定的时间后,断路器会切换到 half open 状态,此状态会放行少量的请求
  6. 若请求成功,断路器关闭;否则再切换回 open 状态,再持续一定的时间

开启熔断
熔断需要开启 项目全局配置

feign:
  hystrix:
    enabled: true

接口熔断配置

@RequestMapping(value = "/wait/{time}", method = RequestMethod.GET)
@HystrixCommand(fallbackMethod = "waitTimeoutFallback",commandProperties = {
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "5000"),
        @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),// 是否开启断路器
        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),// 请求次数
        @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "20000"), // 时间窗口,若断路器打开,窗口期开始时少量放行请求,若通过,断路器关闭否则再持续一个窗口期
        @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60")// 失败率达到多少后跳闸
})
@ResponseBody
public CommonResult<String> waitTimeout(@PathVariable("time") Integer time) {
}

配置详解:

  • circuitBreaker.enabled 是否开启熔断
  • circuitBreaker.requestVolumeThreshold 请求容积阈值,请求数量不够不涉及熔断的判断
  • circuitBreaker.sleepWindowInMilliseconds 睡眠窗口,熔断后,断路器会在此窗口时长中拒绝所有请求,直到下一个窗口放行少量,根据其访问是否失败决定关闭断路器还是继续睡一个窗口时长
  • circuitBreaker.errorThresholdPercentage 触发断路的失败百分比

TODO
熔断中涉及的概念()
MTTR、MTBF、MTTF

§3.3 常见问题

正确配置了 @HystrixCommand 注解,但就是不能触发 fallback
希望触发 fallback 的异常最终一定要抛出,若进行捕获后组织返回信息,即使里面夹带异常信息也是正常返回的范畴,不会触发 fallback

§4 注解

§5 Dashboard

依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

启动类

@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardApplication {
    public static void main(String[] args) {
        SpringApplication.run(HystrixDashboardApplication.class,args);
    }
}

服务配置
被监控的服务上添加配置

@Bean
public ServletRegistrationBean getServlet() {
    HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
    ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
    registrationBean.setLoadOnStartup(1);
    registrationBean.addUrlMappings("/hystrix.stream");
    registrationBean.setName("HystrixMetricsStreamServlet");
    return registrationBean;
}

访问
http://ip:port/hystrix
在这里插入图片描述
在这里插入图片描述


传送门:
微服务架构 | 组件目录

posted on 2022-07-28 15:45  问仙长何方蓬莱  阅读(104)  评论(0编辑  收藏  举报