IT知识库 购物 网址 游戏 小说 歌词 快照 开发 股票 美女 新闻 笑话 | 汉字 软件 日历 阅读 下载 图书馆 编程 China
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题 autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程 CSS/HTML/Xhtml html5 CSS XML/XSLT Dreamweaver教程 经验交流 开发者乐园 Android开发资料
站长资讯 .NET新手 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA VisualStudio ASP.NET-MVC .NET控件开发 EntityFramework WinRT-Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动 Html-Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP OracleERP DynamicsCRM K2 BPM 信息安全 企业信息 Android开发 iOS开发 WindowsPhone WindowsMobile 其他手机 敏捷开发 项目管理 软件工程 SQLServer Oracle MySQL NoSQL 其它数据库 Windows7 WindowsServer Linux
  IT知识库 -> 架构设计 -> 简易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上下文传递的参数传递,后续我再解决。
本文源码
https://github.com/jiangmin168168/jim-framework
文中代码是依赖上述项目的,如果有不明白的可下载源码
上一篇文章      下一篇文章      查看所有文章
加:2017-12-02 23:25:35  更:2017-12-02 23:25:37 
 
  架构设计 最新文章
spring boot实现ssm(2)功能
java 企业站源码 兼容手机平板PC 自适应响应
Serverless无服务应用架构纵横谈
理论篇:关注点分离(Separation of concern
Struts 2 入门
spring boot实现ssm(1)功能
整理下.net分布式系统架构的思路
.net之工作流工程展示及代码分享(一)工作
GPS部标监控平台的架构设计(十一)
一步一步搭建开发框架(二)工厂模式
技术频道: 站长资讯 .NET新手区 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA Visual Studio ASP.NET MVC .NET控件开发 Entity Framework WinRT/Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动设计 Html/Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP Oracle ERP Dynamics CRM K2 BPM 信息安全 企业信息化其他 Android开发 iOS开发 Windows Phone Windows Mobile 其他手机开发 敏捷开发 项目与团队管理 软件工程其他 SQL Server Oracle MySQL NoSQL 其它数据库 Windows 7 Windows Server Linux
脚本语言: vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题 autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程
网站开发: CSS/HTML/Xhtml html5 CSS XML/XSLT Dreamweaver教程 经验交流 开发者乐园 Android开发资料
360图书馆 软件开发资料 文字转语音 购物精选 软件下载 新闻资讯 小游戏 Chinese Culture 股票 三丰软件 开发 中国文化 网文精选 阅读网 看图 日历 万年历 2018年10日历
2018-10-22 13:28:16
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT知识库