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 partially implement our operations model, enabling separately deployed microservices to communicate with each other. In this blog post we will focus on fault handling in a microservice landscape, improving resilience using Hystrix, Netflix circuit breaker.
Now bad things will start to happen in the system landscape that we established in Part 1. Some of the core services that the composite service depends on will suddenly not respond, jeopardizing the composite service if faults are not handled correctly.
In general we call this type of problem a chain of failures, where an error in one component can cause errors to occur in other components that depend on the failing component. This needs special attention in a microservice based system landscape where, potentially a large number of, separately deployed microservices communicate with each other. One common solution to this problem is to apply a circuit breaker pattern, for details see the book Release It! or read the blog post Fowler - Circuit Breaker. A circuit breaker typically applies state transitions like:
(Source: Release It!)
Enter Netflix Hystrix and some powerful annotations provided by Spring Cloud!
- SPRING CLOUD AND NETFLIX OSS
From the table presented in Part 1 we will cover: Hystrix, Hystrix dashboard and Turbine.
Netflix Hystrix - Circuit breaker Netflix Hystrix provides circuit breaker capabilities to a service consumer. If a service doesn’t respond (e.g. due to a timeout or a communication error), Hystrix can redirect the call to an internal fallback method in the service consumer. If a service repeatedly fails to respond, Hystrix will open the circuit and fast fail (i.e. call the internal fallback method without trying to call the service) on every subsequent call until the service is available again. To determine wether the service is available again Hystrix allow some requests to try out the service even if the circuit is open. Hystrix executes embedded within its service consumer.
Netflix Hystrix dashboard and Netflix Turbine - Monitor Dashboard Hystrix dashboard can be used to provide a graphical overview of circuit breakers and Turbine can, based on information in Eureka, provide the dashboard with information from all circuit breakers in a system landscape. A sample screenshot from Hystrix dashboard and Turbine in action:
Hystrix
- THE SYSTEM LANDSCAPE
The system landscape from Part 1 is complemented with supporting infrastructure servers for Hystrix dashboard and Turbine. The service product-composite is also enhanced with a Hystrix based circuit breaker. The two new components are marked with a red line in the updated picture below:
system-landscape
As in Part 1, we emphasize the differences between microservices and monolithic applications by running each service in a separate microservice, i.e. in separate processes.
- BUILD FROM SOURCE
As in Part 1 we use Java SE 8, Git and Gradle. So, to access the source code and build it perform:
$ git clone https://github.com/callistaenterprise/blog-microservices.git
$ cd blog-microservices
$ git checkout -b B2 M2.1
$ ./build-all.sh
If you are on Windows you can execute the corresponding bat-file build-all.bat!
Two new source code components have been added since Part 1: monitor-dashboard and turbine:
source-code
The build should result in eight log messages that all says:
BUILD SUCCESSFUL
4. SOURCE CODE WALKTHROUGH
New from Part 1 is the use of Hystrix as a circuit breaker in the microservice product-composite, so we will focus on the additional source code required to put the circuit breaker in place.
4.1 GRADLE DEPENDENCIES
We now have a couple of Hystrix-based starter dependencies to drag into our build files. Since Hysteric use RabbitMQ to communicate between circuit breakers and dashboards we also need to setup dependencies for that as well.
For a service consumer, that want to use Hystrix as a circuit breaker, we need to add:
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")
For a complete example see product-composite-service/build.gradle.
To be able to setup an Turbine server add the following dependency:
compile('org.springframework.cloud:spring-cloud-starter-turbine-amqp:1.0.0.RELEASE')
For a complete example see turbine/build.gradle.
4.2. INFRASTRUCTURE SERVERS
Set up a Turbine server by adding the annotation @EnableTurbineAmqp to a standard Spring Boot application:
@SpringBootApplication
@EnableTurbineAmqp
@EnableDiscoveryClient
public class TurbineApplication {
public static void main(String[] args) {
SpringApplication.run(TurbineApplication.class, args);
}
}
For a complete example see TurbineApplication.java.
To setup a Hystrix Dashboard add the annotation @EnableHystrixDashboard instead. For a complete example see HystrixDashboardApplication.java.
With these simple annotation you get a default server configuration that makes you get started. When needed, the default configurations can be overridden with specific settings.
4.3 BUSINESS SERVICES
To enable Hystrix, add a @EnableCircuitBreaker-annotation to your Spring Boot application. To actually put Hystrix in action, annotate the method that Hystrix shall monitor with
@HystrixCommand where we also can specify a fallback-method, e.g.:
@HystrixCommand(fallbackMethod = "defaultReviews")
public ResponseEntity<List<Review>> getReviews(int productId) {
...
}
public ResponseEntity<List<Review>> defaultReviews(int productId) {
...
}
The fallback method is used by Hystrix in case of an error (call to the service fails or a timeout occurs) or to fast fail if the circuit is open. For a complete example see ProductCompositeIntegration.java.
- START UP THE SYSTEM LANDSCAPE
As in Part 1, we will start the microservices as java processes in our local development environment and you need to have the cURL and jq tools installed to be able to run some of the commands below.
As already mentioned, Hystrix use RabbitMQ for internal communication so we need to have it installed and running before we can start up our system landscape. Follow the instructions at Downloading and Installing. Then start RabbitMQ use the rabbitmq-server program in the sbin-folder of your installation.
$ ~/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.
If you are on Windows use Windows Services to ensure that the RabbitMQ service is started!
We are now ready to start up the system landscape. Each microservice is started using the command ./gradlew bootRun.
First start the infrastructure microservices, e.g.:
$ cd support/discovery-server; ./gradlew bootRun
$ cd support/edge-server; ./gradlew bootRun
$ cd support/monitor-dashboard; ./gradlew bootRun
$ cd support/turbine; ./gradlew bootRun
Once they are started up, launch the business microservices:
$ 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
If you are on Windows you can execute the corresponding bat-file start-all.bat!
Once the microservices are started up and registered with the service discovery server they should write the following in the log:
DiscoveryClient ... - registration status: 204
As in Part 1, we should be able to see our four business services and the edge-server in the service discovery web app (http://localhost:8761):
Eureka
Finally ensure that the circuit breakers are operational, e.g. closed. Try a call to the composite service through the edge-server as in Part 1 (shortened for brevity:
$ 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
}
Go to the url http://localhost:7979 in a web browser, enter the url http://localhost:8989/turbine.stream and click on the “Monitor Stream” – button):
Hystrix
We can see that the composite service have three circuit breakers operational, one for each core service it depends on. They are all fine, i.e. closed. We are now ready to try out a negative test to see the circuit breaker in action!
- SOMETHING GOES WRONG
Stop the review microservice and retry the command above:
$ curl -s localhost:8765/productcomposite/product/1 | jq .
{
"name": "name",
"productId": 1,
"recommendations": [
{
"author": "Author 1",
"rate": 1,
"recommendationId": 0
},
...
],
"reviews": null,
"weight": 123
}
The review - part of the response is now empty, but the rest of the reply remains intact! Look at the log of the product-composite services and you will find warnings:
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
I.e. the circuit breaker has detected a problem with the review service and routed the caller to the fallback method in the service consumer. In this case we simply return null but we could, for example, return data from a local cache to provide a best effort result when the review service is unavailable.
The circuit is still closed since the error is not that frequent:
Hystrix
Let’s increase the error frequency over the limits where Hystrix will open the circuit and start to fast fail (we use Hystrix default values to keep the blog post short…). We use the Apache HTTP server benchmarking tool for this:
ab -n 30 -c 5 localhost:8765/productcomposite/product/1
Now the circuit will be opened:
Hystrix
…and subsequent calls will fast fail, i.e. the circuit breaker will redirect the caller directly to its fallback method without trying to get the reviews from the review service. The log will no longer contain a message that says 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
However, from time to time it will let some calls pass through to see if they succeeds, i.e. to see if the review service is available again. We can see that by repeating the curl call a number of times and look in the log of the product-composite service:
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
As we can see from the log output, every fifth call is allowed to try to call the review service (still without success…).
Let’s start the review service again and try calling the composite service!
Note: You might need to be a bit patient here (max 1 min), both the service discovery server (Eureka) and the dynamic router (Ribbon) must be made aware of that a review service instance is available again before the call succeeds.
Now we can see that the response is ok, i.e. the review part is back in the response, and the circuit is closed again:
Hystrix
- SUMMARY
We have seen how Netflix Hystrix can be used as a circuit breaker to efficiently handle the problem with chain of failures, i.e. where a failing microservice potentially can cause a system outage of a large part of a microservice landscape due to propagating errors. Thanks to the annotations and starter dependencies available in Spring Cloud it is very easy to get started with Hystrix in a Spring environment. Finally the dashboard capabilities provided by Hystrix dashboard and Turbine makes it possible to monitor a large number of circuit breakers in a system landscape.
- NEXT STEP
In the next blog post in the Blog Series - Building Microservices we will look at how to use OAuth 2.0 to restrict access to microservices that expose an external API.
Stay tuned!
Building microservices with Spring Cloud and Netflix OSS, part 2的更多相关文章
- 基于Spring Cloud和Netflix OSS 构建微服务-Part 1
前一篇文章<微服务操作模型>中,我们定义了微服务使用的操作模型.这篇文章中,我们将开始使用Spring Cloud和Netflix OSS实现这一模型,包含核心部分:服务发现(Servic ...
- 基于Spring Cloud和Netflix OSS构建微服务,Part 2
在上一篇文章中,我们已使用Spring Cloud和Netflix OSS中的核心组件,如Eureka.Ribbon和Zuul,部分实现了操作模型(operations model),允许单独部署的微 ...
- Microservices Reference Architecture - with Spring Boot, Spring Cloud and Netflix OSS--转
原文地址:https://www.linkedin.com/pulse/microservices-reference-architecture-spring-boot-cloud-anil-alle ...
- Building Microservices with Spring Boot and Apache Thrift. Part 1 with servlet
https://dzone.com/articles/building-microservices-spring In the modern world of microservices it's i ...
- Building Microservices with Spring Boot and Apache Thrift. Part 2. Swifty services
http://bsideup.blogspot.com/2015/04/spring-boot-thrift-part2.html In previous article I showed y ...
- Netflix OSS、Spring Cloud还是Kubernetes? 都要吧!
Netflix OSS是由Netflix公司主持开发的一套代码框架和库,目的是解决上了规模之后的分布式系统可能出现的一些有趣问题.对于当今时代的Java开发者们来说,Netflix OSS简直就是在云 ...
- Spring Cloud介绍 Spring Cloud与Dubbo对比
spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理.服务发现.断路器.智能路由.微代理.控制总线.全局锁.决策竞选.分布式会话和集群状 ...
- 构建微服务(Building Microservices)-PDF 文档
闲时翻译了几篇基于Spring Cloud.Netflix OSS 构建微服务的英文文章,为方便分享交流,整理为PDF文档. PDF 文档目录: 目录 一.微服务操作模型... 3 1. 前提 ...
- Spring cloud子项目
目前来说spring主要集中于spring boot(用于开发微服务)和spring cloud相关框架的开发,我们从几张图着手理解,然后再具体介绍: spring cloud子项目包括: Sprin ...
随机推荐
- 关于File.getPath,File.getAbsolutePath,File.getCanonicalPath的区别
这个问题, 不了解一下还是挺恍惚它们之间的区别的. 其实也挺简单的. getPath()-->>new File()时的路径 getAbsolutePath()-->>当前路径 ...
- debian清除无用的库文件(清理系统,洁癖专用)
deborphan 可以用来找出在系统中已经没有被依赖的套件.一般的情况是 library 会在其他套件需要的时候被牵引进来,但是当这些套件升级或删除后,被牵引进来的 library package ...
- asp.net session容易丢失解决方案
web Form 网页是基于HTTP的,它们没有状态, 这意味着它们不知道所有的请求是否来自 同一台客户端计算机,网页是受到了破坏,以及是否得到了刷新,这样就可能造成信息的 丢失. 于是, 状态管理就 ...
- VC操作Excel之基本操作
// 变量的定义 _Application app; Workbooks books; _Workbook book; Worksheets sheets; _Worksheet sheet; Ran ...
- [设计模式]<<设计模式之禅>>模板方法模式
1 辉煌工程——制造悍马 周三,9:00,我刚刚坐到位置上,打开电脑准备开始干活. “小三,小三,叫一下其他同事,到会议室开会”,老大跑过来吼,带着坏笑.还没等大家坐稳,老大就开讲了:“告诉大家一个好 ...
- Java Classloader原理分析
类的加载过程指通过一个类的全限定名来获取描述此类的二进制字节流,并将其转化为方法区的数据结构,进而生成一个java.lang.Class对象作为方法区这个类各种数据访问的入口.这个过程通过Jav ...
- 嵌入式开发笔记 - U-Boot相关
1.U-boot使用准备 1.1 U-boot下载 通过德国的denx软件中心提供的FTP下载合集,下载网址: ftp://ftp.denx.de/pub/u-boot/
- StringBuilder 类
表示可变字符字符串.无法继承此类. 此类表示值为可变字符序列的类似字符串的对象.之所以说值是可变的,是因为在通过追加.移除.替换或插入字符而创建它后可以对它进行修改.有关比较,请参见 String 类 ...
- HttpClient(4.3.5) - HTTP Authentication
HttpClient provides full support for authentication schemes defined by the HTTP standard specificati ...
- 【转载】Apache kafka原理与特性(0.8V)
http://blog.csdn.net/xiaolang85/article/details/37821209 前言: kafka是一个轻量级的/分布式的/具备replication能力的日志采集组 ...