在上一篇文章中,咱们已使用Spring Cloud和Netflix OSS中的核心组件,如Eureka、Ribbon和Zuul,部分实现了操做模型(operations model),容许单独部署的微服务相互通讯。在本文中,咱们继续关注微服务环境中的故障处理,经过Hystrix(Netflix Circuit Breaker)提高服务弹性。html
如今咱们创建的系统开始出现故障,组合服务(composite service)依赖的部分核心服务忽然没有反应,若是故障没有正确处理,将进一步损害组合服务。java
一般,咱们将这一类问题称为失败链(a chain of failures),一个组件中的错误将致使依赖于错误组件中的其余组件也产生错误。在基于微服务的系统中,尤为是大量独立部署的微服务相互通讯,这一状况须要特别关注。针对这一问题的通用解决方案是应用电路断路器模式(circuit breaker pattern),详细信息能够查阅其余文档,或者阅读Fowler-Circuit Breaker的文章。一个典型电路断路器应用以下状态转换图:git
(Source: Release It!) https://pragprog.com/book/mnee/release-itgithub
以下表所示,本文将包含:Hystrix、Hystrix dashboard和Turbine。spring
1/ Netflix Hystrix – 电路断路器(Circuit Breaker)windows
Netflix Hystrix 对微服务消费方提供了电路断路器功能。若是一个服务没有响应(如超时或者网络链接故障),Hystrix 能够在服务消费方中重定向请求到回退方法(fallback method)。若是服务重复失败,Hystrix 会打开电路,并快速失败(如直接调用内部的回退方法,再也不尝试调用服务),直到服务从新恢复正常。浏览器
为了验证是否服务再次恢复正常,即便在电路打开的状况下,Hystrix 也会容许一部分请求再次调用微服务。Hystrix 是嵌入在服务调用方内部执行的。缓存
2/ Netflix Hystrix dashboard和Netflix Turbine –监控仪表盘(Monitor Dashboard)服务器
Hystrix仪表盘用来提供电路断路器的图形化视图;Turbine 基于Eureka服务器的信息,获取系统中全部电路断路器的信息,提供给仪表盘。下图是Hystrix仪表盘和Turbine工做视图:网络
将前一部分Part 1实现的微服务系统,进一步添加支持性的基础服务-Hystrix Dashboard和Turbine。另外,微服务product-composite也加强了基于Hystrix的电路断路器。新增的2个组件标识为红色外框,以下图所示:
在Part 1中,咱们重点强调了微服务和单体应用的差别,将每个微服务独立部署运行(独立进程)
在Part 1中,咱们使用Java SE 8,Git和Gradle工具。接下来访问源代码,并进行编译:
$ git clone https://github.com/callistaenterprise/blog-microservices.git
$ cd blog-microservices
$ git checkout -b B2 M2.1
$ ./build-all.sh
若是运行在windows平台,请执行相应的bat文件 – build-all.bat。
在Part 1源码的基础上,新增了2个源码组件-monitor-dashboard和turbine:
编译输出8条log日志:
BUILD SUCCESSFUL
和Part 1源代码进行比较,本文在微服务product-composite中新增了Hystrix电路断路器的使用。所以,咱们将关注电路断路器部分新增的额外代码。
4.1 Gradle依赖
如今,咱们在build文件中加入了几个Hystrix相关的starter依赖。由于Hystrix使用RabbitMQ消息中间件在电路断路器和仪表盘(dashboard)之间通讯,所以咱们也须要添加相应的依赖。
对于服务消费方,如须要使用Hystrix做为电路断路器,则须要添加以下依赖配置:
compile("org.springframework.cloud:spring-cloud-starter-hystrix:1.0.0.RELEASE")
compile("org.springframework.cloud:spring-cloud-starter-bus-amqp:1.0.0.RELEASE")
compile("org.springframework.cloud:spring-cloud-netflix-hystrix-amqp:1.0.0.RELEASE")
更完整的示例,能够查看product-composite-service/build.gradle文件。
为了搭建Turbine 服务器,须要添加以下依赖:
compile('org.springframework.cloud:spring-cloud-starter-turbine-amqp:1.0.0.RELEASE')
更完整的示例,能够查看turbine/build.gradle文件。
4.2 基础设施服务器
在标准的Spring Boot应用中,添加@EnableTurbineAmqp标注,就能够搭建Turbine服务器了。
@SpringBootApplication
@EnableTurbineAmqp
@EnableDiscoveryClient
public class TurbineApplication {
public static void main(String[] args) {
SpringApplication.run(TurbineApplication.class, args);
}
}
完整的示例,能够查看TurbineApplication.java文件。
搭建Hystrix仪表盘,则须要添加@EnableHystrixDashboard标注。完整的示例,能够查看HystrixDashboardApplication.java文件。
经过上述简单的标注,就能够得到默认服务器配置了。可根据须要使用特定的配置,覆盖默认的配置。
4.3 业务服务
为了启用Hystrix,须要在Spring Boot应用中添加@EnableCircuitBreaker标注。为了让Hystrix真实地生效,还须要在Hystrix监控的方法上标注@HystrixCommand,在这个标注中,还能够指定回退方法(fallback method),以下所示:
@HystrixCommand(fallbackMethod = "defaultReviews")
public ResponseEntity<List<Review>> getReviews(int productId) {
...
}
public ResponseEntity<List<Review>> defaultReviews(int productId) {
...
}
在发生错误的时候(如调用服务失败或者超时),Hystrix会调用回退方法;或者在电路打开的时候,进行快速失败处理。完整的示例,能够查看ProductCompositeIntegration.java文件。
如前所述,Hystrix经过RabbitMQ消息中间件进行内部通讯,所以咱们在启动微服务系统以前,须要先安装并运行RabbitMQ。能够访问以下连接,了解RabbitMQ安装教程:
https://www.rabbitmq.com/download.html
安装完成以后,接着启动RabbitMQ,经过运行RabbitMQ安装目录下的sbin子目录中的rabbitmq-server程序进行启动。
$ ~/Applications/rabbitmq_server-3.4.3/sbin/rabbitmq-server
RabbitMQ 3.4.3. Copyright (C) 2007-2014 GoPivotal, Inc.
## ## Licensed under the MPL. See http://www.rabbitmq.com/
## ##
########## Logs: /Users/magnus/Applications/rabbitmq_server-3.4.3/sbin/../var/log/rabbitmq/rabbit@Magnus-MacBook-Pro.log
###### ## /Users/magnus/Applications/rabbitmq_server-3.4.3/sbin/../var/log/rabbitmq/rabbit@Magnus-MacBook-Pro-sasl.log
##########
Starting broker... completed with 6 plugins.
如在windows系统中,确保RabbitMQ 服务已经启动。
如今咱们准备好启动系统了。使用./gradlew命令启动每个微服务。
首先启动基础设施微服务:
$ cd support/discovery-server; ./gradlew bootRun
$ cd support/edge-server; ./gradlew bootRun
$ cd support/monitor-dashboard; ./gradlew bootRun
$ cd support/turbine; ./gradlew bootRun
一旦上述服务启动完成以后,接着启动业务微服务:
$ cd core/product-service; ./gradlew bootRun
$ cd core/recommendation-service; ./gradlew bootRun
$ cd core/review-service; ./gradlew bootRun
$ cd composite/product-composite-service; ./gradlew bootRun
如在windows平台,能够执行相应的bat文件 – start-all.bat。
一旦微服务启动完成,并注册到服务发现服务器(Service Discovery Server),将同时输出以下日志:
DiscoveryClient ... - registration status: 204
和Part 1 同样,咱们能够在服务发现Web应用中看到以下4个业务服务和一个edge-server,以下所示(http://localhost:8761):
最后,验证电路断路器工做正常。在处于closed状态时,经过edge-server访问组合服务(composite service),输出响应结果以下:
$ curl -s localhost:8765/productcomposite/product/1 | jq .
{
"name": "name",
"productId": 1,
"recommendations": [
{
"author": "Author 1",
"rate": 1,
"recommendationId": 0
},
...
],
"reviews": [
{
"author": "Author 1",
"reviewId": 1,
"subject": "Subject 1"
},
...
],
"weight": 123
}
在浏览器中首先访问http://localhost:7979 地址(Hystrix Dashboard),接着在文本框中输入 http://localhost:8989/turbine.stream,并点击Monitor Stream 按钮:
咱们看到组合服务有3个电路断路器正在运行中,分别是3个依赖的核心服务。目前都工做正常。接着,咱们准备尝试故障测试,验证电路断路器发挥做用。
中止review微服务,再次尝试以前的命令:
$ curl -s localhost:8765/productcomposite/product/1 | jq .
{
"name": "name",
"productId": 1,
"recommendations": [
{
"author": "Author 1",
"rate": 1,
"recommendationId": 0
},
...
],
"reviews": null,
"weight": 123
}
返回的响应报文中review部分是空的,可是其他部分报文保持不变。查看product-composite服务日志,能够发现以下警告信息:
2015-04-02 15:13:36.344 INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration : GetRecommendations...
2015-04-02 15:13:36.497 INFO 29901 --- [teIntegration-2] s.c.m.c.p.s.ProductCompositeIntegration : GetReviews...
2015-04-02 15:13:36.498 WARN 29901 --- [teIntegration-2] s.c.m.composite.product.service.Util : Failed to resolve serviceId 'review'. Fallback to URL 'http://localhost:8081/review'.
2015-04-02 15:13:36.500 WARN 29901 --- [teIntegration-2] s.c.m.c.p.s.ProductCompositeIntegration : Using fallback method for review-service
电路断路器检测到review服务发生了故障,将请求路由到服务消费方的回退方法(fallback method)。在本示例中,咱们只是简单地返回一个null,但咱们也能够返回一个本地缓存数据,以便在review服务发生故障时,提供更好的效果。
由于此时故障发生频率并不高,所以电路仍然是闭合状态(closed):
咱们接下来提升故障频率,并超出Hystrix打开电路的限制,开始快速失败。这里,咱们使用Apache HTTP server benchmarking tool是实现这一目的:
ab -n 30 -c 5 localhost:8765/productcomposite/product/1
如今电路打开了:
随后的请求将快速失败,也就是说,电路断路器将直接转发请求到回退方法,再也不调用review服务。此时,log日志中将再也不有GetReviews相关日志。
2015-04-02 15:14:03.930 INFO 29901 --- [teIntegration-5] s.c.m.c.p.s.ProductCompositeIntegration : GetRecommendations...
2015-04-02 15:14:03.984 WARN 29901 --- [ XNIO-2 task-62] s.c.m.c.p.s.ProductCompositeIntegration : Using fallback method for review-service
然而,Hystrix不时地让一部分请求经过电路,查看是否能够调用成功,也就是检查review服务是否再次恢复正常。咱们能够屡次重复执行curl调用,查看product-composite服务的输出日志:
2015-04-02 15:17:33.587 INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration : GetRecommendations...
2015-04-02 15:17:33.769 INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration : GetReviews...
2015-04-02 15:17:33.769 WARN 29901 --- [eIntegration-10] s.c.m.composite.product.service.Util : Failed to resolve serviceId 'review'. Fallback to URL 'http://localhost:8081/review'.
2015-04-02 15:17:33.770 WARN 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration : Using fallback method for review-service
2015-04-02 15:17:34.431 INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration : GetRecommendations...
2015-04-02 15:17:34.569 WARN 29901 --- [ XNIO-2 task-18] s.c.m.c.p.s.ProductCompositeIntegration : Using fallback method for review-service
2015-04-02 15:17:35.209 INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration : GetRecommendations...
2015-04-02 15:17:35.402 WARN 29901 --- [ XNIO-2 task-20] s.c.m.c.p.s.ProductCompositeIntegration : Using fallback method for review-service
2015-04-02 15:17:36.043 INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration : GetRecommendations...
2015-04-02 15:17:36.192 WARN 29901 --- [ XNIO-2 task-21] s.c.m.c.p.s.ProductCompositeIntegration : Using fallback method for review-service
2015-04-02 15:17:36.874 INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration : GetRecommendations...
2015-04-02 15:17:37.031 WARN 29901 --- [ XNIO-2 task-22] s.c.m.c.p.s.ProductCompositeIntegration : Using fallback method for review-service
2015-04-02 15:17:41.148 INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration : GetRecommendations...
2015-04-02 15:17:41.340 INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration : GetReviews...
2015-04-02 15:17:41.340 WARN 29901 --- [eIntegration-10] s.c.m.composite.product.service.Util : Failed to resolve serviceId 'review'. Fallback to URL 'http://localhost:8081/review'.
2015-04-02 15:17:41.341 WARN 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration : Using fallback method for review-service
从log日志的输出中,咱们发现每5个调用,容许一次尝试调用review服务(仍然没有成功调用)。
如今,咱们再次启动review服务,继续尝试调用组合服务product-composite。
备注:此时,你可能须要一点耐心(最多1分钟)。在调用成功以前,须要服务发现服务器(Eureka)和动态路由(Ribbon)必须感知到review服务实例再次恢复可用。
如今,咱们看到返回结果正常了,review节点也恢复到返回报文中,电路也再次闭合(closed):
咱们已经看到了Netflix Hystrix如何用做电路断路器(Circuit Breaker)有效地处理失败链的问题。失败链是指:当单个微服务故障时,因为故障的扩散,会致使系统中大范围微服务故障事故。幸好Spring Cloud框架提供的简单标注和starter依赖,能够很是容易在Spring环境中启用Hystrix。最后,Hystrix dashboard和Turbine提供的仪表盘(Dashboard)功能,使得监控系统范围内的大量电路断路器变得切实可行。
在构建微服务的下一篇文章中,咱们将学习如何使用OAuth 2.0 来限制对暴露为外部API的微服务进行访问。
英文原文连接:
Building microservices with Spring Cloud and Netflix OSS, part 2
相关连接: