在上一篇文章中,我们已使用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. com.atomikos.icatch.HeurHazardException: Heuristic Exception

    com.atomikos.icatch.HeurHazardException: Heuristic Exception: 删除Tomcat  bin文件夹下的spring.loglog4j.appe ...

  2. 未来手机Alo即将问世!全息投影手机的新高峰!全息3d 网

    文章来源:网络         编辑:大熊 [摘要]全息投影手机很早就开始炒,网络上的概念机也是丛出不穷,那么这款出自法国的概念机又是多么的奇葩?全息 3d 网带你一探究竟. 据外媒报道,在不久将来语 ...

  3. eNSP仿真学习,网络入门!

    为了简单的认识Internet的框架的整体结构,简单学习华为的eNSP软件来高度模拟仿真网络框架!(华为和思科公司都发布了自己的网络设备仿真软件,当然我就用国产的吧~) 华为官方的eNSP学习论坛网站 ...

  4. 安装软件(基于redhat、centos发行版)

    yum 命令的使用: yum local install package_name.rpm 安装本地rpm包yum list updates 列出所有可以更新的安装包yum update packag ...

  5. 关于github中的README.md文件

    0x01 README.md文件是用Markdown语言编写的,md=Markdown; 在线编辑工具: https://stackedit.io/editor# https://maxiang.io ...

  6. Java面向对象知识点

    对象:一切客观存在的事物都是对象 语法部分: 类的概念:1.类是对象的抽象 2.类是客观事物在人脑中的主观反应 3.类是对象的模板 类的设计: 属性:定义位置:类以内,方法以外 实例变量:1 有默认值 ...

  7. margin:0 auto;不居中?

    1.没有设置宽度 <div style="margin:0 auto;"></div> 看看上面的代码,根本没有设置DIV的宽度,如何根据宽度自适应呢?新手 ...

  8. 二cha树

    void porder(BTree *b) { BTree *St[MaxSize],*p; ; if(b!=NULL) { top++; St[top]=b; ) { p=St[top]; top- ...

  9. BZOJ 4086: [Sdoi2015]travel(SDOI2015 round2 day1)(分类讨论+容斥原理)

    描述:给定一张图(n<1000,m<5000)求有多少点对u,v有不重复经过其他点,共经过k个点的路径.(k<=7) 这个做法应该不是正解吧..顺便说下SDOI的几道题在BZ上都要卡 ...

  10. HTML5 DragEvent

    DragEvent是一个表示drag和drop交互的DOM event接口.用户通过将指针设备(如:鼠标)放在目标的表面开始拖动,然后拖动指针到一个新的位置(如其他DOM元素).应用程序自动的解析拖放 ...