在上一篇文章中,我们已使用Spring Cloud和Netflix OSS中的核心组件,如Eureka、Ribbon和Zuul,部分实现了操作模型(operations model),允许单独部署的微服务相互通信。在本文中,我们继续关注微服务环境中的故障处理,通过Hystrix(Netflix Circuit Breaker)提升服务弹性。

现在我们建立的系统开始出现故障,组合服务(composite service)依赖的部分核心服务突然没有反应,如果故障没有正确处理,将进一步损害组合服务。

通常,我们将这一类问题称为失败链(a chain of failures),一个组件中的错误将导致依赖于错误组件中的其他组件也产生错误。在基于微服务的系统中,尤其是大量独立部署的微服务相互通信,这一情况需要特别关注。针对这一问题的通用解决方案是应用电路断路器模式(circuit breaker pattern),详细信息可以查阅其他文档,或者阅读Fowler-Circuit Breaker的文章。一个典型电路断路器应用如下状态转换图:

(Source: Release It!) https://pragprog.com/book/mnee/release-it

1. Spring Cloud和Netflix OSS

如下表所示,本文将包含:Hystrix、Hystrix dashboard和Turbine。

1/ Netflix Hystrix – 电路断路器(Circuit Breaker)

Netflix Hystrix 对微服务消费方提供了电路断路器功能。如果一个服务没有响应(如超时或者网络连接故障),Hystrix 可以在服务消费方中重定向请求到回退方法(fallback method)。如果服务重复失败,Hystrix 会打开电路,并快速失败(如直接调用内部的回退方法,不再尝试调用服务),直到服务重新恢复正常。

为了验证是否服务再次恢复正常,即使在电路打开的情况下,Hystrix 也会允许一部分请求再次调用微服务。Hystrix 是嵌入在服务调用方内部执行的。

2/ Netflix Hystrix dashboard和Netflix Turbine –监控仪表盘(Monitor Dashboard)

Hystrix仪表盘用来提供电路断路器的图形化视图;Turbine 基于Eureka服务器的信息,获取系统中所有电路断路器的信息,提供给仪表盘。下图是Hystrix仪表盘和Turbine工作视图:

2.  系统全貌

将前一部分Part 1实现的微服务系统,进一步添加支持性的基础服务-Hystrix Dashboard和Turbine。另外,微服务product-composite也增强了基于Hystrix的电路断路器。新增的2个组件标识为红色外框,如下图所示:

在Part 1中,我们重点强调了微服务和单体应用的差异,将每一个微服务独立部署运行(独立进程)

3.  构建源代码

在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

4. 阅读源代码

和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文件。

5. 启动系统

如前所述,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个依赖的核心服务。目前都工作正常。接着,我们准备尝试故障测试,验证电路断路器发挥作用。

6. 发生故障

停止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):

7. 总结

我们已经看到了Netflix Hystrix如何用作电路断路器(Circuit Breaker)有效地处理失败链的问题。失败链是指:当单个微服务故障时,由于故障的扩散,会导致系统中大范围微服务故障事故。幸亏Spring Cloud框架提供的简单标注和starter依赖,可以非常容易在Spring环境中启用Hystrix。最后,Hystrix dashboard和Turbine提供的仪表盘(Dashboard)功能,使得监控系统范围内的大量电路断路器变得切实可行。

8. 接下来

在构建微服务的下一篇文章中,我们将学习如何使用OAuth 2.0 来限制对暴露为外部API的微服务进行访问。

英文原文链接:

Building microservices with Spring Cloud and Netflix OSS, part 2

相关链接:

基于Spring Cloud和Netflix OSS 构建微服务-Part 1

微服务操作模型

基于Spring Cloud和Netflix OSS构建微服务,Part 2的更多相关文章

  1. 基于Spring Cloud和Netflix OSS 构建微服务-Part 1

    前一篇文章<微服务操作模型>中,我们定义了微服务使用的操作模型.这篇文章中,我们将开始使用Spring Cloud和Netflix OSS实现这一模型,包含核心部分:服务发现(Servic ...

  2. 在IDEA编辑器中建立Spring Cloud的子项目包(构建微服务)

    本文介绍在IDEA编辑器中建立Spring Cloud的子项目包 总共分为5个包: 外层使用maven quickstart建立,子modules直接选择了springboot

  3. Building microservices with Spring Cloud and Netflix OSS, part 2

    In Part 1 we used core components in Spring Cloud and Netflix OSS, i.e. Eureka, Ribbon and Zuul, to ...

  4. 今天介绍一下自己的开源项目,一款以spring cloud alibaba为核心的微服务架构项目,为给企业与个人提供一个零开发基础的微服务架构。

    LaoCat-Spring-Cloud-Scaffold 一款以spring cloud alibab 为核心的微服务框架,主要目标为了提升自己的相关技术,也为了给企业与个人提供一个零开发基础的微服务 ...

  5. spring cloud 入门,看一个微服务框架的「五脏六腑」

    Spring Cloud 是一个基于 Spring Boot 实现的微服务框架,它包含了实现微服务架构所需的各种组件. 注:Spring Boot 简单理解就是简化 Spring 项目的搭建.配置.组 ...

  6. Spring Cloud(1):微服务简介

    架构的演进: 1.十年前:用户->单一服务器->单一数据库(支持十万级用户) 2.五年前:用户->负载均衡器->多台服务器->缓存集群->主从数据库(支持百万级用户 ...

  7. SpringCloud(10)使用Spring Cloud OAuth2和JWT保护微服务

    采用Spring Security AOuth2 和 JWT 的方式,避免每次请求都需要远程调度 Uaa 服务.采用Spring Security OAuth2 和 JWT 的方式,Uaa 服务只验证 ...

  8. Spring Cloud(Dalston.SR5)--Zuul 网关-微服务集群

    通过 url 映射的方式来实现 zuul 的转发有局限性,比如每增加一个服务就需要配置一条内容,另外后端的服务如果是动态来提供,就不能采用这种方案来配置了.实际上在实现微服务架构时,服务名与服务实例地 ...

  9. 使用Spring Cloud OAuth2和JWT保护微服务

    采用Spring Security AOuth2 和 JWT 的方式,避免每次请求都需要远程调度 Uaa 服务.采用Spring Security OAuth2 和 JWT 的方式,Uaa 服务只验证 ...

随机推荐

  1. 本地ssh连接到vbox中的linux

    本机是window xp系统, 安装vbox,在vbox下安装linux,想在xp中用ssh连接linux,此时需要配置网络. 1.设置vbox的网络,选择host-only 2.设置window虚拟 ...

  2. HDU5842

    Lweb and String Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)T ...

  3. We Chall-Encodings: URL -Writeup

    MarkdownPad Document html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,ab ...

  4. ContextMenu控件引用以及不用v4包的方法

    最近想撸个APP出来玩玩,本想用Yalantis出的SideMenu,结果因为依赖问题放弃了,改用他们家的ContextMenu. 如果你用了v4包 那么问题就比较简单了,直接打开项目中app中的bu ...

  5. hibernate 为什么持久化类时必须提供一个不带参数的默认构造函数

    因为hibernate框架会调用这个默认构造方法来构造实例对象..即Class类的newInstance方法 这个方法就是通过调用默认构造方法来创建实例对象的 ,另外再提醒一点,如果你没有提供任何构造 ...

  6. phpcms 列表项 内容项

    根据上一篇内容继续 首页替换完成后 接下来替换列表页 首先把列表的静态网页放入相应模板的content文件夹下,并改名为 list.html 并且创建栏目时选择下面一项 同样,头尾去掉,利用{temp ...

  7. Trick 小记

    1.\[P(A|BC) = \frac{P(AB|C)}{P(B|C)}\] 2. In EM algorithm, the usual expectation function can be wri ...

  8. Top 10 Books For Advanced Level Java Developers

    Java is one of the most popular programming language nowadays. There are plenty of books for beginne ...

  9. XML入门知识

    什么是XML? 答:指可扩展标记语言(eXtensible Markup Language),被设计用来传输和存储数据:标签没有被预定义.您需要自行定义标签:被设计为具有自我描述性. XML和HTML ...

  10. Java多线程——深入重入锁ReentrantLock

    简述 ReentrantLock 是一个可重入的互斥(/独占)锁,又称为“独占锁”. ReentrantLock通过自定义队列同步器(AQS-AbstractQueuedSychronized,是实现 ...