springcloud 总集:https://www.tapme.top/blog/detail/2019-02-28-11-33

本次用到全部代码见文章最下方。

一、为什么要有客户端弹性模式

  所有的系统都会遇到故障,分布式系统单点故障概率更高。如何构建应用程序来应对故障,是每个软件开发人员工作的关键部分。但是通常在构建系统时,大多数工程师只考虑到基础设施或关键服务彻底发生故障,使用诸如集群关键服务器、服务间的负载均衡以及异地部署等技术。尽管这些方法考虑到组件系统的彻底故障,但他们之解决了构建弹性系统的一小部分问题。当服务崩溃时,很容易检测到该服务以及失效,因此应用程序可以饶过它。然而,当服务运行缓慢时,检测到这个服务性能越发低下并绕过它是非常困难的,因为以下几个原因:

  • 服务的降级可以是以间歇性的故障开始,并形成不可逆转的势头————可能开始只是一小部分服务调用变慢,直到突然间应用程序容器耗尽了线程(所有线程都在等待调用完成)并彻底崩溃。
  • 应用程序通常的设计是处理远程资源的彻底故障,而不是部分降级————通常,只要服务没有完全死掉,应用程序将继续调用这个服务,直到资源耗尽崩溃。

  性能较差的远程服务会导致很大的潜在问题,它们不仅难以检测,还会触发连锁反应,从而影响整个应用程序生态系统。如果没有适当的保护措施,一个性能不佳的服务可以迅速拖垮整个应用程序。基于云、基于微服务的应用程序特别容易受到这些类型的终端影响,因为这些应用由大量细粒度的分布式服务组成,这些服务在完成用户的事务时涉及不同的基础设施。

二、什么是客户端弹性模式

  客户端弹性模式是在远程服务发生错误或表现不佳时保护远程资源(另一个微服务调用或者数据库查询)免于崩溃。这些模式的目标是为了能让客户端“快速失败”,不消耗诸如数据库连接、线程池之类的资源,还可以避免远程服务的问题向客户端的消费者进行传播,引发“雪崩”效应。spring cloud 主要使用的有四种客户端弹性模式:

  • 客户端负载均衡(client load balance)模式

  上一篇已经说过,这里不再赘述。

  • 断路器(circuit breaker)模式

  本模式模仿的是电路中的断路器。有了软件断路器,当远程服务被调用时,断路器将监视这个调用,如果调用时间太长,断路器将介入并中断调用。此外,如果对某个远程资源的调用失败次数达到某个阈值,将会采取快速失败策略,阻止将来调用失败的远程资源。

  • 后备(fallback)模式

  当远程调用失败时,将执行替代代码路径,并尝试通过其他方式来处理操作,而不是产生一个异常。也就是为远程操作提供一个应急措施,而不是简单的抛出异常。

  • 舱壁(bulkhead)模式

  舱壁模式是建立在造船的基础概念上。我们都知道一艘船会被划分为多个水密舱(舱壁),因而即使少数几个部位被击穿漏水,整艘船并不会被淹没。将这个概念带入到远程调用中,如果所有调用都使用的是同一个线程池来处理,那么很有可能一个缓慢的远程调用会拖垮整个应用程序。在舱壁模式中可以隔离每个远程资源,并分配各自的线程池,使之互不影响。

  下图展示了这些模式是如何运用到微服务中的:

三、spring cloud 中使用

  使用 Netflix 的 Hystrix 库来实现上述弹性模式。继续使用上一节的项目,给 licensingservice 服务实现弹性模式。

1、代码修改

1、依赖引入

  首先修改 POM 文件,添加下面两个依赖:

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<!--本依赖不是必须的,spring-cloud-starter-hystrix已经带了,但是在Camden.SR5发行版本中使用了1.5.6,这个版本有一个不一致的地方,在没有后备的情况下会抛出java.lang.reflect.UndeclaredThrowableException而不是com.netflix.hystrix.exception.HystrixRuntimeException,
在后续版本中修复了这个问题-->
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-javanica</artifactId>
<version>1.5.9</version>
</dependency>

  然后在启动类上加入@EnableCircuitBreaker启用 Hystrix。

2、实现断路器

  首先修改 organizationservice 项目中的 OrganizationController,模拟延迟,每隔两次让线程 sleep 2 秒

@RestController
public class OrganizationController { private static int count=1; @GetMapping(value = "/organization/{orgId}")
public Object getOrganizationInfo(@PathVariable("orgId") String orgId) throws Exception{
if(count%2==0){
TimeUnit.SECONDS.sleep(2);
}
count++;
Map<String, String> data = new HashMap<>(2);
data.put("id", orgId);
data.put("name", orgId + "公司");
return data;
}
}

  只需在方法上添加@HystrixCommand,即可实现超时短路。如果 Spring 扫描到该注解注释的类,它将动态生成一个代理,来包装这个方法,并通过专门用于处理远程调用的线程池来管理对该方法的所有调用。

  修改 licensingservice 服务中的 OrganizationByRibbonService,OrganizationFeignClient,给其中的方法加上@HystrixCommand的注解。然后再访问接口localhost:10011/licensingByRibbon/11313,localhost:10011/licensingByFeign/11313。多次访问可发现抛出错误com.netflix.hystrix.exception.HystrixRuntimeException,断路器生效,默认情况下操时时间为 1s。

{
"timestamp": 1543823192424,
"status": 500,
"error": "Internal Server Error",
"exception": "com.netflix.hystrix.exception.HystrixRuntimeException",
"message": "OrganizationFeignClient#getOrganization(String) timed-out and no fallback available.",
"path": "/licensingByFeign/11313/"
}

  可通过设置注解参数来修改操时时间。设置超时时间大于 2s 后便不会报操时错误。(不知道为什么在 Feign 中设置失败,ribbon 中正常。)。一般都是将配置写在配置文件中。

@HystrixCommand(commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "20000")
})

3、后备处理

  由于远程资源的消费者和资源本身之间存在存在一个"中间人",因此开发人员能够拦截服务故障,并选择替代方案。在 Hystrix 中进行后备处理,非常容易实现。

  1. 在 ribbon 中的实现

  只需在@HystrixCommand注解中加入属性 fallbackMethod="methodName",那么在执行失败时,便会执行后备方法。注意防备方法必须和被保护方法在同一个类中,并且方法签名必须相同。修改 licensingservice 中 service 包下的 OrganizationByRibbonService 类,改为如下:

@Component
public class OrganizationByRibbonService { private RestTemplate restTemplate; @Autowired
public OrganizationByRibbonService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
} @HystrixCommand(commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000")
},fallbackMethod = "getOrganizationWithRibbonBackup")
public Organization getOrganizationWithRibbon(String id) throws Exception {
ResponseEntity<Organization> responseEntity = restTemplate.exchange("http://organizationservice/organization/{id}",
HttpMethod.GET, null, Organization.class, id);
return responseEntity.getBody();
} public Organization getOrganizationWithRibbonBackup(String id)throws Exception{
Organization organization = new Organization();
organization.setId("0");
organization.setName("组织服务调用失败");
return organization;
}
}

  启动应用,多次访问localhost:10011/licensingByRibbon/11313/,可以发现调用失败时,会启用后备方法。

  1. 在 feign 中实现

  在 feign 中实现后备模式,需要编写一个 feign 接口的实现类,然后在 feign 接口中指定该类。以 licensingservice 为例。首先在 client 包中添加一个 OrganizationFeignClientImpl 类,代码如下:

@Component
public class OrganizationFeignClientImpl implements OrganizationFeignClient{ @Override
public Organization getOrganization(String orgId) {
Organization organization=new Organization();
organization.setId("0");
organization.setName("后备模式返回的数据");
return organization;
}
}

然后修改 OrganizationFeignClient 接口的注解,将@FeignClient("organizationservice")改为@FeignClient(name="organizationservice",fallback = OrganizationFeignClientImpl.class。

  重启项目,多次访问localhost:10011/licensingByFeign/11313/,可发现后备服务起作用了。

  在确认是否要启用后备服务时,要注意以下两点:

  • 后备是一种在资源操时或失败时提供行动方案的机制。如果只是用后备来捕获操时异常然后只做日志记录,那只需要 try..catch 即可,捕获 HystrixRuntimeException 异常。

  • 注意后备方法所执行的操作。如果在后备服务中调用另一个分布式服务,需要注意用@HystrixCommand 方法注解包装后备方法。

4、实现舱壁模式

  在基于微服务的应用程序中,通常需要调用多个微服务来完成特定的任务,在不适用舱壁的模式下,这些调用默认是使用同一批线程来执行调用的,而这些线程是为了处理整个 Java 容器的请求而预留的。因此在存在大量请求的情况下,一个服务出现性能问题会导致 Java 容器内的所有线程被占用,同时阻塞新请求,最终容器彻底崩溃。

  Hystrix 使用线程池来委派所有对远程服务的调用,默认情况下这个线程池有 10 个工作线程。但是这样很容易出现一个运行缓慢的服务占用全部的线程,所有 hystrix 提供了一种一种易于使用的机制,在不同的远程资源调用间创建‘舱壁’,将不同服务的调用隔离到不同的线程池中,使之互不影响。

  要实现隔离的线程池,只需要在@HystrixCommand上加入线程池的注解,这里以 ribbon 为例(Feign 类似)。修改 licensingservice 中 service 包下的 OrganizaitonByRibbonService 类,将getOrganizationWithRibbon方法的注解改为如下:

@HystrixCommand(commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000")
}, fallbackMethod = "getOrganizationWithRibbonBackup",
threadPoolKey = "licenseByOrgThreadPool",
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "30"),
@HystrixProperty(name = "maxQueueSize", value = "10")
})

如果将maxQueueSize属性值设为-1,将使用SynchronousQueue保存所有的传入请求,同步队列会强制要求正在处理中的请求数量永远不能超过线程池的大小。设为大于 1 的值将使用LinkedBlockingQueue。

  注意:示例代码中都是硬编码属性值到 Hystrix 注解中的。在实际应用环境中,一般都是将配置项配置在 Spring Cloud Config 中的,方便统一管理。

本次用到全部代码:点击跳转

本篇原创发布于:FleyX 的个人博客

springCloud学习3(Netflix Hystrix弹性客户端)的更多相关文章

  1. SpringCloud学习笔记(3)——Hystrix

    参考Spring Cloud官方文档第13.14.15章 13. Circuit Breaker: Hystrix Clients Netflix提供了一个叫Hystrix的类库,它实现了断路器模式. ...

  2. springCloud学习-断路器(Hystrix)

    1.问题分析 在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用(RPC),在Spring Cloud可以用RestTemplate+Ribbon和Feign来调用.为了保证其高 ...

  3. springCloud学习总览

      写完最后一篇特意去看了看第一篇是什么时候写的---2018/11/19,到现在三个月多一点,总的来说这三个月通过<Spring 微服务实战>这本书,算是对微服务进行了一次扫盲学习.   ...

  4. springcloud学习04- 断路器Spring Cloud Netflix Hystrix

    依赖上个博客:https://www.cnblogs.com/wang-liang-blogs/p/12072423.html 1.断路器存在的原因 引用博客 https://blog.csdn.ne ...

  5. SpringCloud学习笔记(14)----Spring Cloud Netflix之Hystrix对Feign的支持

    1. Hystrix对Feign的支持 添加Feign中IUserBiz的实现类HystrixFallBack: package com.wangx.cloud.springcloud02consum ...

  6. SpringCloud学习笔记(12)----Spring Cloud Netflix之Hystrix断路器的流程和原理

    工作流程(参考:https://github.com/Netflix/Hystrix/wiki/How-it-Works) 1. 创建一个HystrixCommand或HystrixObservabl ...

  7. SpringCloud学习笔记(4):Hystrix容错机制

    简介 在微服务架构中,微服务之间的依赖关系错综复杂,难免的某些服务会出现故障,导致服务调用方出现远程调度的线程阻塞.在高负载的场景下,如果不做任何处理,可能会引起级联故障,导致服务调用方的资源耗尽甚至 ...

  8. SpringCloud学习系列之三----- 断路器(Hystrix)和断路器监控(Dashboard)

    前言 本篇主要介绍的是SpringCloud中的断路器(Hystrix)和断路器指标看板(Dashboard)的相关使用知识. SpringCloud Hystrix Hystrix 介绍 Netfl ...

  9. SpringCloud学习笔记(七):Hystrix断路器

    概述 什么时候需要断路器?熔断? 举个简单的例子:小明喜欢小美,可是小美没有电话,小美给了小明家里的座机,小明打给座机,这个时候小美的妈妈接到了,小明怕妈妈知道自己喜欢小美,就跟小美妈妈说让小美哥接电 ...

随机推荐

  1. easyui datagrid的editor编辑器如何为validatebox控件添加改变事件

    项目中需要为行编辑器Editor的某个列的文本框添加改变事件 需求:新增行时,为用户名输入特殊字符进行验证,不允许保存用户数据 html页面 <table id="gridlist&q ...

  2. k8s记录-node组件部署(十)

    1)CA 证书配置登录 192.168.0.1 app 用户下cd ssl/kubernetes#注意修改 KUBE_HOME,BOOTSTRAP_TOKEN #与 3.5 3)token 一致,KU ...

  3. python 使用sqlalchemy进行数据库操作

    sqlalchemy是python下一个著名的数据库orm库,可以方便地进行数据表创建.数据增删改查等操作 最详细的教程,见官方:https://docs.sqlalchemy.org 这里列举一些常 ...

  4. awk(gawk)文本报告生成器

    awk是gawk的链接文件,是一种优良的文本处理工具,实现格式化文本输出,是Linux和Unix现有环境中功能最强大的数据处理引擎之一.这种编程及数据操作语言的最大功能取决于一个人拥有的知识量,使用& ...

  5. 将pip源设置国内源

    windows (1)打开文件资源管理器(文件夹地址栏中) (2)地址栏上面输入 %appdata% (3)在这里面新建一个文件夹 pip (4)在pip文件夹里面新建一个文件叫做 pip.ini , ...

  6. maven:不再支持源选项 5。请使用 6 或更高版本。

    解决办法: 在pom.xml中添加maven的配置 <maven.compiler.source>11</maven.compiler.source> <maven.co ...

  7. 去掉WARN spring.jpa.open-in-view is enabled by default

    使用springboot jpa,在运行项目时发现一个WARN WARN 11472 --- [ main] aWebConfiguration$JpaWebMvcConfiguration : sp ...

  8. oracle python操作 增删改查

    oracle删除 删除表内容 truncate table new_userinfo; 删除表 drop table new_userinfo; 1.首先,python链接oracle数据库需要配置好 ...

  9. 009 SpringCloud 学习笔记5-----Hystrix保护机制

    1.概述 Hystrix,英文意思是豪猪,全身是刺,看起来就不好惹,是一种保护机制.Hystrix也是Netflix公司的一款组件.主页:https://github.com/Netflix/Hyst ...

  10. codeforces --- Round #250 (Div. 2) B. The Child and Set

    <传送门> [题目大意] 给你一个sum和一个limit,现在要你在1~limit中找到一些数来使得这些数的和等于sum,如果能找到的话就输出找到的数的个数和这些数,未找到输出" ...