服务容错和Hystrix

在微服务架构中,由于某个服务的不可用导致一系列的服务崩溃,被称之为雪崩效应。所以防御服务的雪崩效应是必不可少的,在Spring Cloud中防雪崩的利器就是Hystrix,Spring Cloud Hystri是基于Netflix Hystrix实现的。Hystrix的目标在于通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Hystrix 具备服务降级、服务容错、服务熔断、线程和信号隔离、请求缓存、请求合并以及服务监控等强大功能。

Hystrix中的资源隔离:

在Hystrix中, 主要通过线程池来实现资源隔离. 通常在使用的时候我们会根据调用的远程服务划分出多个线程池. 例如调用产品服务的Command放入A线程池, 调用账户服务的Command放入B线程池. 这样做的主要优点是运行环境被隔离开了. 这样就算调用服务的代码存在bug或者由于其他原因导致自己所在线程池被耗尽时, 不会对系统的其他服务造成影响. 但是带来的代价就是维护多个线程池会对系统带来额外的性能开销. 如果是对性能有严格要求而且确信自己调用服务的客户端代码不会出问题的话, 可以使用Hystrix的信号模式(Semaphores)来隔离资源.

关于服务降级:

  • 优先核心服务,非核心服务不可用或弱可用
  • 在Hystrix中可通过HystrixCommand注解指定可降级的服务
  • 在fallbackMethod(回退函数)中具体实现降级逻辑。对于查询操作, 我们可以实现一个fallback方法, 当请求后端服务出现异常的时候, 可以使用fallback方法返回的值. fallback方法的返回值一般是设置的默认值或者来自缓存

触发降级

本小节我们来模拟一下触发服务降级的情况,首先在订单服务项目的pom.xml文件中,加入Spring Cloud Hystrix依赖。如下:

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

添加好依赖后修改一下启动类的注解。修改后代码如下:

package org.zero.springcloud.order.server;import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;@SpringCloudApplication
@EnableFeignClients(basePackages = "org.zero.springcloud.product.client")
public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}
}

在controller包中,新建一个 HystrixController ,我们在这个类里做实验。在这个类里,我们调用了商品服务中的查询商品信息接口。为了模拟服务宕机触发降级,所以此时我已经把商品服务关闭了。具体代码如下:

package org.zero.springcloud.order.server.controller;import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;import java.util.Collections;/*** @program: sell_order* @description: Hystrix Demo* @author: 01* @create: 2018-08-28 20:10**/
@Slf4j
@RestController
@RequestMapping("/hystrix/demo")
public class HystrixController {/*** 通过@HystrixCommand注解指定可降级的服务,fallbackMethod参数指向的是回调函数,函数名称可自定义** @return String*/@HystrixCommand(fallbackMethod = "fallback")@GetMapping("/getProductInfoList")public String getProductInfoList() {RestTemplate restTemplate = new RestTemplate();return restTemplate.postForObject("http://127.0.0.1:8519/buyer/product/listForOrder",Collections.singletonList("157875196366160022"), String.class);}/*** 触发降级后的回调函数** @return String*/public String fallback() {return "太拥挤了, 请稍后重试~";}
}

启动项目,访问结果如下:

从测试结果可以看到,由于商品服务关闭了,导致无法调用相应的接口。触发了服务降级后,调用了注解中指定的回调函数,并返回了相应的提示。

触发服务降级不一定是服务调用失败,因为服务降级的主要触发原因是抛出了异常,所以只要这个方法中抛出了未被捕获的异常都会触发服务降级。如下示例:

@HystrixCommand(fallbackMethod = "fallback")
@GetMapping("/getProductInfoList")
public String getProductInfoList() {throw new RuntimeException("发生了异常");
}

在某些情况下,我们可能只需要定义一个默认的回调处理函数即可,那么我们就可以使用@DefaultProperties注解来定义默认的回调函数,这样就不需要每个 @HystrixCommand 注解都指定一个回调函数了。如下示例:

package org.zero.springcloud.order.server.controller;import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;import java.util.Collections;/*** @program: sell_order* @description: Hystrix Demo* @author: 01* @create: 2018-08-28 20:10**/
@Slf4j
@RestController
@RequestMapping("/hystrix/demo")
@DefaultProperties(defaultFallback = "defaultFallback")
public class HystrixController {/*** 定义了@DefaultProperties后,只需通过@HystrixCommand注解指定可降级的服务即可** @return String*/@HystrixCommand@GetMapping("/getProductInfoList")public String getProductInfoList() {RestTemplate restTemplate = new RestTemplate();return restTemplate.postForObject("http://127.0.0.1:8519/buyer/product/listForOrder",Collections.singletonList("157875196366160022"), String.class);}/*** 触发降级后的回调函数** @return String*/public String defaultFallback() {return "太拥挤了, 请稍后重试~";}
}

超时设置

使用 @HystrixCommand 注解的接口是有一个默认超时时间的,当调用某个服务的耗时超过这个时间也会触发服务降级,默认的超时时间是1秒。我们也可以去自定义这个超时时间,如下示例:

@HystrixCommand(commandProperties = {// 设置超时时间为3秒@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
@GetMapping("/getProductInfoList")
public String getProductInfoList() {RestTemplate restTemplate = new RestTemplate();return restTemplate.postForObject("http://127.0.0.1:8519/buyer/product/listForOrder",Collections.singletonList("157875196366160022"), String.class);
}

Hystrix断路器

断路器就像电路中的断路器一样,当短路发生时,它第一时刻熔断,切断了故障电路,保护其他用电单元。

在分布式架构中,断路器的作用类似,当某个服务单元发生了故障,通过断路器的故障监控,直接切断原来的主逻辑调用,强迫以后的多个服务调用不再访问远程服务器,防止应用程序继续执行或等待超时。熔断器也可以监控服务单元的错误是否已经修正,如果已经修正,应用程序会再次尝试调用操作。

在微服务架构中,系统被拆分成了一个个小的服务单元,各自运行在自己的线程中,各单元之间通过注册与订阅的方式互相远程调用,此时若网络故障或是某一服务挂掉则会出现调用延迟,进一步导致调用方的对外服务也出现延迟,如果调用方的请求不断增加,服务单元线程资源无法释放,队列装满,最终导致故障的蔓延,故断路器就是解决这种问题的。

断路器模式:

当Hystrix Command请求后端服务失败数量超过一定比例(默认50%), 断路器会切换到开路状态(Open). 这时所有请求会直接失败而不会发送到后端服务. 断路器保持在开路状态一段时间后(默认5秒), 自动切换到半开路状态(HALF-OPEN). 这时会判断下一次请求的返回情况, 如果请求成功, 断路器切回闭路状态(CLOSED), 否则重新切换到开路状态(OPEN). 即有自我检测并恢复的能力.

代码示例:

@HystrixCommand(commandProperties = {@HystrixProperty(name = "circuitBreaker.enabled", value = "true"), // 开启熔断机制@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), // 设置当请求失败的数量达到10个后,打开断路器,默认值为20@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), // 设置打开断路器多久以后开始尝试恢复,默认为5s@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"),  // 设置出错百分比阈值,当达到此阈值后,打开断路器,默认50%
})
@GetMapping("/getProductInfoList")
public String getProductInfoList(@RequestParam("number") Integer number) {if (number % 2 == 0) {return "success";}RestTemplate restTemplate = new RestTemplate();return restTemplate.postForObject("http://127.0.0.1:8519/buyer/product/listForOrder",Collections.singletonList("157875196366160022"), String.class);
}

使用配置项

在代码里写配置可能不太方便维护,我们也可以在配置文件中使用配置项进行配置。例如超时时间配置如下:

hystrix:command:default:execution:isolation:thread:timeoutInMilliseconds: 3000

若指定配置某一个方法的超时时间,将default换成相应方法名即可。如下示例:

hystrix:command:getProductInfoList:execution:isolation:thread:timeoutInMilliseconds: 3000

断路器的的配置方式也是一样的,如下示例:

hystrix:command:default:execution:isolation:thread:timeoutInMilliseconds: 3000circuitBreaker:enabled: truerequestVolumeThreshold: 10sleepWindowInMilliseconds: 10000errorThresholdPercentage: 60

feign-hystrix的使用

我们在订单服务中,使用了feign组件去调用商品服务实现服务间的通信。而feign内部已包含了hystrix,所以也可以实现服务降级。首先在订单服务项目的配置文件中,增加如下配置:

feign:hystrix:enabled: true  # 开启hystrix

到商品服务项目的client模块中,新增一个 ProductClientFallback 类,并实现ProductClient接口。代码如下:

package org.zero.springcloud.product.client;import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.zero.springcloud.product.common.DecreaseStockInput;
import org.zero.springcloud.product.common.ProductInfoOutput;import java.util.List;/*** @program: sell_product* @description: 触发服务降级时会调用相应的方法* @author: 01* @create: 2018-08-29 21:39**/
@Slf4j
@Component
public class ProductClientFallback implements ProductClient {@Overridepublic List<ProductInfoOutput> productInfoList(List<String> productIdList) {log.info("productInfoList() 触发了服务降级");return null;}@Overridepublic void decreaseStock(List<DecreaseStockInput> cartDTOList) {log.info("decreaseStock() 触发了服务降级");}
}

然后在 ProductClient 接口的@FeignClient注解里增加 fallback 属性,并指定以上编写的实现类。当某个接口触发降级时,就会调用实现类里的方法。代码如下:

package org.zero.springcloud.product.client;import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.zero.springcloud.product.common.DecreaseStockInput;
import org.zero.springcloud.product.common.ProductInfoOutput;import java.util.List;/*** @program: sell_order* @description: 配置需要调用的接口地址* @author: 01* @create: 2018-08-19 12:14**/
@FeignClient(name = "PRODUCT", fallback = ProductClientFallback.class)
public interface ProductClient {/*** 调用商品服务-按id查询商品列表* 注意,接口地址需要填写完整** @param productIdList productIdList* @return List<ProductInfo>*/@PostMapping("/buyer/product/listForOrder")List<ProductInfoOutput> productInfoList(@RequestBody List<String> productIdList);/*** 调用商品服务-扣库存** @param cartDTOList cartDTOList*/@PostMapping("/buyer/product/decreaseStock")void decreaseStock(@RequestBody List<DecreaseStockInput> cartDTOList);
}

编写完以上的代码后,不要忘了安装到maven本地仓库中,安装命令如下:

mvn clean -Dmaven.test.skip=true install

回到订单服务,在启动类上增加@ComponentScan注解,扩大包扫描范围:

package org.zero.springcloud.order.server;import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;@SpringCloudApplication
@ComponentScan(basePackages = "org.zero.springcloud")
@EnableFeignClients(basePackages = "org.zero.springcloud.product.client")
public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}
}

重启订单服务项目,访问创建订单接口,如下:

控制台输出如下:

注:此时我已关闭了商品服务,所以才会触发服务降级

如果是超时导致服务降级的话,可以在配置文件中配置feign的超时时间,如下:

feign:client:config:default:connectTimeout: 5000readTimeout: 5000loggerLevel: basic

hystrix-dashboard

hystrix-dashboard是一个可视化的熔断监视工具,我们本小节来看看如何在项目中使用这个工具。我们以订单服务项目为例,首先在pom.xml文件中,增加如下依赖:

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

在启动类中,增加@EnableHystrixDashboard注解。代码如下:

package org.zero.springcloud.order.server;import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;@EnableHystrixDashboard
@SpringCloudApplication
@ComponentScan(basePackages = "org.zero.springcloud")
@EnableFeignClients(basePackages = "org.zero.springcloud.product.client")
public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}
}

在config包下新建一个 HystrixConfig 配置类,用于配置 HystrixMetricsStreamServlet 。代码如下:

package org.zero.springcloud.order.server.config;import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @program: sell_order* @description: 配置HystrixMetricsStreamServlet* @author: 01* @create: 2018-08-29 22:22**/
@Configuration
public class HystrixConfig {@Beanpublic HystrixMetricsStreamServlet hystrixMetricsStreamServlet() {return new HystrixMetricsStreamServlet();}@Beanpublic ServletRegistrationBean registration(HystrixMetricsStreamServlet servlet) {ServletRegistrationBean<HystrixMetricsStreamServlet> registrationBean = new ServletRegistrationBean<>();registrationBean.setServlet(servlet);//是否启用该registrationBeanregistrationBean.setEnabled(true);registrationBean.addUrlMappings("/hystrix.stream");return registrationBean;}
}

完成以上代码的编写后,重启项目,访问http://localhost:9080/hystrix,会进入到如下页面中:

通过Hystrix Dashboard主页面的文字介绍,我们可以知道,Hystrix Dashboard共支持三种不同的监控方式:

  • 默认的集群监控:通过URL:http://turbine-hostname:port/turbine.stream开启,实现对默认集群的监控。
  • 指定的集群监控:通过URL:http://turbine-hostname:port/turbine.stream?cluster=[clusterName]开启,实现对clusterName集群的监控。
  • 单体应用的监控:通过URL:http://hystrix-app:port/hystrix.stream开启,实现对具体某个服务实例的监控。
  • Delay:控制服务器上轮询监控信息的延迟时间,默认为2000毫秒,可以通过配置该属性来降低客户端的网络和CPU消耗。
  • Title:该参数可以展示合适的标题。

我这里使用的是单体应用的监控,点击Monitor Stream后,进入到如下页面,在此页面可以看到这个项目的请求信息:

我们来对这些指标进行一个简单的说明:

转载于:https://blog.51cto.com/zero01/2173377

Spring Cloud Hystrix - 服务容错相关推荐

  1. Spring Cloud Hystrix 服务容错保护

    在微服务架构中,我们将系统拆分成了很多服务单元,各单元的应用间通过服务注册与订阅的方式互相依赖.由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服务自身间 ...

  2. Spring Cloud微服务简介

    1. 基础知识1 什么是微服务架构? 与单体系统的区别 如何实施微服务? 微服务优缺点 为什么选择Spring Cloud? 微服务技术选型 为什么选择Spring Cloud? Spring Clo ...

  3. Spring Cloud之Hystrix服务容错

    Spring Cloud之Hystrix服务容错 Hystrix的概述 Hystrix的使用 相关依赖 Eureka注册中心 服务提供者 服务消费者 执行测试 @HystrixCommand详解 服务 ...

  4. 实战系列-Spring Cloud微服务中三把利器Feign、Hystrix、Ribbon

    导语   在之前的分享中分享过关于Fegin的底层实现原理,以及Spring Cloud OpenFegin的启动原理.在这次的分享中主要总结一下Spring Cloud 微服务架构的三把利器.对于F ...

  5. spring cloud微服务治理eureka、hystrix、zuul代码例子

    spring cloud微服务中台服务代码例子,包括eureka.hystrix.zuul https://github.com/birdstudiocn/spring-cloud-sample/tr ...

  6. spring cloud微服务分布式云架构 - Spring Cloud集成项目简介

    Spring Cloud集成项目有很多,下面我们列举一下和Spring Cloud相关的优秀项目,我们的企业架构中用到了很多的优秀项目,说白了,也是站在巨人的肩膀上去整合的.在学习Spring Clo ...

  7. Spring Cloud微服务实战pdf

    下载地址:网盘下载 内容提要 编辑 <Spring Cloud微服务实战>从时下流行的微服务架构概念出发,详细介绍了Spring Cloud针对微服务架构中几大核心要素的解决方案和基础组件 ...

  8. Spring Cloud Hystrix理解与实践(一):搭建简单监控集群

    前言 在分布式架构中,所谓的断路器模式是指当某个服务发生故障之后,通过断路器的故障监控,向调用方返回一个错误响应,这样就不会使得线程因调用故障服务被长时间占用不释放,避免故障的继续蔓延.Spring ...

  9. Spring Cloud 学习笔记(四)-Spring Cloud Hystrix

    Spring Cloud 学习笔记(四)-Spring Cloud Hystrix 由于前一阵子项目的原因,今天才继续弄上,今天想学习一下Hystrix组件 这个组件还挺抽象的,最开始我一直没太明白, ...

  10. 基于 Spring Cloud 的服务治理实践

    http://www.infoq.com/cn/articles/spring-cloud-based-service-governance 大家好,我是来自贝壳金控的赵文乐,目前主要从事架构方面的工 ...

最新文章

  1. CSDN蒋涛提出技术社区三倍速定律,称下一个20年全球开发者数量将过亿
  2. 用或非门构造D型触发器
  3. 学习笔记Spark(七)—— Spark SQL应用(2)—— Spark DataFrame基础操作
  4. 数据分析方法有哪些_数据分析方法
  5. 145. Binary Tree Postorder Traversal
  6. 面试了上百位性能测试后,我发现了一个令人不安的事实
  7. Kotlin中使用RxJAVA的map()操作符遇到的问题
  8. 故障解决:三块300GSAS硬盘 一块硬盘状态灯为红色
  9. vs2017安装好后颜色主题、字体、语言包的设置
  10. python3高性能网络编程_Python高级网络编程系列之基础篇
  11. 阶段5 3.微服务项目【学成在线】_day02 CMS前端开发_06-vuejs研究-vuejs基础-v-on指令...
  12. 学会System Generator(1)入门与安装
  13. Gilbreath原理中的数学与魔术(一)——Gilbreath Shuffle First Principle
  14. 景联文科技入选全国信息技术标准化技术委员会生物特征识别技术委员会
  15. 三峡大学校赛----十万桃花图(线性基)
  16. python中clear和clear()
  17. TCP/IP协议分层模型详解
  18. 三千预算进卡吧的顺口溜是啥
  19. Android Studio 配置翻译工具
  20. apache添加php语言模块,在apache中添加php处理模块-Go语言中文社区

热门文章

  1. yii2 mysql 队列_yii2.0 中的队列
  2. bat 暂停一段时间_BAT面试问是否具备3年工作经验,这么回答绝了!
  3. dd命令打包多个文件_Android shell 下dd命令浅析
  4. java 默认为空的注解,错误注解的字段设置一个默认的空值
  5. 为什么不建议吃小绿叶_为什么看了那么多食谱,还是不知道给宝宝吃什么?
  6. web在session设置的账户用户名显示为空_海蜘蛛路由Web认证怎么设置 海蜘蛛路由Web认证方法【介绍】...
  7. c 语言打印沙漏图形,PAT乙级 1027打印沙漏 [图形输出]
  8. 深度优先搜索(DFS)与广度优先搜索(BFS) -- 总结
  9. 力扣题目系列:1370. 上升下降字符串(Python题解)
  10. 中指北针怎么画_木工图纸怎么快速看懂?助你看懂施工图的9个技巧