Spring Cloud学习笔记-006
服务容错保护:Spring Cloud Hystrix
在微服务架构中,我们将系统拆分成了很多服务单元,各单元的应用间通过服务注册与订阅的方式互相依赖。由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服务自身问题出现调用故障或延迟,而这些问题会直接导致调用方的对外服务业出现延迟,若此时调用方的请求不断增加,最后就会因等待出现故障的依赖响应形成任务积压,最终导致自身服务的瘫痪。
举个例子,在一个电商网站中,我们可能会将系统拆分成用户、订单、库存、积分、评论等一系列服务单元。用户创建一个订单的时候,客户端将调用订单服务的创建订单接口,此时创建订单接口又会向库存服务来请求出货(判断是否有足够库存来出货)。此时若库存服务因自身处理逻辑等原因造成响应缓慢,会直接导致创建订单服务的线程被挂起,以等待库存申请服务的响应,在漫长的等待之后用户会因为请求库存失败而得到创建订单失败的结果。如果在高并发的情况下,因这些挂起的线程在等待库存服务的响应而未能释放,使得后续到来的创建订单请求被阻塞,最终导致订单服务业不可用。
在微服务架构中,存在着那么多的服务单元,若一个单元出现故障,就很容易因依赖关系而引发故障的蔓延,最终导致整个系统的瘫痪,这样的架构相较传统架构更加不稳定。为了解决这样的问题,产生了断路器等一系列的服务保护机制。
断路器:在分布式架构中,当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个错误的响应,而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。
针对上述问题,Spring Cloud Hystrix实现了断路器、线程隔离等一系列服务保护功能。它也是基于Netflix的开源框架Hystrix实现的,该框架的目标在于通过控制那些访问远程系统、服务和第三方库节点,从而对延迟和故障提供更强大的容错能力。Hystrix具备服务降级、服务熔断、线程和信号隔离、请求缓存、请求合并以及服务监控等强大功能。
1. 为了测试Spring Cloud Hystrix,我们需要先搭建一个基础架构:
- demo-eureka工程:服务注册中心,端口为7001
- demo-member工程:会员服务单元,启动两个服务实例,端口分别为5001、5002,该服务中提供一个接口“/member”,返回一个字符串信息。
- demo-customer-ribbon工程:使用Ribbon实现的服务消费者,端口为9001,该服务中通过提供一个接口“/getMember”,通过Ribbon调用demo-member工程的“/member”接口。
2. 在未加入断路器之前,关闭5001的实例,发送GET请求到http://localhost:9001/getMember,可以看到浏览器提示以下信息:
3. 然后引入Spring Cloud Hystrix。在demo-customer-ribbon工程的pom.xml中引入spring-cloud-starter-hystrix依赖:
4. 在demo-customer-ribbon工程的启动类中使用@EnableCircuitBreaker注解开启断路器功能(注:这里还可以是所有Spring Cloud应用中的@SpringCloudApplication注解来修饰启动类,进入该注解源码可以看到,该注解包含了上述我们所引用的三个注解,这也意味着一个Spring Cloud标准应用应包含服务发现以及断路器):
5. 改造服务消费方式,新增CustomerRibbonService类,注入RestTemplate实例。然后,将在CustomerRibbonController中对RestTemplate的使用迁移到新增的CustomerRibbonService类中,最后,在CustomerRibbonService类的getMember方法上增加@HystrixCommand注解来指定回调方法(注:不要忘记在启动类上添加对service层的扫描):
6. 修改CustomerRibbonController类,注入上面实现的CustomerRibbonService实例,并在getMember方法中进行调用:
7. 接下来验证一下通过断路器实现的服务回调逻辑,重新启动之前关闭的5001端口的demo-member,确保此时服务注册中心、两个demo-member以及demo-customer-ribbon均已启动,访问http://localhost:9001/getMember可以轮询两个demo-member并返回信息。此时断开5001的demo-member,然后访问http://loalhost:9001/getMember,当轮询到5001服务端时,输出内容为error,不再是之前的错误内容,Hystrix的服务回调生效。
8. 除了通过断开具体的服务实例来模拟某个节点无法访问的情况之外,我们还可以模拟一下服务阻塞(长时间未响应)的情况。对demo-member的/member接口进行改装:
9. 重新启动demo-member和demo-customer-ribbon实例,连续访问http://localhost:9001/getMember几次,通过观察可以看到,当控制台输出的时间大于1000的时候,就会返回error,即服务消费者因调用的服务超时从而触发熔断请求,并调用回调逻辑返回结果,由此也可以猜测到Hystrix的默认超时时间为1000毫秒。