ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

HystrixRPC保护的原理:RPC保护的目标与HystrixCommand简介

2022-01-15 16:33:08  阅读:174  来源: 互联网

标签:HystrixRPC 调用 命令 RPC 线程 HystrixCommand Setter


RPC保护的目标

在分布式多节点集群架构系统内部,在节点之间进行RPC保护的目标如下:

(1)避免整个系统出现级联失败而雪崩,这是非常重要的目标。

在RPC调用过程中,需要防止由单个服务的故障而耗尽整个服务集群的线程资源,避免分布式环境里大量级联失败。

(2)RPC调用能够相互隔离。

为每一个目标服务维护着一个线程池(或信号量),即使其中某个目标服务的调用资源被耗尽,也不会影响对其他服务的RPC调用。当目标服务的线程池(或信号量)被耗尽时,拒绝RPC调用。

(3)能够快速地降级和恢复。

当RPC目标服务故障时,能够快速和优雅地降级;当RPC目标服务失效后又恢复正常时,快速恢复。

(4)能够对RPC调用提供接近实时的监控和警报。

监控信息包括请求成功、请求失败、请求超时和线程拒绝。如果对特定服务RPC调用的错误百分比超过阈值,后续的RPC调用就会自动失败,一段时间内停止对该服务的所有请求。

前面已经介绍Spring Cloud在调用处理器中是使用HystrixCommand命令封装RPC调用,从而实现RPC保护。

HystrixCommand简介

Hystrix使用命令模式并结合RxJava的响应式编程和滑动窗口技术实现了对外部服务RPC调用的保护。

Hystrix实现了HystrixCommand和HystrixObservableCommand两个命令类,用于封装需要保护的RPC调用。由于其中的HystrixObservableCommand命令不具备同步执行的能力,只具备异步执行能力,而HystrixCommand命令却都具备,并且Spring Cloud中重点使用HystrixCommand命令,因此本章将以HystrixCommand命令为重点介绍Hystrix的原理和使用。

HystrixCommand的使用

如果不是在Spring Cloud的开发环境中使用HystrixCommand命令,就需要增加其Maven的依赖坐标,设置如下:

<dependency>
 <groupId>com.netflix.hystrix</groupId>
 <artifactId>hystrix-core</artifactId>
 </dependency>

独立使用HystrixCommand命令主要有以下两个步骤:

(1)继承HystrixCommand类,将正常的业务逻辑实现在继承的run方法中,将回退的业务逻辑实现在继承的getFallback方法中。

(2)使用HystrixCommand类提供的启动方法启动命令的执行。

HystrixCommand命令的run方法是异步调用(或者同步调用)时被调度时执行的方法,getFallback方法是当run执行异常(或超时等)时的回退方法。

使用HystrixCommand命令时,需要通过它的启动方法(如execute)来启动其执行,这个过程有点像使用Thread时通过start方法启动run方法的执行。

HystrixCommand命令的完整执行过程比较复杂,简化版本的HystrixCommand命令的执行过程如图5-1所示。

HystrixRPC保护的原理:RPC保护的目标与HystrixCommand简介

图5-1 简化版本的HystrixCommand命令的执行过程

下面通过继承HystrixCommand创建一个简单的HTTP请求命令,并且对HTTP请求过程中执行的总次数、失败的总次数进行统计,具体的代码如下:

package com.crazymaker.demo.hystrix;
//省略import
@Slf4j
public class HttpGetterCommand extends HystrixCommand<String>
{
 private String url;
 //run方法是否执行
 private boolean hasRun = false;
 //执行的次序
 private int index;
 //执行的总次数,线程安全
 private static AtomicInteger total = new AtomicInteger(0);
 //失败的总次数,线程安全
 private static AtomicInteger failed = new AtomicInteger(0);
 public HttpGetterCommand(String url, Setter setter)
 {
 super(setter);
 this.url = url;
 }
 @Override
 protected String run() throws Exception
 {
 hasRun = true;
 index = total.incrementAndGet();
 log.info("req{} begin...", index);
 String responseData = HttpRequestUtil.simpleGet(url);
 log.info(" req{} end: {}", index, responseData);
 return "req" + index + ":" + responseData;
 }
 @Override
 protected String getFallback()
 {
 //是否直接失败
 boolean isFastFall = !hasRun;
 if (isFastFall)
 {
 index = total.incrementAndGet();
 }
 if (super.isCircuitBreakerOpen())
 {
 HystrixCommandMetrics.HealthCounts hc =
super.getMetrics().getHealthCounts();
 log.info("window totalRequests:{},errorPercentage:{}",
 hc.getTotalRequests(), //滑动窗口总的请求数
 hc.getErrorPercentage()); //滑动窗口出错比例
 }
 //熔断器是否打开
 boolean isCircuitBreakerOpen = isCircuitBreakerOpen();
 log.info("req{} fallback: 熔断{},直接失败 {},失败次数{}",
 index,
 isCircuitBreakerOpen,
 isFastFall,
 failed.incrementAndGet());
 return "req" + index + ":调用失败";
 }
}

以上自定义的HTTP请求命令HttpGetterCommand继承了HystrixCommand,并且实现了该基类的run和getFallback两个方法。在构造函数中,使用HystrixCommand.Setter配置实例对该基类的实例进行了初始化。

HttpGetterCommand的测试用例代码如下:

package com.crazymaker.demo.hystrix;
...
@Slf4j
public class HystryxCommandExcecuteDemo
{
 /***测试HttpGetterCommand */
 @Test
 public void testHttpGetterCommand() throws Exception
 {
 /**
 *构造配置实例
 */
 HystrixCommand.Setter setter = HystrixCommand.Setter
 .withGroupKey(HystrixCommandGroupKey.Factory.asKey("group-1"))
 .andCommandKey(HystrixCommandKey.Factory.asKey("command-1"))
 .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("threadPool-1"));
 /**测试HttpGetterCommand */
 String result =new HttpGetterCommand(HELLO_TEST_URL, setter)
.execute();
 log.info("result={}", result);
 }
}

用例中首先构造了一个配置实例setter,配置了非常基础的命令组Key(GroupKey)、命令Key(CommandKey)、线程池Key(ThreadPoolKey)3个配置项,然后创建了HttpGetterCommand实例并使用execute()执行该命令,执行的结果大致如下:

[hystrix-testThreadPool-1] INFO c.c.d.h.HttpGetterCommand - req1 begin...
[hystrix-testThreadPool-1] INFO c.c.d.h.HttpGetterCommand - req1 fallback: 熔断false,直接失败false,失败次数 1
[main] INFO c.c.d.h.HystryxCommandExcecuteDemo - result=req1:调用失败
这里的HttpGetterCommand实例所请求的地址是一个常量,其值如下:
 /**
 *演示用地址: demo-provider的REST接口 /api/demo/hello/v1
 *根据实际的地址调整
 */
 public static final String HELLO_TEST_URL =
 "http://crazydemo.com:7700/demo-provider/api/demo/hello/v1";

为了演示启动请求失败的过程,这里特意没有启动demo-provider服务,所以从上面的执行结果中可以看到,由于HTTP请求失败,因此getFallback()回退方法被成功地执行了。

HystrixCommand的配置内容和方式

HystrixCommand命令的配置方式之一是使用HystrixCommand.Setter配置实例进行配置,简单的配置实例如下:

 HystrixCommand.Setter setter = HystrixCommand.Setter
 .withGroupKey(HystrixCommandGroupKey.Factory.asKey("group-1"))
 .andCommandKey(HystrixCommandKey.Factory.asKey("command-1"))
 .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("threadPool-1"));

其中涉及以下3个配置项:

(1)CommandKey:该命令的名称。

(2)GroupKey:该命令属于哪一个组,以帮助我们更好地组织命令。

(3)ThreadPoolKey:该命令所属线程池的名称,相同的线程池名称会共享同一线程池,若不进行配置,则默认使用GroupKey作为线程池名称。

除此之外,还可以通过HystrixCommand.Setter配置实例,整体设置一些其他的属性集合,如:

(1)CommandProperties:与命令执行相关的一些属性集,包括降级设置、熔断器的配置、隔离策略以及一些监控指标配置项等。

(2)ThreadPoolProperties:与线程池相关的一些属性集,包括线程池大小、排队队列的大小等。由于本书的很多用例要用到HystrixCommand.Setter配置实例,因此专门写了一个方法获取配置实例,它的源码如下:

package com.crazymaker.demo.hystrix;
...
@Slf4j
public class SetterDemo
{
 public static HystrixCommand.Setter buildSetter(
 String groupKey,
 String commandKey,
 String threadPoolKey)
 {
 /**
 *与命令执行相关的一些属性集
 */
 HystrixCommandProperties.Setter commandSetter =
 HystrixCommandProperties.Setter()
 //至少有3个请求,熔断器才达到熔断触发的次数阈值
 .withCircuitBreakerRequestVolumeThreshold(3)
 //熔断器中断请求5秒后会进入half-open状态,尝试放行
 .withCircuitBreakerSleepWindowInMilliseconds(5000)
 //错误率超过60%,快速失败
 .withCircuitBreakerErrorThresholdPercentage(60)
 //启用超时
 .withExecutionTimeoutEnabled(true)
 //执行的超时时间,默认为1000ms
 .withExecutionTimeoutInMilliseconds(5000)
 //可统计的滑动窗口内的buckets数量,用于熔断器和指标发布
 .withMetricsRollingStatisticalWindowBuckets(10)
 //可统计的滑动窗口的时间长度
 //这段时间内的执行数据用于熔断器和指标发布
 .withMetricsRollingStatisticalWindowInMilliseconds(10000);
 /**
 *线程池配置
 */
 HystrixThreadPoolProperties.Setter poolSetter =
 HystrixThreadPoolProperties.Setter()
 //这里我们设置了线程池大小为5
 .withCoreSize(5)
 .withMaximumSize(5);
 /**
 *与线程池相关的一些属性集
 */
 HystrixCommandGroupKey hGroupKey = HystrixCommandGroupKey.Factory.
asKey(groupKey);
 HystrixCommandKey hCommondKey = HystrixCommandKey.Factory.
asKey(commandKey);
 HystrixThreadPoolKey hThreadPoolKey = HystrixThreadPoolKey.Factory.
asKey(threadPoolKey);
 HystrixCommand.Setter outerSetter = HystrixCommand.Setter
 .withGroupKey(hGroupKey)
 .andCommandKey(hCommondKey)
 .andThreadPoolKey(hThreadPoolKey)
 .andCommandPropertiesDefaults(commandSetter)
 .andThreadPoolPropertiesDefaults(poolSetter);
 return outerSetter;
 }
}

以上代码中涉及的配置项比较多,后面都会介绍。

HystrixCommand命令的配置方式之二是使用Hystrix提供的ConfigurationManager配置管理类的工厂实例对HystrixCommand命令的执行参数进行配置。下面是一个简单的实例:

 //熔断器的请求次数阈值:大于3次请求
 ConfigurationManager
 .getConfigInstance()
 .setProperty("hystrix.command.default.circuitBreaker.
requestVolumeThreshold", 3);

Spring Cloud Hystrix所使用的正是这种配置方法。

本文给大家讲解的内容是SpringCloudRPC远程调用核心原理: Hystrix RPC保护的原理 RPC保护的目标与HystrixCommand简介

  1. 下篇文章给大家讲解的是SpringCloudRPC远程调用核心原理:Hystrix RPC保护的原理,HystrixCommand命令的执行方法;
  2. 觉得文章不错的朋友可以转发此文关注小编;
  3. 感谢大家的支持!

 

标签:HystrixRPC,调用,命令,RPC,线程,HystrixCommand,Setter
来源: https://blog.csdn.net/m0_63437643/article/details/122511911

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有