Java RPC框架中熔断降级机制是如何运作的?

2026-05-28 04:151阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计3202个文字,预计阅读时间需要13分钟。

Java RPC框架中熔断降级机制是如何运作的?

在RPC(远程过程调用)环境中,熔断和降级是常见的需求。以下是对这些概念简略的

熔断与降级需求的原因分析在RPC调用中,熔断和降级是保障系统稳定性的重要机制。具体原因如下:

- 熔断:当依赖的服务不稳定或响应时间过长时,为了防止整个系统雪崩,需要快速切断与该服务的连接,即熔断。- 降级:在资源紧张或服务不可用时,通过降级策略,减少对依赖服务的调用,以保证核心功能的正常运行。

熔断的理解我理解熔断主要解决以下问题:- 当依赖对象不稳定时,如何快速切断连接。- 如何确保系统在依赖问题出现时,不会影响核心功能的正常运行。

Java RPC框架中熔断降级机制是如何运作的?

示例图由于文字限制,无法直接展示图片,但以下为描述:- 图中展示了一个RPC调用流程,包括客户端、服务端和熔断器。- 当服务端响应时间过长时,熔断器会触发熔断,切断客户端与服务端的连接。

总结熔断和降级是RPC环境中重要的保障机制,通过快速切断不稳定连接和减少资源消耗,确保系统稳定运行。

熔断与降级

为什么在RPC环节中有熔断以及降级的需求,详细的原因这里不多解释,从网上搜索一张图做示意。

熔断

我理解熔段主要解决如下几个问题:

当所依赖的对象不稳定时,能够起到快速失败的目的快速失败后,能够根据一定的算法动态试探所依赖对象是否恢复

比如产品详细页获取产品的好评总数时,由于后端服务异常导致客户端每次都需要等到超时。如果短时间内服务不能恢复,那么这段时间内的所有请求时间都将是最大的超时时间,这类消费时间又得不到正确结果的现象是不能容忍的。所以遇到这类情况,就需要根据一定的算法判定服务短时间不可用,将后面的请求进行快速失败处理,这样可以节省服务等待时间。

同时,后端服务是有可能自主或者人为在一定时间内恢复的,所以之前被判定为快速失败的服务,需要有能力去试探服务是否已经恢复。

上面提到的快速失败以及自主恢复现象就是熔断

降级

降级是指自己的待遇下降了,从RPC调用环节来讲,就是去访问一个本地的伪装者而不是真实的服务,但这对调用端来说是没有区别的。拿电商展示某个产品的详细页来说:

当加载评论时,由于评论服务不可用,此时可以返回一些默认的评论当加载产品库存,由于库存服务不可用,此时可以固定显示一个库存数

上面提供返回默认评论,固定库存的服务就是伪装服务,这类服务一般不依赖其它服务,稳定性最高。由伪装者提供服务给客户端的现象就是服务降级。

RPC如何支持熔断与降级

一种最简单的办法就是借用hystrix来实现。

引入包依赖

由于示例未采用注解式方案,所以只需要引用下面两个包即可。

<dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-core</artifactId> <version>${hystrix-version}</version> </dependency> <dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-metrics-event-stream</artifactId> <version>${hystrix-version}</version> </dependency>

实现命令模式

hystrix遵循命令模式,这里可以往这个标准的UML图上去套。

创建一个新的类,RpcHystrixCommand,继承自HystrixCommand即可。

我这里采用线程隔离方式。

构造函数参数

由于需要远程调用,所以构造函数需要接收远程调用所需求必要参数

/** * 远程目标方法 */ private Method method; /** * 远程目标接口 */ private Object obj; /** * 远程方法所需要的参数 */ private Object[] params; /** * 远程接口客户端引用注解 */ private RpcReference rpcReference; /** * RPC客户端配置 */ private ReferenceConfig referenceConfig;

构造函数方法签名:

public RpcHystrixCommand(Object obj, Method method, Object[] params, RpcReference rpcReference, ReferenceConfig referenceConfig)

初始化hystrix

这里只是一个示例,所以参数设置比较随意,详细的可参考文档。

super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("CircuitBreakerRpcHystrixCommandGroup")) .andCommandKey(HystrixCommandKey.Factory.asKey("CircuitBreakerRpcHystrixCommandKey")) .andCommandPropertiesDefaults( HystrixCommandProperties.Setter() .withCircuitBreakerEnabled(true) .withCircuitBreakerRequestVolumeThreshold(1) .withCircuitBreakerErrorThresholdPercentage(50) .withCircuitBreakerSleepWindowInMilliseconds(5*1000) .withMetricsRollingStatisticalWindowInMilliseconds(10*1000) ) .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("CircuitBreakerRpcHystrixCommandPool")) .andThreadPoolPropertiesDefaults( HystrixThreadPoolProperties.Setter().withCoreSize(100) ) );

run()函数

run()函数就是正常调用时所需要执行的方法,将调用远程通信的逻辑迁移到此,由于此处不涉及今天讲的熔断降级,所以不用关心里面的代码。

@Override protected Object run() { // 执行远程调用 }

扩展rpcReference注解以支持降级

在之前的注解中增加一个属性,用来配置服务伪装者所属的类对象

public @interface RpcReference { /** * 服务降级的伪装者类对象 * @return */ Class<?> fallbackServiceClazz() default Object.class; }

getFallback()函数

当快速失败时,我们希望返回一些预先准备好的值给到客户端,实现这个需求就需要实现这个fallback函数。

伪装者的逻辑由于是客户端控制,所以我们通过参数来动态支持。 通过rpcReference注解可以获取配置的伪装者

protected Object getFallback() { Method[] methods = this.rpcReference.fallbackServiceClazz().getMethods(); for (Method methodFallback : methods) { if(this.method.getName().equals(methodFallback.getName())){ try { Object fallbackServiceMock= ApplicationContextUtils.getApplicationContext().getBean(this.rpcReference.fallbackServiceClazz()); return methodFallback.invoke(fallbackServiceMock,this.params); } catch (IllegalAccessException e) { logger.error("RpcHystrixCommand.getFallback error",e); } catch (InvocationTargetException e) { logger.error("RpcHystrixCommand.getFallback error",e); } } } throw new RpcException("service fallback unimplement"); }

RpcProxy嵌入熔断降级机制

代理的invoke方法,将改调用命令模式的execute方法来代替。

@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { RpcHystrixCommand rpcHystrixCommand=new RpcHystrixCommand(proxy,method,args,this.reference,this.referenceConfig); return rpcHystrixCommand.execute(); }

客户端使用

dubbo有一个mock机制,功能有些弱,有兴趣可以自行研究。我这里更加倾向于根据逻辑来判断是否使用熔断降级,降级的逻辑需要有更多的支持。

Spring Cloud的熔断降级的做法与我的类似,它是通过注解在接口上

@FeignClient(value = "JIM-CLOUD-PROVIDER-SERVER",fallback = ProductServiceHystrix.class) public interface ProductService { @RequestMapping(value = "/product/{productId}",method = RequestMethod.GET) String getById(@PathVariable("productId") final long productId); }

创建伪装者接口

定义伪装者接口,约定成员方法的签名与真身相同。

public interface ProductCommentMockService { Product getById(Long productId); }

实现伪装者接口

实现伪装者接口,这里不光是简单的固定数据,可心任意编写伪装者业务逻辑,与普通的service bean 没有区别。

@Service public class ProductCommentMockServiceImpl implements ProductCommentMockService { @Override public Product getById(Long productId) { Product mockProduct=new Product(); mockProduct.setId(0L); mockProduct.setName("mock product name"); return mockProduct; } }

服务引用使用熔断降级机制

在引用远程服务接口的注解上,配置伪装者接口的类即可。

@RpcReference( maxExecutesCount = 1, fallbackServiceClazz = ProductCommentMockService.class ) private ProductService productService;

测试

故意不启动服务端,请求接口,此时出现mock数据说明组件功能正常。

{"id":0,"name":"mock product name"}

待解决问题

由于熔断器采用的是新线程执行,所以会影响Rpc上下文传递的参数传递。

本文源码

github.com/jiangmin168168/jim-framework

文中代码是依赖上述项目的,如果有不明白的可下载源码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持易盾网络。

本文共计3202个文字,预计阅读时间需要13分钟。

Java RPC框架中熔断降级机制是如何运作的?

在RPC(远程过程调用)环境中,熔断和降级是常见的需求。以下是对这些概念简略的

熔断与降级需求的原因分析在RPC调用中,熔断和降级是保障系统稳定性的重要机制。具体原因如下:

- 熔断:当依赖的服务不稳定或响应时间过长时,为了防止整个系统雪崩,需要快速切断与该服务的连接,即熔断。- 降级:在资源紧张或服务不可用时,通过降级策略,减少对依赖服务的调用,以保证核心功能的正常运行。

熔断的理解我理解熔断主要解决以下问题:- 当依赖对象不稳定时,如何快速切断连接。- 如何确保系统在依赖问题出现时,不会影响核心功能的正常运行。

Java RPC框架中熔断降级机制是如何运作的?

示例图由于文字限制,无法直接展示图片,但以下为描述:- 图中展示了一个RPC调用流程,包括客户端、服务端和熔断器。- 当服务端响应时间过长时,熔断器会触发熔断,切断客户端与服务端的连接。

总结熔断和降级是RPC环境中重要的保障机制,通过快速切断不稳定连接和减少资源消耗,确保系统稳定运行。

熔断与降级

为什么在RPC环节中有熔断以及降级的需求,详细的原因这里不多解释,从网上搜索一张图做示意。

熔断

我理解熔段主要解决如下几个问题:

当所依赖的对象不稳定时,能够起到快速失败的目的快速失败后,能够根据一定的算法动态试探所依赖对象是否恢复

比如产品详细页获取产品的好评总数时,由于后端服务异常导致客户端每次都需要等到超时。如果短时间内服务不能恢复,那么这段时间内的所有请求时间都将是最大的超时时间,这类消费时间又得不到正确结果的现象是不能容忍的。所以遇到这类情况,就需要根据一定的算法判定服务短时间不可用,将后面的请求进行快速失败处理,这样可以节省服务等待时间。

同时,后端服务是有可能自主或者人为在一定时间内恢复的,所以之前被判定为快速失败的服务,需要有能力去试探服务是否已经恢复。

上面提到的快速失败以及自主恢复现象就是熔断

降级

降级是指自己的待遇下降了,从RPC调用环节来讲,就是去访问一个本地的伪装者而不是真实的服务,但这对调用端来说是没有区别的。拿电商展示某个产品的详细页来说:

当加载评论时,由于评论服务不可用,此时可以返回一些默认的评论当加载产品库存,由于库存服务不可用,此时可以固定显示一个库存数

上面提供返回默认评论,固定库存的服务就是伪装服务,这类服务一般不依赖其它服务,稳定性最高。由伪装者提供服务给客户端的现象就是服务降级。

RPC如何支持熔断与降级

一种最简单的办法就是借用hystrix来实现。

引入包依赖

由于示例未采用注解式方案,所以只需要引用下面两个包即可。

<dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-core</artifactId> <version>${hystrix-version}</version> </dependency> <dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-metrics-event-stream</artifactId> <version>${hystrix-version}</version> </dependency>

实现命令模式

hystrix遵循命令模式,这里可以往这个标准的UML图上去套。

创建一个新的类,RpcHystrixCommand,继承自HystrixCommand即可。

我这里采用线程隔离方式。

构造函数参数

由于需要远程调用,所以构造函数需要接收远程调用所需求必要参数

/** * 远程目标方法 */ private Method method; /** * 远程目标接口 */ private Object obj; /** * 远程方法所需要的参数 */ private Object[] params; /** * 远程接口客户端引用注解 */ private RpcReference rpcReference; /** * RPC客户端配置 */ private ReferenceConfig referenceConfig;

构造函数方法签名:

public RpcHystrixCommand(Object obj, Method method, Object[] params, RpcReference rpcReference, ReferenceConfig referenceConfig)

初始化hystrix

这里只是一个示例,所以参数设置比较随意,详细的可参考文档。

super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("CircuitBreakerRpcHystrixCommandGroup")) .andCommandKey(HystrixCommandKey.Factory.asKey("CircuitBreakerRpcHystrixCommandKey")) .andCommandPropertiesDefaults( HystrixCommandProperties.Setter() .withCircuitBreakerEnabled(true) .withCircuitBreakerRequestVolumeThreshold(1) .withCircuitBreakerErrorThresholdPercentage(50) .withCircuitBreakerSleepWindowInMilliseconds(5*1000) .withMetricsRollingStatisticalWindowInMilliseconds(10*1000) ) .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("CircuitBreakerRpcHystrixCommandPool")) .andThreadPoolPropertiesDefaults( HystrixThreadPoolProperties.Setter().withCoreSize(100) ) );

run()函数

run()函数就是正常调用时所需要执行的方法,将调用远程通信的逻辑迁移到此,由于此处不涉及今天讲的熔断降级,所以不用关心里面的代码。

@Override protected Object run() { // 执行远程调用 }

扩展rpcReference注解以支持降级

在之前的注解中增加一个属性,用来配置服务伪装者所属的类对象

public @interface RpcReference { /** * 服务降级的伪装者类对象 * @return */ Class<?> fallbackServiceClazz() default Object.class; }

getFallback()函数

当快速失败时,我们希望返回一些预先准备好的值给到客户端,实现这个需求就需要实现这个fallback函数。

伪装者的逻辑由于是客户端控制,所以我们通过参数来动态支持。 通过rpcReference注解可以获取配置的伪装者

protected Object getFallback() { Method[] methods = this.rpcReference.fallbackServiceClazz().getMethods(); for (Method methodFallback : methods) { if(this.method.getName().equals(methodFallback.getName())){ try { Object fallbackServiceMock= ApplicationContextUtils.getApplicationContext().getBean(this.rpcReference.fallbackServiceClazz()); return methodFallback.invoke(fallbackServiceMock,this.params); } catch (IllegalAccessException e) { logger.error("RpcHystrixCommand.getFallback error",e); } catch (InvocationTargetException e) { logger.error("RpcHystrixCommand.getFallback error",e); } } } throw new RpcException("service fallback unimplement"); }

RpcProxy嵌入熔断降级机制

代理的invoke方法,将改调用命令模式的execute方法来代替。

@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { RpcHystrixCommand rpcHystrixCommand=new RpcHystrixCommand(proxy,method,args,this.reference,this.referenceConfig); return rpcHystrixCommand.execute(); }

客户端使用

dubbo有一个mock机制,功能有些弱,有兴趣可以自行研究。我这里更加倾向于根据逻辑来判断是否使用熔断降级,降级的逻辑需要有更多的支持。

Spring Cloud的熔断降级的做法与我的类似,它是通过注解在接口上

@FeignClient(value = "JIM-CLOUD-PROVIDER-SERVER",fallback = ProductServiceHystrix.class) public interface ProductService { @RequestMapping(value = "/product/{productId}",method = RequestMethod.GET) String getById(@PathVariable("productId") final long productId); }

创建伪装者接口

定义伪装者接口,约定成员方法的签名与真身相同。

public interface ProductCommentMockService { Product getById(Long productId); }

实现伪装者接口

实现伪装者接口,这里不光是简单的固定数据,可心任意编写伪装者业务逻辑,与普通的service bean 没有区别。

@Service public class ProductCommentMockServiceImpl implements ProductCommentMockService { @Override public Product getById(Long productId) { Product mockProduct=new Product(); mockProduct.setId(0L); mockProduct.setName("mock product name"); return mockProduct; } }

服务引用使用熔断降级机制

在引用远程服务接口的注解上,配置伪装者接口的类即可。

@RpcReference( maxExecutesCount = 1, fallbackServiceClazz = ProductCommentMockService.class ) private ProductService productService;

测试

故意不启动服务端,请求接口,此时出现mock数据说明组件功能正常。

{"id":0,"name":"mock product name"}

待解决问题

由于熔断器采用的是新线程执行,所以会影响Rpc上下文传递的参数传递。

本文源码

github.com/jiangmin168168/jim-framework

文中代码是依赖上述项目的,如果有不明白的可下载源码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持易盾网络。