SpringCloud实战6 - 使用Hystrix实现微服务的容错处理

容错机制

如果服务提供者相应非常缓慢,那么消费者对提供者的请求就会被强制等待,知道提供者相应超时。在高负载场景下,如果不作任何处理,此类问题可能会导致服务消费者的资源耗尽甚至整个系统崩溃。

雪崩效应

微服务架构的应用系统通常包含多个服务层,微服务之间通过网络进行通信,从而支撑起整个应用系统,因此,微服务之间难免存在依赖关系。我们常把“基础服务故障”导致“级联故障”的现象成为雪崩效应。雪崩效应描述的是提供者不可用导致消费者不可用,并将不可用逐步扩大的过程。

如何容错

为了防止雪崩效应,必须有一个强大的容错机制。该容错机制需实现以下两点:

1.为网络请求设置超时

必须为网络请求设置超时。正常情况下,一个远程调用一般在及时毫秒内就能得到响应了。如果依赖的服务不可用或者网络有问题,那么响应时间就会变得特别长。

通常情况下,一次远程调用对应着一个线程/进程。如果响应太慢,这个线程/进程就得不到释放。而线程/进程又对应着系统资源,如果得不到释放的线程/进程约积越多,资源就会逐渐被耗尽,最终导致服务的不可用。

2.使用断路器模式

如果对某个微服务的请求有大量超时(常常说明该微服务不可用),再去让新的请求访问该服务已经没有任何意义,只会无所谓消耗资源。例如,设置了超时时间为1秒,如果短时间内有大量的请求无法在1秒内得到响应,就没有必要再去请求依赖的服务了。

短路器可理解为对容易导致错误的操作的代理。这种代理能够统计一段时间内调用失败的次数,并决定是正常请求依赖的服务还是直接返回。

断路器可以实现快速失败,如果它在一段时间内检测到许多类似的错误(例如超时),就会在之后的一段时间内,强迫对该服务的调用快速失败,即不再请求所依赖的服务。这样,应用程序就无需再浪费cpu时间去等待长时间的超时。

短路器也可自动诊断是否已经恢复正常。如果发现依赖的服务已经恢复正常,那么就会恢复请求该服务。使用这种方式,就可以实现微服务的“自我修复”——当依赖的服务不正常打开断路器时快速失败,从而防止雪崩效应;当发现依赖的服务恢复正常时,又会恢复请求。

 

断路器状态转换逻辑:

- 正常情况下,断路器关闭,可正常请求依赖的服务

- 当一段时间内,请求失败率达到一定阀值(例如错误率达到50%,或100次/分钟等),断路器就会打开。此时,不会再去请求依赖的服务。

- 断路器打开一段时间后,会自动进入“半开”状态。此时,断路器可允许一个请求访问依赖的服务。如果该请求能够调用成功,则关闭断路器;否则继续保持打开状态。

使用Hystrix实现容错 

Hystrix简介 

Hystrix是一个实现了超时机制和断路器模式的工具类库。是由Netfix开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统可用性与容错性。Hystrix主要通过以下几点实现延迟和容错。

  • 包裹请求:使用HystrixCommand(或者HystrixObservableCommand)包裹对依赖的调用逻辑,每个命令在独立线程中执行。这使用了设计模式中的“命令模式”。
  • 跳闸机制:当某服务的错误率超过一定阀值时,Hystrix可以自动或者手动跳闸,停止请求该服务一段时间。
  • 资源隔离:Hystrix为每个依赖都维护了一个小型的线程池(或者信号量)。如果该线程池已满,发往该依赖的请求就被立即拒绝,而不是排队等候,从而加速失败判断
  • 监控:Hystrix可以近乎实时地监控运行指标和配置的变化,例如成功、失败、超时、以及被拒绝的请求等。
  • 回退机制:当请求失败、超时、被拒绝,或当断路器打开时,执行回退逻辑。回退逻辑可由开发人员自行提供,例如返回一个缺省值。
  • 自我修复:断路器打开一段时间后,会自动进入“半开”状态。

通用方式整合Hystrix 

   在Springcloud中,整合Hystrix非常方便,我们以ribbon-consumer项目为例

   添加如下依赖

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

   在启动类添加注解 @EnableHystrix //开启断路器功能

@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix //开启断路器功能
public class YmkRibbonConsumerApplication {

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

    //	开启客户端负载均衡
    @LoadBalanced
    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

   修改控制器代码,让hello方法具有容错能力。   

@RestController
public class HelloController {

    @Autowired
    RestTemplate restTemplate;
    @Autowired
    private LoadBalancerClient loadBalancerClient;

//  HystrixCommand具有容错能力  fallbackMethod属性指定回退方法
    @HystrixCommand(fallbackMethod = "helloFallBack")
    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String hello(@RequestParam String name) {
        ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://provider/hello?name={1}", String.class,name);
        return responseEntity.getBody();
    }

//   回退方法有跟正常方法一样的参数
    public String helloFallBack(String name){
        return "helloFallBack "+name;
    }

    @GetMapping("/log-user-instance")
    public void logUserInstance() {
        ServiceInstance serviceInstance = this.loadBalancerClient.choose("provider");
        // 打印当前选择的是哪个节点
        System.out.println("{}:{}:{}," + serviceInstance.getServiceId()+","+ serviceInstance.getHost()+","+ serviceInstance.getPort());
    }
}

    以此启动项目: 访问 http://localhost:8010/hello?name=feign

以上是正常的访问结果,现在关掉提供者项目,模拟提供者服务不可用。停掉ymk-provider项目,

再次访问 http://localhost:8010/hello?name=feign

   再次访问,直接进入了回退方法中。

   很多场景下,我们需要知道造成回退的原因,只需在fallback方法上添加一个Throwable参数即可,

//   回退方法有跟正常方法一样的参数
    public String helloFallBack(String name,Throwable throwable){
        System.out.println(throwable);
        return "helloFallBack "+name;
    }

   很多情况下,当发生业务异常时候,我们并不想触发fallback,怎么办呢? Hystrix有个HystrixBadRequestException类,这是一个特殊的异常类,当该异常发生时候,不会触发回退。因此,可将自定义的异常类继承该类,从而达到业务异常不 回退的效果。

   Hystrix断路器的状态监控与深入理解

添加依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

   断路器的状态会暴露在Actuator提供的/health端点中,可以直观的看到断路器的状态。

   依次启动项目,访问 http://localhost:8010/hello?name=feign 是正常的,再次访问 http://localhost:8010/health 

  

此时Hsytrix的状态是UP,说明一切正常。此时断路器是关闭的。

现在停止提供者项目

再次访问 http://localhost:8010/hello?name=feign 结果进入了回退方法里了,再次访问 http://localhost:8010/health

我们发现尽管进入了回退方法,但是Hystrix的状态依然UP,这是因为我们的失败率还没达到阈值(默认5秒内失败20次),也就是说进入回退方法,并不代表断路器已经打开。

Feign使用Hystrix

   使用ymk-feign-consumer项目,添加依赖

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

   接口通过fallback添加回退类,回退类要实现接口

@FeignClient(name = "provider" ,configuration = FeignLogConfiguration.class,fallback = FeignClientFallback.class)
public interface TestFeignClient {

    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    String hello(@RequestParam("name") String name);
}

@Component
class FeignClientFallback implements TestFeignClient {
    @Override
    public String hello(String name) {
        return "FeignhelloFallBack "+name;
    }
}

   在application.yml中添加

feign:
  hystrix:
    enabled: true
# 说明:请务必注意,从Spring Cloud Dalston开始,Feign默认是不开启Hystrix的。
# 因此,如使用Dalston请务必额外设置属性:feign.hystrix.enabled=true,否则断路器不会生效。
# 而,Spring Cloud Angel/Brixton/Camden中,Feign默认都是开启Hystrix的。无需设置该属性。

完成!

通过Fallback Factroy检查回退原因

   

@FeignClient(name = "provider", fallbackFactory = FeignClientFallbackFactory.class)
public interface TestFeignClientFallBack {
     @RequestMapping(value = "/hello", method = RequestMethod.GET)
    String hello( String name);
}

/**
 * UserFeignClient的fallbackFactory类,该类需实现FallbackFactory接口,并覆写create方法
 */
@Component
class FeignClientFallbackFactory implements FallbackFactory<TestFeignClientFallBack> {

  @Override
  public TestFeignClientFallBack create(Throwable cause) {
    return new TestFeignClientFallBack() {
      @Override
      public String hello(String name) {
        // 日志最好放在各个fallback方法中,而不要直接放在create方法中。
        // 否则在引用启动时,就会打印该日志。
        System.out.println("fallback; reason was:"+ cause);
        return name;
      }
    };
  }
}

   为Feign禁用Hystrix

      为指定的客户端禁用Hystrix  新建配置类

@Configuration
public class FeignDisableHystrixConfiguration {

    @Bean
    @Scope("prototype")
    public Feign.Builder feignBuider(){
        
        return Feign.builder();
    }
}

        想要禁用ystrix的FeignClient引用此配置类即可   

@FeignClient(name = "provider",configuration = FeignDisableHystrixConfiguration.class)

    全局禁用,只需要在application.yml中配置feign.hystrix.enabled = false即可。

 

 

源码下载:  https://download.csdn.net/download/u013083284/10755912

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值