白话SpringCloud | 第五章:服务容错保护(Hystrix)
前言
前一章节,我们知道了如何利用
RestTemplate
+Ribbon
和Feign
的方式进行服务的调用。在微服务架构中,一个服务可能会调用很多的其他微服务应用,虽然做了多集群部署,但可能还会存在诸如网络原因或者服务提供者自身处理的原因,或多或少都会出现请求失败或者请求延迟问题,若服务提供者长期未对请求做出回应,服务消费者又不断的请求下,可能就会造成服务提供者服务崩溃,进而服务消费者也一起跟着不可用,严重的时候就发生了系统雪崩
了。鉴于此,产生了断路器等一系列的服务保护机制。本章节,就来说下如何利用Hystrix
进行容错处理。
一点知识
按照此系列的惯例,我们先来了解下一些相关的知识。
注:以下部分内容转至大佬纯洁的微笑:熔断器Hystrix。
容错处理手段
容错处理是指软件运行时,能对由非正常因素引起的运行错误给出适当的处理或信息提示,使软件运行正常结束——百度百科
从百度百科的解释中可以看出,简单理解,所谓的容错处理
其实就是捕获异常了,不让异常影响系统的正常运行,正如java
中的try catch
一样。
而在微服务调用中,自身异常可自行处理外,对于依赖的服务若发生错误,或者调用异常,或者调用时间过长等原因时,避免长时间等待,造成系统资源耗尽。
一般上都会通过设置请求的超时时间
,如http
请求中的ConnectTimeout
和ReadTimeout
;再或者就是使用熔断器
模式,隔离问题服务,防止级联错误等。
雪崩效应
在微服务架构中,存在很多的微服务单元,各个微服务之间通过网络进行通讯,难免出现依赖关系,若某一个单元
出现故障
,就很容易因依赖关系而引发故障的蔓延,产生“雪崩效应”
,最终导致整个系统的瘫痪。
下面这张图,相比大家都有看过了。
如图所示:A作为服务提供者,B为A的服务消费者,C和D是B的服务消费者。A不可用引起了B的不可用,并将不可用像滚雪球一样放大到C和D时,雪崩效应就形成了。也就应了那句话:星星之火,可以燎原!
熔断器
熔断器,和现实生活中的空气开关
作用很像。它可以实现快速失败,如果它在一段时间内侦测到许多类似的错误,会强迫其以后的多个调用快速失败,不再访问远程服务器,从而防止应用程序不断地尝试执行可能会失败的操作,使得应用程序继续执行而不用等待修正错误,或者浪费CPU时间去等到长时间的超时产生。熔断器也可以使应用程序能够诊断错误是否已经修正,如果已经修正,应用程序会再次尝试调用操作。
熔断器模式就像是那些容易导致错误的操作的一种代理。这种代理能够记录最近调用发生错误的次数,然后决定使用允许操作继续,或者立即返回错误。
可以看出,熔断器一共有三种状态,之间转换关系如下:
- 关闭状态
当熔断器处于关闭状态时,请求是可以被放行的;
当熔断器统计的失败次数触发开关时,转为打开状态。 - 打开状态
当熔断器处于打开状态时,所有请求都是不被放行的,直接返回失败;
只有在经过一个设定的时间窗口周期后,熔断器才会转换到半开状态 - 半开状态
当熔断器处于半开状态时,当前只能有一个请求被放行;
这个被放行的请求获得远端服务的响应后,假如是成功的,熔断器转换为关闭状态,否则转换到打开状态。
个人觉得,主要还是快速失败,避免请求堆积,压垮服务器。进而起到保护服务高可用的目的。
Hystrix实践
何为Hystrix
Hystrix是一个实现了超时机制和断路器模式的工具类库。
Hystrix是有Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或第三方库,防止级联失败,从而提升系统的可用性和容错性。
Hystrix容错机制:
- 包裹请求:使用HystrixCommand包裹对依赖的调用逻辑,每个命令在独立线程中执行,这是用到了设计模式“命令模式”。
- 跳闸机制:当某服务的错误率超过一定阈值时,Hystrix可以自动或手动跳闸,停止请求该服务一段时间。
- 资源隔离:Hystrix为每个依赖都维护了一个小型的线程池,如果该线程池已满,发往该依赖的请求就被立即拒绝,而不是排队等候,从而加速判定失败。
- 监控:Hystrix可以近乎实时的监控运行指标和配置的变化。如成功、失败、超时、被拒绝的请求等。
- 回退机制:当请求失败、超时、被拒绝,或当断路器打开时,执行回退逻辑。回退逻辑可自定义。
- 自我修复:断路器打开一段时间后,会自动进入半开状态,断路器打开、关闭、半开的逻辑转换。
下图就是Hystrix
的回退策略,防止级联故障。
常规方式整合Hystrix
创建个工程spring-cloud-hystrix
工程。
0.引入POM依赖。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
1.启动类,加入注解@EnableHystrix
,同时申明一个实现负载均衡的RestTemplate
。(关于消费者服务可查看:第四章:服务消费者(RestTemple+Ribbon+Feign),这里不再阐述了。)
/**
* 熔断器示例
* @author oKong
*
*/
@SpringBootApplication
@EnableHystrix
@EnableDiscoveryClient
@Slf4j
public class HystrixApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(HystrixApplication.class, args);
log.info("sprign-cloud-hystrix启动!");
}
@Bean
@LoadBalanced
public RestTemplate restTemplat() {
return new RestTemplate();
}
}
2.编写一个测试类,加入@HystrixCommand
,指定fallbackMethod
方法。
RibbonController.java
/**
* ribbon 常规方式-示例
* @author oKong
*
*/
@RestController
@Slf4j
public class RibbonController {
@Autowired
RestTemplate restTemplate;
@GetMapping("/ribbon")
@HystrixCommand(fallbackMethod="fallback")
public String hello(String name) {
log.info("使用restTemplate调用服务,参数name:{}", name);
return restTemplate.getForObject("http://eureka-client/hello?name=" + name, String.class);
}
/**
* 发生熔断时调用的方法
* @param name
* @param throwable 发生异常时的异常信息
* @return
*/
public String fallback(String name,Throwable throwable) {
log.error("熔断发生了:{}", throwable);
log.warn("restTemplate调用服务发生熔断,参数name:{}", name);
return "restTemplate调用服务发生熔断,参数name:" + name;
}
}
注意:这里fallback
方法加入了一个参数throwable
,当发生熔断时,可以获悉发生熔断的异常信息,便于定位问题和原因。
3.启动应用,访问:http://127.0.0.1:8038/ribbon?name=oKong 。正常情况下,spring-cloud-eureka-client
应用正常运行时,返回正常结果:
现在我们停止提供者服务,再次访问,可以看见已经进入熔断方法了:
控制台可以看见异常输出:
由于实例尚未被剔除注册中心的服务列表,所以提示是连接超时,等待一段时间后,再次访问服务,可以看见是提示实例不存在了:
注意:对于@HystrixCommand
注解,我们可以放在任何一个调用函数里面,以此实现调用方法发生异常或者错误时,可以快速返回,避免持续请求,造成资源的耗尽。
Feign整合Hystrix
如上小节说示例的,当我们方法很多时,要是分别编写一个fallback
估计也是崩溃的,虽然可以使用一个通用的fallback
,但未进行特殊设置下,也是无法知道具体是哪个方法发生熔断的。
而对于Feign
,我们可以使用一种更加优雅的形式进行。我们可以指定@FeignClient
注解的fallback
属性,或者是fallbackFactory
属性,后者可以获取异常信息的。
修改spring-cloud-hystrix
工程。
0.引入Feigin
的POM依赖。
<!-- feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
1.启动类,加入@EnableFeignClients
启用Feign
.
**
* 熔断器示例
* @author oKong
*
*/
@SpringBootApplication
@EnableHystrix
@EnableDiscoveryClient
@EnableFeignClients
@Slf4j
public class HystrixApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(HystrixApplication.class, args);
log.info("sprign-cloud-hystrix启动!");
}
@Bean
@LoadBalanced
public RestTemplate restTemplat() {
return new RestTemplate();
}
}
- 创建一个服务接口类
IHelloClient.java
,同时定义fallback
或者fallbackFactory
属性值。注意:两者 同时设置时,优先调用fallback
,fallbackFactory
不进行调用了。
@FeignClient(name="eureka-client",/*fallback=HelloClientFailImpl.class,*/ fallbackFactory = HelloClientFallbackFactory.class)
public interface IHelloClient {
/**
* 定义接口
* @param name
* @return
*/
@RequestMapping(value="/hello", method=RequestMethod.GET)
public String hello(@RequestParam("name") String name);
}
- 创建
fallback
和fallbackFactory
属性对应类。
HelloClientFailImpl.java
@Component("fallback")
@Slf4j
public class HelloClientFailImpl implements IHelloClient{
@Override
public String hello(String name) {
log.error("restTemplate调用[hello]服务发生熔断,参数name:{}", name);
return "restTemplate调用[hello]服务发生熔断,参数name:" + name;
}
}
HelloClientFallbackFactory/java
@Component
@Slf4j
public class HelloClientFallbackFactory implements FallbackFactory<IHelloClient>{
@Autowired
@Qualifier("fallback")
IHelloClient helloClient;
@Override
public IHelloClient create(Throwable cause) {
log.error("feign调用发生异常,触发熔断", cause);
return helloClient;
}
}
可以知道,正常fallback
就是一个接口的实现类,当发送异常时,会调用此接口实现类进行服务调用。而FallbackFactory
是也是一个接口实现类,需要实现feign.hystrix.FallbackFactory<T>
接口,在发生熔断时,调用create
方法,同时返回被调用接口的实现类,以便进行fallback处理。
3.配置文件开启feign的熔断器功能。
feign.hystrix.enabled=true
或者,申明一个Feign.Builder
类也是可以的,我们从org.springframework.cloud.openfeign.FeignClientsConfiguration
可以看出,启用feign
的条件:
所以正常,我们只需要在配置文件中加入feign.hystrix.enabled
为true
即可,注意:此属性在IDE下未进行提示的。
或者就如此类一样,申明一个bean:
@Bean
public Feign.Builder feignHystrixBuilder() {
return HystrixFeign.builder();
}
也是可以的。
4.编写一个测试类FeignController
:
/**
* feign 熔断器示例
* @author oKong
*
*/
@RestController
@Slf4j
public class FeignController {
@Autowired
IHelloClient helloClient;
@GetMapping("/feign")
public String hello(String name) {
log.info("使用feign调用服务,参数name:{}", name);
return helloClient.hello(name);
}
}
5.再次启动应用,访问:http://127.0.0.1:8038/feign?name=oKong ,正常调用如下:
关闭服务提供者,再次访问,浏览器返回了错误提示:
同时,我们使用了FallbackFactory
,控制台打印出了具体异常:
针对熔断超时时间等相关设置,可以通过@HystrixCommand
注解的各属性进行配置,主要还是commandProperties
属性值,具体的参数可查看com.netflix.hystrix.HystrixCommandProperties
类,也可以针对某个调用方法进行特殊设置。具体的可以看看这篇文章:hystrix的基本介绍和配置属性说明,或者可以去大佬程序员DD博客查阅下关于 Hystrix
相关知识点:服务容错保护(Hystrix断路器)【Dalston版】、服务容错保护(Hystrix依赖隔离)【Dalston版】,版本虽然是D版的,但原理是差不多的~
参考资料
总结
本章节主要讲解了如何整合
Hystrix
。本身Hystrix
已经包含了服务降级
、依赖隔离
、熔断器
等功能了,我们使用时并没进行特殊设置,默认都是生效的。对于一些关于Hystrix
的高级用法,比如信号量
隔离、线程池的设置等等,还有一些像超时时间
等,由于此方面了解的不多,这里就不班门弄斧了。大家可去官方网站或者谷歌搜索下相关材料下,对于一些业务场景,可进行一些自定义设置。主要还是针对@HystrixCommand
注解的相关配置。关于调用统一异常的处理相关实践,比如当提供方异常时,调用方如何进行统一异常处理,或者服务不可用时,进行统一的异常捕获,告知外围调用者服务不可用等信息。这些相关实践部分会在之后的实践篇系列文章中进行阐述的,也许不是最佳的实践,仅希望提供一个参考方案吧。这里就不表了,敬请期待~
最后
目前互联网上大佬都有分享
SpringCloud
系列教程,内容可能会类似,望多多包涵了。原创不易,码字不易,还希望大家多多支持。若文中有错误之处,还望提出,谢谢。
老生常谈
- 个人QQ:
499452441
- 微信公众号:
lqdevOps
个人博客:http://blog.lqdev.cn
源码示例:https://github.com/xie19900123/spring-cloud-learning
原文地址:http://blog.lqdev.cn/2018/09/23/SpringCloud/chapter-five/
白话SpringCloud | 第五章:服务容错保护(Hystrix)的更多相关文章
- 第五章 服务容错保护:Spring Cloud Hystrix
在微服务架构中,我们将系统拆分为很多个服务,各个服务之间通过注册与订阅的方式相互依赖,由于各个服务都是在各自的进程中运行,就有可能由于网络原因或者服务自身的问题导致调用故障或延迟,随着服务的积压,可能 ...
- 第五章 服务容错保护: Spring Cloud Hystrix
在微服务架构中, 存在着那么多的服务单元, 若一个单元出现故障, 就很容易因依赖关系而引发故障的蔓延,最终导致整个系统的瘫痪,这样的架构相较传统架构更加不稳定.为了解决这样的问题, 产生了断路器等一系 ...
- SpringCloud开发学习总结(五)—— 服务容错保护Hystrix
在微服务架构中,我们将系统拆分成了很多服务单元,各单元的应用间通过服务注册与订阅的方式相互依赖.但由于每个单元都在不同的进程中运行,一来通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服务自身 ...
- Spring Cloud(四):服务容错保护 Hystrix【Finchley 版】
Spring Cloud(四):服务容错保护 Hystrix[Finchley 版] 发表于 2018-04-15 | 更新于 2018-05-07 | 分布式系统中经常会出现某个基础服务不可用 ...
- 【Dalston】【第四章】容错保护(Hystrix)
我们在实践微服务架构时,通常会将业务拆分成一个个微服务,微服务之间通过网络进行通信,进行互相调用,造成了微服务之间存在依赖关系.我们知道由于网络原因或者自身的原因,服务并不能保证服务的100%可用,如 ...
- Spring Cloud (8) 服务容错保护-Hystrix依赖隔离
依赖隔离 docker使用舱壁模式来实现进程的隔离,使容器与容器之间不会互相影响.而Hystrix则使用该模式实现线程池的隔离,它会为每一个Hystrix命令创建一个独立的线程池,这样就算在某个Hys ...
- Spring Cloud (7) 服务容错保护-Hystrix服务降级
在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以互相调用,在Spring Cloud可以用RestTemplate+Ribbon和Feign来调用.为了保证其高可用,单个服务通常会集群 ...
- Spring Cloud (9) 服务容错保护-Hystrix断路器
断路器 断路器本身是一种开关装置,用于在电路上保护线路过载,当线路中又电路发生短路时,断路器能够及时的切断故障电路,放置发生过载.发热.甚至起火等严重后果. 在分布式架构中,断路器模式的作用也是类似, ...
- 服务容错保护hystrix
灾难性雪崩效应 如何解决灾难性雪崩效应 降级 超时降级.资源不足时(线程或信号量)降级,降级后可以配合降级接口返回托底数据.实现一个 fallback 方法, 当请求后端服务出现异常的时候, 可以使用 ...
随机推荐
- 运维利器:钉钉机器人脚本告警(Linux Python 篇)
写在前面的话 在前面的博客中已经具体提到了如何获取对的机器人的 Token 等操作,不清楚的可以参考之前写的 [运维利器:钉钉机器人脚本告警(Linux Shell 篇)]这篇博客的前部分. 本文主要 ...
- luoguP2781 传教
https://www.luogu.org/problemnew/show/P2781 简化版题意:有 n 个数,初始值为 0,进行 m 次操作,每次操作支持将 [l, r] 加 v 和查询 [l, ...
- uoj #298. 【CTSC2017】网络
#298. [CTSC2017]网络 一个一般的网络系统可以被描述成一张无向连通图.图上的每个节点为一个服务器,连接服务器与服务器的数据线则看作图上的一条边,边权为该数据线的长度.两个服务器之间的通讯 ...
- mysql设计-优化
mysql表复制 1.复制表结构 create table student like user; 2.复制表内容 insert into t3 select * from t1; mysql索引 1. ...
- 表单校验--js部分
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...
- SpringMVC中视图解析器
视图解析器:固定写法直接coppy就行 1.dispatcherServlet-servlet.xml中添加 <!-- 视图解析器InternalResourceViewResolver --& ...
- bootstrap表单控件
禁用状态: 被禁用的 fieldset 为<fieldset> 设置 disabled 属性,可以禁用 <fieldset> 中包含的所有控件. <form> &l ...
- C#实现,一列数的规则如下: 1、1、2、3、5、8、13、21、34...... 求第35位数是多少, 用递归算法实现
方法函数可以通过调用自身来进行递归.计算理论可以证明递归的作用可以完全取代循环. static void Main(string[] args) { Console.WriteLine(Ra()); ...
- 007 Android 单击事件、toast使用
第一种按钮点击事件(最常用): button=findViewById(R.id.button); button2=findViewById(R.id.button2); button.setOnCl ...
- yyy的python3第七天学习
望着小月亮:https://www.cnblogs.com/triple-y/ 请尊重原创:https://www.cnblogs.com/triple-y/p/9655753.html 第七天学习的 ...