前一章节,咱们知道了如何利用
RestTemplate
+Ribbon
和Feign
的方式进行服务的调用。在微服务架构中,一个服务可能会调用不少的其余微服务应用,虽然作了多集群部署,但可能还会存在诸如网络缘由或者服务提供者自身处理的缘由,或多或少都会出现请求失败或者请求延迟问题,若服务提供者长期未对请求作出回应,服务消费者又不断的请求下,可能就会形成服务提供者服务崩溃,进而服务消费者也一块儿跟着不可用,严重的时候就发生了系统雪崩
了。鉴于此,产生了断路器等一系列的服务保护机制。本章节,就来讲下如何利用Hystrix
进行容错处理。html
按照此系列的惯例,咱们先来了解下一些相关的知识。java
注:如下部份内容转至大佬纯洁的微笑:熔断器Hystrix。git
容错处理是指软件运行时,能对由非正常因素引发的运行错误给出适当的处理或信息提示,使软件运行正常结束——百度百科程序员
从百度百科的解释中能够看出,简单理解,所谓的容错处理
其实就是捕获异常了,不让异常影响系统的正常运行,正如java
中的try catch
同样。github
而在微服务调用中,自身异常可自行处理外,对于依赖的服务若发生错误,或者调用异常,或者调用时间过长等缘由时,避免长时间等待,形成系统资源耗尽。 通常上都会经过设置请求的超时时间
,如http
请求中的ConnectTimeout
和ReadTimeout
;再或者就是使用熔断器
模式,隔离问题服务,防止级联错误等。spring
在微服务架构中,存在不少的微服务单元,各个微服务之间经过网络进行通信,不免出现依赖关系,若某一个单元
出现故障
,就很容易因依赖关系而引起故障的蔓延,产生“雪崩效应”
,最终致使整个系统的瘫痪。设计模式
下面这张图,相比你们都有看过了。浏览器
如图所示:A做为服务提供者,B为A的服务消费者,C和D是B的服务消费者。A不可用引发了B的不可用,并将不可用像滚雪球同样放大到C和D时,雪崩效应就造成了。也就应了那句话:星星之火,能够燎原!服务器
熔断器,和现实生活中的空气开关
做用很像。它能够实现快速失败,若是它在一段时间内侦测到许多相似的错误,会强迫其之后的多个调用快速失败,再也不访问远程服务器,从而防止应用程序不断地尝试执行可能会失败的操做,使得应用程序继续执行而不用等待修正错误,或者浪费CPU时间去等到长时间的超时产生。熔断器也可使应用程序可以诊断错误是否已经修正,若是已经修正,应用程序会再次尝试调用操做。微信
熔断器模式就像是那些容易致使错误的操做的一种代理。这种代理可以记录最近调用发生错误的次数,而后决定使用容许操做继续,或者当即返回错误。
能够看出,熔断器一共有三种状态,之间转换关系以下:
我的以为,主要仍是快速失败,避免请求堆积,压垮服务器。进而起到保护服务高可用的目的。
Hystrix是一个实现了超时机制和断路器模式的工具类库。
Hystrix是有Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或第三方库,防止级联失败,从而提高系统的可用性和容错性。
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
注解,咱们能够放在任何一个调用函数里面,以此实现调用方法发生异常或者错误时,能够快速返回,避免持续请求,形成资源的耗尽。
如上小节说示例的,当咱们方法不少时,要是分别编写一个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
系列教程,内容可能会相似,望多多包涵了。原创不易,码字不易,还但愿你们多多支持。若文中有错误之处,还望提出,谢谢。
499452441
lqdevOps
我的博客:http://blog.lqdev.cn
源码示例:https://github.com/xie19900123/spring-cloud-learning
原文地址:http://blog.lqdev.cn/2018/09/23/SpringCloud/chapter-five/