`
chozee
  • 浏览: 2937 次
社区版块
存档分类
最新评论

【转】接口重构一些思路-dubbo负载均衡扩展接口重构实例

阅读更多
转于自己在公司的Blog:
http://pt.alibaba-inc.com/wp/experience_1003/loadbalance_refactor.html

项目中的一个重构的过程及理由,用于知会团队成员,在这里备一个。

RPC远程调用框架中有很多可选的负载均衡策略,
比如:随机,轮循,最少连接等等,
这个时候就需要一个SPI扩展点,为后续增加新的策略提供可能,

重构前:
原接口形式,如下:




1.public class LoadBalance<T> {  
2.  
3.    // 给定资源和权重,返回选中资源的下标号  
4.    int select(T[] resources, int[] weights);  
5.  
6.} 




问题一:
返回下标号,使接口输入输出不一致,并且限制了资源的包装,如:



Java代码 复制代码 收藏代码
1.public class LoadBalance {  
2.  
3.    // 给定资源和权重,返回选中资源  
4.    <T> T select(T[] resources, int[] weights);  
5.  
6.}  




问题二:
作为扩展接口,即然使用泛型,表示策略实现不限制资源类型,接口本身定义泛型没有意义,泛型声明应该定义在方法上,如:



Java代码 复制代码 收藏代码
1.public class LoadBalance {  
2.  
3.    // 给定资源和权重,返回选中资源  
4.    <T> T select(T[] resources, int[] weights);  
5.  
6.}  




问题三:
作为扩展接口,权重信息的传递过于特殊化,
比如现在最小连接数策略要用到当前活跃连接数,
需增加新的参数actives,如:



Java代码 复制代码 收藏代码
1.public class LoadBalance {  
2.  
3.    // 给定资源和权重,返回选中资源  
4.    <T> T select(T[] resources, int[] weights, int[] actives);  
5.  
6.}  




问题四:
但像上面这样,你并不清楚后续还有什么参数要加入,接口的契约不容扩展,
另一种办法是,在最小连接数策略实现中将T强制转型成RpcInvoker接口,然后调用getActive(),
但即然active数通过get方获取,为什么weight却通过另一个参数传入,明显的不一致,
而且这里的强制转型,也会导致策略的实现并不能像原来期望的通用,
作为一个框架的扩展点,通用意义并不大,越通用越难用,上面的泛型T有过度设计之嫌,
直接用RpcInvoker作为参数,更能保证契约的完备性,如:



Java代码 复制代码 收藏代码
1.public class LoadBalance {  
2.  
3.    // RpcInvoker接口中有getWeight(), getActive()等获取参数方法  
4.    // 给定资源和权重,返回选中资源  
5.    RpcInvoker select(RpcInvoker[] resources);  
6.  
7.}  



如果有通用性需求,也可以考虑再抽取一个接口,如:



Java代码 复制代码 收藏代码
1.public class LoadBalance {  
2.  
3.    // 给定资源和权重,返回选中资源  
4.    Selectable select(Selectable[] resources);  
5.  
6.}  



问题五:
有一种需求是基于客户端一致性的,要求执行所有RpcInvoker,而不是选其中一个RpcInvoker执行,
原有实现,是将其作为特例,写死在代码中的,基于上面的LoadBalance接口,
完全可以将传入的所有RpcInvoker[]包装成一个总的RpcInvoker,里面用for循环委派所有调用。
如果有w + r > n(写节点 + 读节点 > 总节点)的一致性需求,也可以用相应方法处理,只是增加一些配置项,如:


Java代码 复制代码 收藏代码
1.public class AllLoadBalance {  
2.  
3.    public RpcInvoker select(RpcInvoker[] resources) {  
4.        return new AllRpcInvoker(resources);  
5.    }  
6.  
7.}  
8.class AllRpcInvoker implements RpcInvoker {  
9.  
10.    private RpcInvoker[] invokers;  
11.      
12.    public AllRpcInvoker(RpcInvoker[] invokers) {  
13.        this.invokers = invokers;  
14.    }  
15.      
16.    // Delegate all methods to invokers  
17.      
18.}  




问题六:
有的策略实现是带状态的,比如轮循策略需记录轮循序号,
也就是并不能单实例使用LoadBalance实例,
这对框架的维护非常不利,容易给后来的维护者埋下地雷,
而且,同一个resources集合,必需用同一个LoadBalance实例,
也就是LoadBalance实例的变更是跟随resources集合的变更,
即然如此,资源集合的设定,可以在select()之前确定,如:



1.public class LoadBalance {  
2.  
3.    // 初始化资源集合  
4.    void init(RpcInvoker[] resources);  
5.  
6.    // 返回选中资源  
7.    RpcInvoker select();  
8.  
9.}  



这样的好处是,LoadBalance的实现可以在init()时做预处理及缓存,
比如随机策略,需要统计总权重,如果在init()方法中统计,
select()时可以减少一次for循环,
而且,可以通过重复调用init()方法,复用单一LoadBalance实例,
当然,LoadBalance的实现需确保线程安全性。

------------------------
Dubbo设计分享系列:
一些设计上的基本常识
谈谈泛化式扩展与组合式扩展
分享到:
评论

相关推荐

    JAVA上百实例源码以及开源项目源代码

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    java版商城源码下载-e3-springboot:SpringBoot+Docker重构宜立方商城

    java版商城源码下载 SpringBoot+Docker重构宜立方商城 本项目源于宜立方商城项目,重新利用 SpringBoot 2.0.4 框架替代原始的SSM三大框架进行重构项目,采用 ...启动所有Dubbo服务; 服务 模块 guo.ping.e3mall.manage

    JAVA上百实例源码以及开源项目

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    java开源包1

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    抽奖系统设计方案.pdf

     4.2 重构关键技法 重构关键技法 静态 -&gt; 动态 早绑定 -&gt; 晚绑定 继承 -&gt; 组合 编译时依赖 -&gt; 运⾏时依赖 紧耦合 -&gt; 松耦合 4.3 本项⽬中运⽤的设计模式 本项⽬中运⽤的设计模式 对象创建过程中使⽤new,new依赖...

    java开源包10

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包2

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包3

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包6

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包5

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包8

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包7

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包9

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包11

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包4

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    java开源包101

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

    Java资源包01

    同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...

Global site tag (gtag.js) - Google Analytics