7天学会使用springcloud(四)
7天学会使用springcloud(四)
什么是熔断机制
最近电脑翻墙出了点问题,无法到wiki上去看它的定义,只能上百度百科上去找这个定义了,这个名词其实引自股票行业:
熔断机制(Circuit Breaker),也叫自动停盘机制,是指当股指波幅达到规定的熔断点时,交易所为控制风险采取的暂停交易措施。 [1] 具体来说是对某一合约在达到涨跌停板之前,设置一个熔断价格,使合约买卖报价在一段时间内只能在这一价格范围内交易的机制。
引入到软件架构中,就是当某个应用服务达到一个风险值的时候(内存,cpu等),使此应用暂停服务,以免影响整个服务的正常运行。
springcloud的熔断机制
在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用(RPC),在Spring Cloud可以用RestTemplate+Ribbon和Feign来调用。为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。
为了解决这个问题,业界提出了断路器模型。
springcloud熔断机制有几种方式
路由熔断
zull除了做网关,还可以做路由熔断。
当我们的后端服务出现异常的时候,我们不希望将异常抛出给最外层,期望服务可以自动进行一降级。Zuul给我们提供了这样的支持。当某个服务出现异常时,直接返回我们预设的信息。
目前最新的zuul是通过filter的方式进行熔断的
如果zuul引用的版本是:
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.3.1.RELEASE</version>
我们通过自定义的fallback方法,并且将其指定给某个route来实现该route访问出问题的熔断处理。主要继承ZuulFallbackProvider接口来实现,ZuulFallbackProvider默认有两个方法,一个用来指明熔断拦截哪个服务,一个定制返回内容
public interface ZuulFallbackProvider {
/**
* The route this fallback will be used for.
* @return The route the fallback will be used for.
*/
public String getRoute();
/**
* Provides a fallback response.
* @return The fallback response.
*/
public ClientHttpResponse fallbackResponse();
}
实现类通过实现getRoute方法,告诉Zuul它是负责哪个route定义的熔断。而fallbackResponse方法则是告诉 Zuul 断路出现时,它会提供一个什么返回值来处理请求。
后来Spring又扩展了此类,丰富了返回方式,在返回的内容中添加了异常信息,因此最新版本建议直接继承类FallbackProvider 。
我们以上面的eruake-service服务为例,定制它的熔断返回内容。
@Component
public class ProducerFallback implements FallbackProvider {
private final Logger logger = LoggerFactory.getLogger(FallbackProvider.class);
//指定要处理的 service。
@Override
public String getRoute() {
return "appclient";
}
public ClientHttpResponse fallbackResponse() {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return 200;
}
@Override
public String getStatusText() throws IOException {
return "OK";
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("The service is unavailable.".getBytes());
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
@Override
public ClientHttpResponse fallbackResponse(Throwable cause) {
if (cause != null && cause.getCause() != null) {
String reason = cause.getCause().getMessage();
logger.info("Excption {}",reason);
}
return fallbackResponse();
}
}
当服务出现异常时,打印相关异常信息,并返回
“The service is unavailable.”。
手动关闭client1项目,多次访问地址:http://localhost:8888/applicent/hello?name=neo&token=xx,会交替返回:
hello neo,this is first messge
The service is unavailable.
...
根据返回结果可以看出:eurake-client-2项目已经启用了熔断,返回:The service is unavailable.
如果zuul引用的版本是:
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix</artifactId>
<version>2.0.0.M8</version>
那就用FallbackProvider代替ZuulFallbackProvider来实现。
ps:
Zuul 目前只支持服务级别的熔断,不支持具体到某个URL进行熔断。
熔断器(CircuitBreaker)
- 断路器原理
断路器的原理很简单,如同电力过载保护器。它可以实现快速失败,如果它在一段时间内侦测到许多类似的错误,会强迫其以后的多个调用快速失败,不再访问远程服务器,从而防止应用程序不断地尝试执行可能会失败的操作,使得应用程序继续执行而不用等待修正错误,或者浪费CPU时间去等到长时间的超时产生。熔断器也可以使应用程序能够诊断错误是否已经修正,如果已经修正,应用程序会再次尝试调用操作。
熔断器模式就像是那些容易导致错误的操作的一种代理。这种代理能够记录最近调用发生错误的次数,然后决定使用允许操作继续,或者立即返回错误。
引入官方的调用图:
Martin Fowler官方对断路器的定义都在这里:
https://martinfowler.com/bliki/CircuitBreaker.html
- Hystrix
Netflix has created a library called Hystrix that implements the circuit breaker pattern. In a microservice architecture, it is common to have multiple layers of service calls
hystrix是实现了martin fowler的断路器的一个框架,目前也是使用最广的。
Hystrix原理很好理解, 当Hystrix Command请求后端服务失败数量超过一定比例(默认50%), 断路器会切换到开路状态(Open). 这时所有请求会直接失败而不会发送到后端服务. 断路器保持在开路状态一段时间后(默认5秒), 自动切换到半开路状态(HALF-OPEN). 这时会判断下一次请求的返回情况, 如果请求成功, 断路器切回闭路状态(CLOSED), 否则重新切换到开路状态(OPEN). Hystrix的断路器就像我们家庭电路中的保险丝, 一旦后端服务不可用, 断路器会直接切断请求链, 避免发送大量无效请求影响系统吞吐量, 并且断路器有自我检测并恢复的能力.
以上摘自springcloud文档中关于断路器中的原文:
- Fallback
Fallback相当于是降级操作. 对于查询操作, 我们可以实现一个fallback方法, 当请求后端服务出现异常的时候, 可以使用fallback方法返回的值. fallback方法的返回值一般是设置的默认值或者来自缓存.
- 资源隔离
在Hystrix中, 主要通过线程池来实现资源隔离. 通常在使用的时候我们会根据调用的远程服务划分出多个线程池. 例如调用产品服务的Command放入A线程池, 调用账户服务的Command放入B线程池. 这样做的主要优点是运行环境被隔离开了. 这样就算调用服务的代码存在bug或者由于其他原因导致自己所在线程池被耗尽时, 不会对系统的其他服务造成影响. 但是带来的代价就是维护多个线程池会对系统带来额外的性能开销. 如果是对性能有严格要求而且确信自己调用服务的客户端代码不会出问题的话, 可以使用Hystrix的信号模式(Semaphores)来隔离资源.
熔断机制的应用场景
依赖服务调用,依赖服务如果访问失败或者服务挂了,但又不想拖垮整个应用网络,则使用它。
熔断机制有什么优缺点
解决大并发数据量情况下,某些调用链环节失败导致拖垮整个网络的情况发生
适合大型分布式应用场景,对外部依赖严重项目
提高了复杂系统之间排查线上问题的效率
使用网关路由熔断只支持具体服务,并且只适合微服务。
在Hystrix中可以支持到url,无服务限制,可以是任何服务地址。
springboot集成熔断
- zuul + zuulFilter
上面已经实现
- fegin+Hystrix
这个放到下篇文章里写吧。
参考文章: