Hystrix——服务容错

1 Hystrix 简介

在微服务架构中,微服务之间通过网络进行通信,存在相互依赖,当其中一个服务不可用时,有可能会造成雪崩效应。要防止这样的情况,必须要有容错机制来保护服务。
Hystrix是Netflix开源的一个延迟和容错库,它主要实现了以下几点:

  • 包裹请求
    使用HystrixCommand(或HystrixObservableCommand)包裹对依赖的调用逻辑,每个命令在独立线程中执行。
  • 跳闸机制
    当某服务的错误率超过一定阈值时,Hystrix可以自动或手动跳闸,停止请求该服务一段时间。
  • 资源隔离
    Hystrix为每个依赖都维护了一个小型的线程池(或信号量),如果该线程池已满,发往该依赖的请求就被立即拒绝。
  • 监控
    Hystrix可以近乎实时地监控运行指标和配置的变化。
  • 回退机制
    当请求失败、超时、被拒绝,或者当断路器打开时,执行回退逻辑。
  • 自我修复
    当断路器打开一段时间后,会自动进入“半打开”状态,允许一个请求访问依赖的服务,如果该请求成功,则关闭断路器,否则继续保持打开状态。

2 整合Hystrix

2.1 Ribbon整合Hystrix

1.添加相应的依赖:

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

2.在启动类里添加@EnableCircuitBreaker 或者 @EnableHystrix注解

@EnableCircuitBreaker
@EnableDiscoveryClient
@SpringBootApplication
public class RibbonDemoApplication {

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



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

3.为需要容错的方法添加@HystrixCommand注解,并使用fallbackMethod属性指定回退方法

    @HystrixCommand(fallbackMethod = "errorFallback")
    @GetMapping("/hello")
    public String hello() {

        return this.restTemplate.getForObject("http://eureka-client-demo/hello", String.class);
    }


    public String errorFallback() {
        return "Error!";
    }

@HystrixCommand的配置类似下面:

@HystrixCommand(fallbackMethod = "stubMyService",
    commandProperties = {
      @HystrixProperty(name="execution.isolation.strategy", value="SEMAPHORE")
    }
)

2.2 Feign使用Hystrix

1.Spring Cloud 中,Feign默认已经整合了Hystrix,所以只需要在配置中启用Hystrix就会包裹全部Feign Client中的方法:

feign:
  hystrix:
    enabled: true

2.编写回退方法,编写一个Feign Client的实现类,在@FeignClient的fallback属性指定对应的类:

@FeignClient(name = "eureka-client-demo", fallback = ErrorFallback.class)
public interface DemoFeignClient {

    @GetMapping("/hello")
    public String hello();
}


@Component
public class ErrorFallback implements DemoFeignClient {

    @Override
    public String hello() {
        return "Error!";
    }
}

3.如果需要回退方法打印错误信息,可以使用fallbackFactory(fallback和fallbackFactory只能使用其中一种):

@FeignClient(name = "eureka-client-demo", fallbackFactory = ErrorFallbackFactory.class)
public interface DemoFeignClient {

    @GetMapping("/hello")
    public String hello();
}


@Component
public class ErrorFallbackFactory implements FallbackFactory<DemoFeignClient> {

    private static final Logger LOGGER = LoggerFactory.getLogger(ErrorFallbackFactory.class);

    @Override
    public DemoFeignClient create(Throwable throwable) {
        return new DemoFeignClient() {
            @Override
            public String hello() {
                //如果在create()中打印错误信息的话,在应用程序启动时就会打印
                ErrorFallbackFactory.LOGGER.info("fall back cause: ", throwable);
                return "Error!";
            }
        };
    }
}

4.如果不想某个Feign Client使用Hystrix的话,可以使用如下配置:

@FeignClient(name = "eureka-client-demo", configuration = DisableHystrix.class)
public interface DemoFeignClient {

    @GetMapping("/hello")
    public String hello();
}

@Configuration
public class DisableHystrix {

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

3 Hystrix监控

3.1 Ribbon中Hystrix的监控

Hystrix提供了端点/hystrix.stream用于监控Hystrix的情况,Ribbon在整合了Hystrix之后,还需要引入Spring Boot 的actuator依赖,才能通过/hystrix.stream监控接口运行情况。

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

/hystrix.stream的页面会返回类似下面的监控数据:

data: {"type":"HystrixCommand","name":"hello","group":"Controller","currentTime":1516202320578,"isCircuitBreakerOpen":false,"errorPercentage":100,"errorCount":1,"requestCount":1,"rollingCountBadRequests":0,"rollingCountCollapsedRequests":0,"rollingCountEmit":0,"rollingCountExceptionsThrown":0,"rollingCountFailure":1,"rollingCountFallbackEmit":0,"rollingCountFallbackFailure":0,"rollingCountFallbackMissing":0,"rollingCountFallbackRejection":0,"rollingCountFallbackSuccess":1,"rollingCountResponsesFromCache":0,"rollingCountSemaphoreRejected":0,"rollingCountShortCircuited":0,"rollingCountSuccess":0,"rollingCountThreadPoolRejected":0,"rollingCountTimeout":0,"currentConcurrentExecutionCount":0,"rollingMaxConcurrentExecutionCount":0,"latencyExecute_mean":0,"latencyExecute":{"0":0,"25":0,"50":0,"75":0,"90":0,"95":0,"99":0,"99.5":0,"100":0},"latencyTotal_mean":0,"latencyTotal":{"0":0,"25":0,"50":0,"75":0,"90":0,"95":0,"99":0,"99.5":0,"100":0},"propertyValue_circuitBreakerRequestVolumeThreshold":20,"propertyValue_circuitBreakerSleepWindowInMilliseconds":5000,"propertyValue_circuitBreakerErrorThresholdPercentage":50,"propertyValue_circuitBreakerForceOpen":false,"propertyValue_circuitBreakerForceClosed":false,"propertyValue_circuitBreakerEnabled":true,"propertyValue_executionIsolationStrategy":"THREAD","propertyValue_executionIsolationThreadTimeoutInMilliseconds":1000,"propertyValue_executionTimeoutInMilliseconds":1000,"propertyValue_executionIsolationThreadInterruptOnTimeout":true,"propertyValue_executionIsolationThreadPoolKeyOverride":null,"propertyValue_executionIsolationSemaphoreMaxConcurrentRequests":10,"propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests":10,"propertyValue_metricsRollingStatisticalWindowInMilliseconds":10000,"propertyValue_requestCacheEnabled":true,"propertyValue_requestLogEnabled":true,"reportingHosts":1,"threadPool":"Controller"}

3.2 Feign中Hystrix的监控

1.虽然Feign整合了Hystrix,但是并没有整合到监控的模块,所以我们需要重新引入依赖包:

        <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>

2.在启动类添加@EnableCircuitBreaker或者@EnableHystrix注解

@EnableCircuitBreaker
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class FeignDemoApplication {

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

然后就可以通过端点/hystrix.stream查看监控数据。

4 可视化监控

4.1 监控单个服务

可以使用hystrix-dashboard进行可视化监控:
1.创建一个新项目,并引入以下依赖:

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
        </dependency>
  1. 在启动类加上@EnableHystrixDashboard注解
@EnableHystrixDashboard
@SpringBootApplication
public class HystrixDashboardApplication {

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

3.启动应用,打开/hystrix/端点,可以看到一下页面:

hystix-dashboard.PNG

往url栏输入/hystrix.stream的链接,如:http://localhost:8004/hystrix.stream,再点击Monitor Stream按钮,就可以看到如下图的页面:
hystix-dashboard-detail.PNG

4.2 监控多个服务

上面的方法只能监控单个服务,如果要监控多个服务,可以使用turbine,然后再使用hystrix-dashboard进行进行可视化监控。
1.新建一个项目,引入turbine的依赖

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

2.在启动类添加@EnableTurbine注解

@EnableTurbine
@SpringBootApplication
public class TurbineApplication {

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

3.配置文件:

server:
  port: 8006
spring:
  application:
    name: turbine
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8001/eureka/
  instance:
    prefer-ip-address: true

turbine:
  app-config: feign-demo,ribbon-demo
  cluster-name-expression: "'default'"
  combine-host-port: true
  • app-config 指定需要监控的服务,用逗号分隔
  • cluster-name-expression 指定集群名称
  • combine-host-port 按主机名和端口区分服务,turbine默认相同host的为同一服务,将该属性设为true后就可以按主机名和端口区分服务

4.启动应用,打开/turbine.stream端点即可以看到两者的监控数据。这个时候,再将turbine的监控数据接入hystrix-dashboard,比如,将url地址http://localhost:8006/turbine.stream填入dash-board的url一栏,再点击Monitor Stream按钮,就可以同时看到两个服务的监控数据。

4.3 使用消息中间件收集数据(RabbitMQ)

  1. 提供服务的微服务添加以下依赖:
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-netflix-hystrix-stream</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
        </dependency>
  1. 添加RabbitMQ的配置:
spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
  1. Turbine项目移除turbine的依赖并添加以下依赖:
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-turbine-stream</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
        </dependency>
  1. 启动类中@EnableTurbine修改为@EnableTurbineStream
  2. 添加RabbitMQ的配置,同2,同时去掉turbine的配置。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342