精华内容
下载资源
问答
  • 自己实现简单的hystrix
    千次阅读
    2019-04-17 22:31:53

    前言

    在微服务治理中,我们常常会遇到依赖接口超时或者调用失败的场景,如果没有对这些异常的场景做补偿会影响用户体验,甚至会导致应用瘫痪,影响其他业务。那如何解决呢?目前业界常用的方案就是熔断和降级两种方式。Hystrix是提供熔断降级的组件,帮助我们解决业务上的困难。下面简单介绍一些Hystrix的一些使用姿势。

    hystrix的两种降级方式

    • 信号量
    • 线程池

    下面是信号量降级的使用:
    具体参数的含义在注释中。

            @HystrixCommand(
                groupKey = "timeline-group-rcmd",
                fallbackMethod = "callback",
                commandProperties = {
                        @HystrixProperty(name="execution.isolation.strategy", value="SEMAPHORE"), // 信号量隔离,因为业务方法用了ThreadLocal
                        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "100"), //超时时间
                        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value="50"),//触发熔断最小请求数量
                        @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value="30"),//触发熔断的错误占比阈值
                        @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value="3000"),//熔断器回复时间
                        @HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests", value="300"),// 单机最高并发
                        @HystrixProperty(name = "fallback.isolation.semaphore.maxConcurrentRequests", value="100")// fallback单机最高并发
                }
        )
        public void call() {
            count++;
            if(0 == 0) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
    
                }
            }
        }
       /**
       * callback 方法
       */
        public void callback() {
            System.out.println("callback");
        }
    
    更多相关内容
  • Hystrix实现容错

    2018-06-02 20:16:20
    客户端整合Hystrix实现容错,通过简单地配置,为系统保驾护航
  • hystrix是一个容错组件,实现了超时机制和断路器模式。hystrix提供了熔断和降级。降级降级其实就相当于,当我们向一个服务发起请求,当请求超时了,就会把这次请求记录到服务中,然后就会尝试向其他服务发请求,如果...

    Hystrix基本介绍

    hystrix是一个容错组件,实现了超时机制和断路器模式。
    hystrix提供了熔断和降级。
    降级
    降级其实就相当于,当我们向一个服务发起请求,当请求超时了,就会把这次请求记录到服务中,然后就会尝试向其他服务发请求,如果还没成功,就对这次请求进行处理(怎么处理取决于业务需求如)就相当于try catch一样的逻辑,当然hystrix底层使用aop来实现的。
    熔断
    熔断就是有一个阈值,向服务发起请求后,如果不成功,就会记录次数,然后当连续失败次数达到阈值时,下次请求的时候就会直接把这个服务停止。请求有三种状态,可以请求(开),不可请求(关),还有一个中间状态,相当于半开状态,半开状态是什么意思呢,就是可以尝试着去请求,就可以在关闭状态后一段时间,发一个请求尝试一下是否可以请求成功,如果是吧,继续保持关闭状态,如果请求成功,则变成开放状态。
    隔离
    每当向服务发起一个请求时,就是会发起一个http请求,每一个http请求就要开启一个线程,然后等待服务返回信息,这容易导致线程的堆积,所以就可以用http的URI作为一个标识,然后相同的URI可以开启一个线程池,然后线程池中限定线程数,这样就可以设置拒绝策略,当线程池满了,就可以快速的抛出异常或者拒绝请求,用线程池做到线程隔离来达到限流。

    Hystrix基本代码简单实现

    引入包

      <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            </dependency>
    
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
    
            </dependency>
    

    启动类加注解

    @EnableHystrix
    

    写一个测试实例,局部配置就在当前类上加上注解,全局配置就是在yml配置文件里面写配置

    package com.example;
    
    import cn.hutool.core.thread.ThreadUtil;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class DemoConroller {
    
        @GetMapping("/test")
    
        /*局部配置*/
       /* @HystrixCommand(fallbackMethod = "testFallback",commandProperties={
                //设置超时时间
                @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
                //是否开启断路器
                @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),
                //统计的时间窗口,默认为10s,一般不需要更改
                @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value = "30000"),
                //请求最小触发次数
                @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "3"),
                //失败率达到多少后跳闸,在统计窗口期中,请求数大于阈值并且失败率达到50,则触发断路,断路器开启,链路中断
                @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50"),
                //断路后休眠状态的时长,10s,默认为5s,断路10s后断路器进入半开状态
                @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "80000"),
        })*/
       @HystrixCommand(fallbackMethod = "testFallback")
    
        /*test和testFallback入参和返回类型必须保持一致*/
        public String test(@RequestParam Integer sleepTime){
            System.out.println("进入正常方法1");
            ThreadUtil.safeSleep(sleepTime);
            System.out.println("进入正常方法2");
            return "这是正常结果";
        }
    
        public String testFallback(@RequestParam Integer sleepTime){
            System.out.println("进入兜底方法");
            return "这是兜底";
    
        }
    }
    

    application.yml全局配置

    #全局配置
    hystrix:
      command:
        default:
          metrics:
            rollingStats:
              timeInMilliseconds: 30000 #统计的时间窗口,默认为10s,一般不需要更改
          fallback:
            enabled: true
          circuitBreaker:
            enabled: true #是否开启断路器
            errorThresholdPercentage: 50 #失败率达到多少后跳闸,在统计窗口期中,请求数大于阈值并且失败率达到60,则触发断路,断路器开启,链路中断
            requestVolumeThreshold: 3 #请求最小触发次数
            sleepWindowInMilliseconds: 80000 #断路后休眠状态的时长,10s,默认为5s,断路10s后断路器进入半开状态
          execution:
            isolation:
              thread:
                interruptOnFutureCancel: true #取消是否中断
                interruptOnTimeout: true #超时是否中断
                timeoutInMilliseconds: 3000 #超时阈值,单位是毫秒
            timeout:
              enabled: true
    

    Hystrix结合openfeign使用

    1.添加依赖,加入Hystrix和openfeign的依赖

    <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            </dependency>
    

    2.配置application.yml

    logging:
      level:
        com:
          example: debug
    server:
      port: 8073
    spring:
      application:
        name: nacos-app-c
      cloud:
        nacos:
          discovery:
            server-addr: 192.168.33.133:8848
    feign:
      hystrix:
        enabled: true
    #设置feign客户端超时时间(OpenFeign默认支持ribbon)
    ribbon:
      #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
      ReadTimeout: 10000
      #指的是建立连接后从服务器读取到可用资源所用的时间
      ConnectTimeout: 10000
    
    hystrix:
      command:
        default:
          metrics:
            rollingStats:
              timeInMilliseconds: 30000 #统计的时间窗口,默认为10s,一般不需要更改
          fallback:
            enabled: true
          circuitBreaker:
            enabled: true #是否开启断路器
            errorThresholdPercentage: 50 #失败率达到多少后跳闸,在统计窗口期中,请求数大于阈值并且失败率达到60,则触发断路,断路器开启,链路中断
            requestVolumeThreshold: 3 #请求最小触发次数
            sleepWindowInMilliseconds: 80000 #断路后休眠状态的时长,10s,默认为5s,断路10s后断路器进入半开状态
          execution:
            isolation:
              thread:
                interruptOnFutureCancel: true #取消是否中断
                interruptOnTimeout: true #超时是否中断
                timeoutInMilliseconds: 3000 #超时阈值,单位是毫秒
            timeout:
              enabled: true
        commandKeyTest:
          metrics:
            rollingStats:
              timeInMilliseconds: 30000 #统计的时间窗口,默认为10s,一般不需要更改
          fallback:
            enabled: true
          circuitBreaker:
            enabled: true #是否开启断路器
            errorThresholdPercentage: 50 #失败率达到多少后跳闸,在统计窗口期中,请求数大于阈值并且失败率达到60,则触发断路,断路器开启,链路中断
            requestVolumeThreshold: 3 #请求最小触发次数
            sleepWindowInMilliseconds: 80000 #断路后休眠状态的时长,10s,默认为5s,断路10s后断路器进入半开状态
          execution:
            isolation:
              thread:
                interruptOnFutureCancel: true #取消是否中断
                interruptOnTimeout: true #超时是否中断
                timeoutInMilliseconds: 3000 #超时阈值,单位是毫秒
            timeout:
              enabled: true
    
    

    3.启动类上加上注解@EnableHystrix和@EnableFeignClients

    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableFeignClients
    @EnableHystrix
    public class CApp {
    
        public static void main(String[] args) {
            SpringApplication.run(CApp.class, args);
        }
    }
    

    4.接口类上:@FeignClient(“被调用的服务器名”,fallback =兜底方法.class)

    @FeignClient(value = "nacos-app-a",fallback = AClientFallBack.class)
    public interface AClient {
    
        @GetMapping("echo")
        String test (@RequestParam("name") String name,@RequestParam("sleepTime") Integer sleepTime);
    
    }
    

    5.兜底方法

    @Service
    public class AClientFallBack implements  AClient {
        @Override
        public String test(@RequestParam("name") String name, @RequestParam("sleepTime") Integer sleepTime) {
            return "兜底";
        }
    }
    
    

    6.编写一个测试类,实现的功能是:由于配置文件中配置的是3秒超时阈值,单位是毫秒,和请求最小触发3次数,所以test方式传入的参数时间大于等于三秒后,将重试3次后熔断调用兜底方法

    @RestController
    public class CController {
    
        @Autowired
        private AClient aClient;
    
        @GetMapping("/test")
        public String test(@RequestParam(value = "name", defaultValue = "这是默认值") String name,@RequestParam("sleepTime") Integer sleepTime) {
    
            System.out.println("进来了");
            String ret = aClient.test(name,sleepTime);
            return  ret;
        }
    }
    
    展开全文
  • 保障 hystrix简单实现
  • Hystrix实现原理 在了解hystrix的工作原理之前,我们先来了解一下命令模式 命令模式 命令模式的定义:将请求封装成一个对象,从而让用户使用不同的请求把客户端参数化,以及支持可撤销和恢复的功能。 命令模式...

    Hystrix实现原理

    在了解hystrix的工作原理之前,我们先来了解一下命令模式

    命令模式

    命令模式的定义: 将请求封装成一个对象,从而让用户使用不同的请求把客户端参数化,以及支持可撤销和恢复的功能。

    命令模式常用的对象

    Command:请求封装成的对象,该对象是命令模式的主角。也就是说将请求方法封装成一个命令对象,通过操作命令对象来操作请求方法。在命令模式是有若干个请求的,需要将这些请求封装成一条条命令对象,客户端只需要调用不同的命令就可以达到将请求参数化的目的。将一条条请求封装成一条条命定对象之后,客户端发起的就是一个个命令对象了,而不是原来的请求方法!

    Receiver:有命令,当然有命令的接收者对象:如果有只有命令,没有接受者,那不就是光棍司令了?没有电视机或者电脑主机,你对着电视机遥控器或者电脑键盘狂按有毛用?Receiver对象的主要作用就是受到命令后执行对应的操作。对于点击遥控器发起的命令来说,电视机就是这个Receiver对象,比如按了待机键,电视机收到命令后就执行了待机操作,进入待机状态。

    Client: 但是有一个问题摆在眼前,命令对象现在已经有了,但是谁来负责创建命令呢?这里就引出了客户端Client对象,再命令模式中命令是有客户端来创建的。打个比方来说,操作遥控器的那个人,就是扮演的客户端的角色。人按下遥控器的不同按键,来创建一条条命令。

    Invoker:现在创建命令的对象Client也已经露脸了,它负责创建一条条命令,那么谁来使用或者调度这个命令呢?--命令的使用者就是Invoker对象了,还是拿人,遥控器,电视机来做比喻,遥控器就是这个Invoker对象,遥控器负责使用客户端创建的命令对象。该Invoker对象负责要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。

    在下面这些情况下应考虑使用命令模式。

    • 使用命令模式作为 “ 回调(CallBack) "在面向对象系统中的替代。"CallBack"讲的

    便是先将 一个函数登记上, 然后在以后调用此函数。

    • 需要在不同的时间指定请求、 将请求排队。 一个命令对象和原先的请求发出者可以

    有不同的生命期。 换言之, 原先的请求发出者可能已经不在了, 而命令对象本身仍

    然是活动的。这时命令的接收者可以是在本地, 也可以在网络的另外一个地址。命

    令对象可以在序列化之后传送到另外一台机器上去。

    • 系统需要支持命令的撤销。命令对象可以把状态存储起来, 等到 客户端需要撤销命

    令所产生的效果时, 可以调用undo()方法, 把命令所产生的效果撤销掉。命令对

    象还可以提供redo()方法, 以供客户端在需要时再重新实施命令效果。

    • 如果要将系统中所有的数据更新到日志里,以便在系统 崩溃时,可以根据日志读回

    所有的数据更新命令, 重新 调用 Execute()方法 一条一条执行 这些命令, 从而恢

    复系统在崩溃前所做的数据更新。

    Netflix hystrix工作流程图

    上图摘自官网:

    https://raw.githubusercontent.com/wiki/Netflix/Hystrix/images/hystrix-command-flow-chart.png

    官网介绍如下:How it Works · Netflix/Hystrix Wiki · GitHubHystrix is a latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where failure is inevitable. - How it Works · Netflix/Hystrix Wikihttps://github.com/Netflix/Hystrix/wiki/How-it-Works

    执行流程

    1. 创建HystrixCommand或HystrixObservableCommand对象

    首先,构建一个HystrixCommand或是HystrixObservableCommand对象,用来表示对依赖服务的操作请求, 同时传递所有需要的参数。 从其命名中我们就能知道它采用了 “命令模式” 来实现对服务调用操作的封装。 而这两个 Command 对象分别针对不同的应用场景。

    1. HystrixCommand: 用在依赖的服务返回单个操作结果的时候。
    2. HystrixObservableCommand: 用在依赖的服务返回多个操作结果的时候

    2. 命令执行

    从图中我们可以看到一共存在4种命令的执行方式,而Hystrix在执行时会根据创建的Command对象以及具体的情况来选择一个执行。

    HystrixComrnand实现了下面两个执行方式:

    execute (): 同步执行,从依赖的服务返回一个单一的结果对象,或是在发生错误的时候抛出异常。

    queue (): 异步执行,直接返回一个Future对象,其中包含了服务执行结束时要返回的单一结果对象。

    R value = command. execute() ;

    Future<R> fValue = command. queue() ;

    HystrixObservableCommand实现了另外两种执行方式:

    observe () : 返回Observable对象,它代表了操作的多个结果,它是一个Hot

    Observable。

    toObservable(): 同样会返回Observable对象,也代表了操作的多个结果,

    但它返回的是 一个Cold Observable。

    Observable<R> ohValue = command.observe(};

    Observable<R> ocValue = command. toObservable(};

    在Hystrix的底层实现中大量地使用了RxJava, 在这里简单介绍一下RxJava的观察者-订阅者模式。

    上面我们所提到的Observable对象就是RxJava中的核心内容之一,可以把它理解

    为 “事件源” 或是 “被观察者”, 与其对应的Subscriber对象,可以理解为 “ 订阅者”

    或是 “观察者”。 这两个对象是RxJava响应式编程的重要组成部分。

    • Observable用来向订阅者Subscriber对象发布事件,Subscriber对象则在接收到事件后对其进行处理, 而在这里所指的事件 通常就是对依赖 服务的调用。

    • 一个Observable可以发出多个事件, 直到结束或是 发生异常。

    • Observable 对象每发出一个事件,就会调用对应观察者Subscriber对象的onNext ()方法。

    • 每一个Observable的执行,最后一定会通过调用 Subscriber. onCompleted () 或者Subscriber.onError()来结束该事件的操作流。

    事件源 observable 提到了两个不同的概念: HotObservable 和 ColdObservable, 分别对应了上面 command. observe ()和command.toObservable() 的返回对象。其中 HotObservable,它不论 ”事件源 ” 是否有 “订阅者”, 都会在创建后对事件进行发布,所以对于HotObservable 的每一个 “订阅者” 都有可能是从 “ 事件源 ” 的中途开始的, 并可能只是看到了整个操作的局部过程。而 Cold Observable 在没有 “订阅者” 的时候并不会发布事件, 而是进行等待, 直到有“订阅者”之后才发布事件,所以对于ColdObservable 的订阅者,它可以保证从一开始看到整个操作的全部过程。

    3. 结果是否被缓存

    若当前命令的请求缓存功能是被启用的, 并且该命令缓存命中, 那么缓存的结果会立即以Observable 对象的形式 返回。

    4. 断路器是否打开

    在命令结果没有缓存命中的时候, Hystrix在执行命令前需要检查断路器是否为打开状态:

    •         如果断路器是打开的,那么Hystrix不会执行命令,而是转接到fallback处理逻辑
    •         如果断路器是关闭的, 那么Hystrix跳到第5步,检查是否有可用资源来 执行命令。

    5. 线程池/请求队列/信号量是否占满

    如果与命令相关的线程池和请求队列,或者信号量(不使用线程池的时候)已经被占满, 那么Hystrix也不会执行命令,而是转接到fallback处理逻辑。

    需要注意的是,这里Hystrix所判断的线程池并非容器的线程池,而是每个依赖服务的专有线程池。

    6. HystrixObservableCommand.construct()或HystrixCommand.run()

    1. HystrixCommand.run(): 返回一个单一 的结果,或者抛出异常。
    2. HystrixObservableCommand.construct(): 返回一个Observable对象来发射多个结果,或通过onError发送错误通知。

    7. 计算断路器的状态

           Hystrix会将“成功”、“失败”、“拒绝”、“超时” 等信息报告给断路器,而断路器会维护一组计数器来统计这些数据。断路器会使用这些统计数据来决定是否要将断路器打开,来对某个依赖服务的请求进行 “熔断/短路”,直到恢复期结束。若在恢复期结束后,根据统计数据判断如果还是未达到健康指标,就再次 “熔断/短路”。

    8.fallback处理

    当命令执行失败的时候, Hystrix会进入fallback尝试回退处理, 我们通常也称该操作为 “ 服务降级”。而能够引起服务降级处理的清况有下面几种:

    • 第4步, 当前命令处于 “熔断/短路” 状态, 断路器是打开的时候。

    • 第5步, 当前命令的线程池、请求队列或者信号量被占满的时候。

    • 第6步, HystrixObservableCommand.construct()或HystrixCommand.run()抛出异常的时候。

    9.返回成功的响应

    当Hystrix命令执行成功之后,它会将处理结果直接返回或是以Observable 的形式返回。

     

    断路器原理

            断路器在 HystrixCommand 和 HystrixObservableCommand 执行过程中起到了非常重要的作用,它是 Hystrix 的核心部件。那么断路器是如何决策熔断和记录信息的呢?

            我们先来看看断路器 HystrixCircuitBreaker 的定义

    public interface HystrixCircuitBreaker {
        public boolean allowRequest();
    
        public boolean isOpen();
    
        void markSuccess();
    
        public static class Factory {...}
    
        static class HystrixCircuitBreakerImpl implements HystrixCircuitBreaker {...}
    
        static class NoOpCircuitBreaker implements HystrixCircuitBreaker {...}
    }

     

    HystrixCircuitBreaker 主要定义了断路器的三个抽象方法

    • allowRequest():每个Hystrix命令的请求都通过它判断是否被执行。
    • isOpen(): 返回当前断路器是否打开。
    • markSuccess(): 用来闭合断路器。

    另外有三个静态类

            静态类 Factory 中维护了一个 Hystrix 命令与 HystrixCircuitBreaker 的关系集合: ConcurrentHashMap<String, HystrixCircuitBreaker> circuitBreakersByCommand, 其中 String 类型的 key 通过 HystrixCommandKey 定义,每一个 Hystrix 命令需要有一个 key 来标识, 同时一个 Hystrix 命令也会在该集合中找到它对应的断路器 HystrixCircuitBreaker 实例。

            静态类NoOpCircuitBreaker定义了一个空的断路器实现,它允许所有请求,并且断路器状态始终是闭合的

            静态类HystrixCircuitBreakerImpl 是断路器接口HystrixCircuitBreaker的实现类,在该类中定义了断路器的4个核心对象。

    private final HystrixCommandProperties properties;
    private final HystrixCommandMetrics metrics;
    
    private AtomicBoolean circuitOpen = new AtomicBoolean(false);
    
    private AtomicLong circuitOpenedOrLastTestedTime = new AtomicLong();

    HystrixCommandProperties properties:断路器对应HystrixCommand实例的属性对象

    HystrixCommandMetrics metrics:用于让HystrixCommand记录各类度量指标的对象。

    AtomicBoolean circuitOpen:断路器是否打开的标志,默认为false

    AtomicLong circuitOpenedOrLastTestedTime:断路器打开或上一次测试的时间戳。

    HystrixCircuitBreakerImpl 对 HystrixCircuitBreaker接口的各个方法实现如下所示:

    1.isOpen函数

    public boolean isOpen() {
        if (circuitOpen.get()) {
            return true;
        }
    
        HealthCounts health = metrics.getHealthCounts();
    
        if (health.getTotalRequests() < properties.circuitBreakerRequestVolumeThreshold().get()) {
            return false;
        }
    
        if (health.getErrorPercentage() < properties.circuitBreakerErrorThresholdPercentage().get()) {
            return false;
        } else {
            // our failure rate is too high, trip the circuit
            if (circuitOpen.compareAndSet(false, true)) {
                // if the previousValue was false then we want to set the currentTime
                circuitOpenedOrLastTestedTime.set(System.currentTimeMillis());
                return true;
            } else {
                return true;
            }
        }
    }

    isOpen (): 判断断路器的打开/关闭状态。

            如果断路器打开标识为true, 则直接返回true, 表示断路器处于打开状态。否则,就从度量指标对象 metrics 中获取 HealthCounts 统计对象做进一步判断(该对象记录了 一个滚动时间窗内的请求信息快照,默认时间窗为10秒)。

            如果它的请求总数(QPS)在预设的阙值范围内就返回 false, 表示断路器处于未打开状态。该阙值的配置参数为circuitBreakerRequestVolumeThreshold,默认值为20。

            如果错误百分比在阈值范围内就返回 false, 表示断路器处于未打开状态。该阙值的配置参数为 circuitBreakerErrorThresholdPercentage, 默认值为50。

            如果上面的两个条件都不满足,则将断路器设置为打开状态 (熔断/短路)。 同时,如果是从关闭状态切换到打开状态的话,就将当前时间记录到上面提到的circuitOpenedOrLastTestedTirne 对象中。

    2. allowRequest函数

    public boolean allowRequest() {
        if (properties.circuitBreakerForceOpen().get()) {
            return false;
        }
        if (properties.circuitBreakerForceClosed().get()) {
            isOpen();
            return true;
        }
        return !isOpen() || allowSingleTest();
    }

            allowRequest(): 判断请求是否被允许。先根据配置对象properties中断路器判断强制打开或关闭属性是否被设置。如果强制打开,就直接返回false,拒绝请求。如果强制关闭,它会允许所有请求,但是同时也会调用 isOpen ()来执行断路器的计算逻辑, 用来模拟断路器打开/关闭的行为。 在默认情况下,断路器并不会进入这两个强制打开或关闭的分支中去,而是通过!isOpen () I I allowSingleTest ()来判断是否允许请求访问。 isOpen()之前已经介绍过,用来判断和计算当前断路器是否打开,如果是断开状态就允许请求。

    public boolean allowSingleTest() {
        long timeCircuitOpenedOrWasLastTested = circuitOpenedOrLastTestedTime.get();
        if (circuitOpen.get() && System.currentTimeMillis() > timeCircuitOpenedOrWasLastTested + properties.circuitBreakerSleepWindowInMilliseconds().get()) {
            if (circuitOpenedOrLastTestedTime.compareAndSet(timeCircuitOpenedOrWasLastTested, System.currentTimeMillis())) {
                return true;
            }
        }
        return false;
    }

            allowSingleTest()判断在断路器打开状态时,是否过了指定休眠时间(circuitBreakerSleepWindowInMilliseconds),如果过了休眠时间,则再次允许请求尝试访问,此时断路器处于‘半开’状态,若此时请求继续失败, 断路器又进入打开状态, 并继续等待下一个休眠窗口过去之后再次尝试;若请求成功, 则将断路器重新置于关闭状态。所以通过 allowSingleTest()与isOpen ()方法的配合,实现了断路器打开和关闭状态的切换。

    3. markSuccess函数

    public void markSuccess() {
        if (circuitOpen.get()) {
            if (circuitOpen.compareAndSet(true, false)) {
                metrics.resetStream();
            }
        }
    }

    该函数用来在 “半开路” 状态时使用。若Hystrix 命令调用成功,通过调用它将打开的断路器关闭, 并重置度量指标对象。

    Netflix Hystrix断路器官方原理图如下:

    依赖隔离

            Hystrix 使用舱壁模式来隔离彼此的依赖关系并限制对其中任何一个的并发访问。Hystrix 则使用该模式实现线程池的隔离,它会为每一个依赖服务创建一个独立的线程池,即通过对依赖服务实现线程池隔离。

    线程和线程池

            客户端(库、网络调用等)在单独的线程上执行。这将它们与调用线程(Tomcat 线程池)隔离,以便调用者可以“离开”耗时过长的依赖调用。

            Hystrix 使用单独的、每个依赖项的线程池作为约束任何给定依赖项的一种方式,因此底层执行的延迟只会使该池中的可用线程饱和。

     

    实现对依赖服务的线程池隔离的好处有:

    1. 应用自身得到完全保护,不会受不可控的依赖服务影响
    2. 可以有效降低接入新服务的风险
    3. 当失败的客户端再次恢复健康时,线程池将被清理,应用程序立即恢复健康的性能,而不是整个 Tomcat 容器不堪重负时的长时间恢复。
    4. 如果客户端库配置错误,线程池的健康状况将迅速证明这一点(通过增加的错误、延迟、超时、拒绝等)并且您可以处理它(通常通过动态属性实时)而不影响应用程序功能。
    5. 如果客户端服务更改性能特征(这种情况经常发生,足以成为一个问题)进而导致需要调整属性(增加/减少超时、更改重试等),这再次通过线程池指标(错误、延迟)变得可见、超时、拒绝),并且可以在不影响其他客户端、请求或用户的情况下进行处理。
    6. 除了隔离的好处之外,拥有专用线程池还提供了内置的并发性,可以利用它在同步客户端库之上构建异步外观(类似于 Netflix API 如何在 Hystrix 命令之上构建反应式、完全异步的 Java API)。

    线程池的缺点

    线程池的主要缺点是它们增加了计算开销。每个命令执行都涉及在单独线程上运行命令所涉及的排队、调度和上下文切换。

    在设计这个系统时,Netflix 决定接受这种开销的成本以换取它提供的好处,并认为它足够小,不会对成本或性能产生重大影响。

    线程成本

    Hystrix 测量在子线程上执行construct()orrun()方法时的延迟以及在父线程上的总端到端时间。通过这种方式,您可以看到 Hystrix 开销(线程、指标、日志记录、断路器等)的成本。

    Netflix API 使用线程隔离每天处理 10 多亿次 Hystrix 命令执行。每个 API 实例有 40 多个线程池,每个线程池有 5-20 个线程(大多数设置为 10 个)。

    下图表示HystrixCommand在单个 API 实例上以每秒 60 次请求执行的情况(每台服务器每秒线程执行总数约为 350 次):

    在中位数(和更低),拥有一个单独的线程没有成本。

    在第 90个百分位数处,拥有单独线程的成本为 3 毫秒。

            在第 99个百分位数处,拥有单独线程的成本为 9 毫秒。但是请注意,成本的增加远小于单独线程(网络请求)的执行时间增加,后者从 2 跳到 28,而成本从 0 跳到 9。

            对于大多数 Netflix 用例而言,对于此类电路而言,这种开销在第 90个百分点或更高的位置上被认为是可以接受的,因为这样可以获得弹性的好处。

    信号量

            您可以使用信号量(或计数器)来限制对任何给定依赖项的并发调用数量,而不是使用线程池/队列大小。这允许 Hystrix 在不使用线程池的情况下减轻负载,但它不允许超时和走开。如果您信任客户端并且只想要减载,则可以使用此方法。

            HystrixCommand并HystrixObservableCommand在 2 个地方支持信号量:

            回退(Execution):当 Hystrix 检索回退时,它总是在调用 Tomcat 线程上执行此操作。

          执行(Execution):如果将该属性设置为execution.isolation.strategy,SEMAPHORE则 Hystrix 将使用信号量而不是线程来限制调用该命令的并发父线程的数量。

            您可以通过定义可以执行多少并发线程的动态属性来配置信号量的这两种用途。您应该使用与调整线程池大小时使用的类似计算来调整它们的大小(在亚毫秒时间内返回的内存中调用可以执行超过 5000rps,信号量仅为 1 或 2……但默认值为 10)。

     

     

     

    展开全文
  • microservice-eureka-ribbon-feign-hystrix微服务(服务发现组件Eureka-负载均衡Ribbon-REST调用Feign-实现容错Hystrix)简介:microservice-eureka-ribbon-feign-hystrix-demo服务提供者:microservice-simple-...
  • Hystrix简单实现

    2019-11-22 16:30:43
    这次要简单实现Hystrix功能,在上篇博客的基础上改动几步就好了。 这里先简单说下自己Hystrix的理解: 它就和我们平时的生活中的断路器一样,每当线路中有电路发生短路时,为了防止危害,断路器就会开启来切断故障...

    项目结构可参考:上一篇博客

    这次要简单实现Hystrix功能,在上篇博客的基础上改动几步就好了。

    这里先简单说下自己对Hystrix的理解:

    它就和我们平时的生活中的断路器一样,每当线路中有电路发生短路时,为了防止危害,断路器就会开启来切断故障电路,它对电路起到了一种保护作用。同理,在微服务中,每个服务之间会相互调用,比如订单服务调用库存服务,如果在订单服务在调用库存服务时,库存服务发生故障,那么请求就会进入长时间的等待,长时间等待后,才会出现请求库存服务失败,进而创建订单失败结果。那么如果是在高并发的场景下,库存服务出现故障,会导致大量线程被占用而无法释放,越来越多的请求会被阻塞,最后会导致订单服务也不可用。如果服务的调用链路比较长的话,那么下游服务的故障就会渐渐的影响到上游的所有服务,导致服务雪崩。

    所以这时引入Hystrix(熔断器)来解决上述情况,当确定服务发生故障时,我们可以采用服务熔断和服务降级,设置降级的处理方式,这样上游服务在下游服务出现故障时,就不用长时间的等待下去,可以回调降级方法,及时给用户响应。更重要的是,它解决了可能出现的服务雪崩现象,维持了整个微服务的稳定性通知。当然Hystrix不止只有服务熔断,服务降级的功能,它还具备其他的类似请求缓存,请求合并等功能。

    • 服务熔断:这里要特别说下服务熔断,服务熔断有3种状态,分别是开启,关闭,半熔断,默认是关闭
    • 开启:在调用下游服务时,在规定的时间内,Hystrix默认是10秒,调用出错的比例达到一定得阈值,就会开启Hystrix,之后调用服务时都会调用降级方法。
    • 关闭:关闭就代表着服务是正常的,Hystrix不做任何限制。
    • 半熔断:为什么还会有这个状态,要知道,我们熔断器不可能是永久的,要是永久的话,那下游服务就没意义了,所以在开启Hystrix一段时间后,默认是5秒,Hystrix会进入
      半熔断的状态,它会尝试性的去调用被熔断的这个接口,如果成功率达标,那么就关闭Hystrix,正常调用服务,不再调用降级方法,反之则继续开启Hystrix。

    下面就是简单的Hystrix使用demo:

    首先导入Hystrix依赖:

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

    其次在spring boot启动类上增加注解@EnableCircuitBreaker开启熔断器:

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

    最后在调用的服务方法上增加@HystrixCommand(fallbackMethod = “fallback”),fallbackMethod里的值表示在该方法调用服务失败后,回滚调用的方法:

    @Service
    public class RibbonService {
        @Autowired
        private RestTemplate restTemplate;
    
        @HystrixCommand(fallbackMethod = "fallback")
        public String helloRibbon(String name) {
            return restTemplate.getForObject("http://eureka-client/helloWorld/" + name, String.class);
        }
    
        /**
         * 调用helloRibbon失败后的降级方法
         *
         * @param name
         * @return
         */
        public String fallback(String name) {
            return "error" + name;
        }
    }
    

    服务正常调用情况如图:
    在这里插入图片描述
    在这里插入图片描述

    断掉端口为8762的服务,效果如图:
    在这里插入图片描述
    在这里插入图片描述
    可以看到在8762端口的服务断掉后,我们调用时,页面并没有返回错误,而是给了我们降级方法的返回响应。这就说明Hystrix已经起到了作用。

    展开全文
  • Hystrix断路器概述Hystrix重要概念(面试常考)Hystrix案例Hystrix 服务提供者Hystrix 服务消费者 概述 1、分布式系统面临的问题 服务雪崩: 多个服务之间在调用的时候,假设微服务A调用微服务B和微服务C,微服务B...
  • Hystrix 1.5 滑动窗口实现原理总结

    千次阅读 2019-01-23 16:51:36
    文章目录总览BucketedCounterStream总览...本文转载自:Hystrix 1.5 滑动窗口实现原理总结 总览 Netflix Hystrix 通过类似滑动窗口的数据结构来统计调用的指标数据。Hystrix 1.5 将滑动窗口设计成了数据流(reacti...
  • OpenFeign+Hystrix
  • 主要介绍了Spring Cloud Hystrix 服务容错保护的原理实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 引用Hystrix官方例子,如果一个服务依赖30个子服务,子服务都是99.99%的可用性,那么该服务可用性为99.99%的30次方 = 99.7%,即0.3%的失败率。从请求数量上讲,一亿次请求中如果有0.3%的失败,失败次数是300万。从...
  • 使用Hystrix实现微服务的容错处理 至此,已用Eureka实现类微服务的注册与发现,Ribbon实现了客户端侧的负载均衡,Feign实现了声明式的API调用。 实现容错的手段 如果服务提供者响应非常缓慢,那么消费者对提供者的...
  • 内容概要:使用简单的登录注册功能串联起验证码的生成与发送、邮件发送、IP防爆刷、用户统一认证等功能,实现所涉及到的技术全部基于SpringCloud微服务架构: Nginx、Eureka、Feign(Ribbon、Hystrix)、Gateway、...
  • 幸运的是,Hystrix 提供了简单易用的方法实现舱壁来隔离不同的远程资源调用。下图说明了 Hystrix 将不同的远程调用隔离在不同的“舱室”(线程池)中: Hystrix 可以为每一个依赖建立一个线程池,使之和其他依赖的...
  • 对于这一问题,hystrix也为我们实现了自动恢复功能。 当断路器打开,对主逻辑进行熔断之后,hystrix会启动一个休眠时间窗,在这个时间窗内,降级逻辑是临时的成为主逻辑,当休眠时间窗到期,断路器将进入半开状态,...
  • 14.0、springcloud-Hystrix:服务熔断实现 分布式系统面临的问题: 复杂分布式体系结构中的应用程序有数十个依赖关系,某个依赖关系在某些时候将会出现不可避免的失败! 服务雪崩: 多个微服务之间调用的...
  • 电商网站的商品详情页系统架构遇到的场景问题 小型电商网站的商品详情页系统架构 小型电商网站的页面展示采用页面...下面是页面模板的简单 Demo 。 <html> <body> 商品名称:#{productName}<br>
  • 这篇文章将介绍feign与hystrix结合来实现调用的同时进行熔断降级防止服务雪崩 使用feign的话自然少不了@FeignClient注解,而@FeignClient注解中除了最基本的name等属性之外,如果要整合hystrix一起使用的话,我们...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 27,920
精华内容 11,168
关键字:

自己实现简单的hystrix