转于自己在公司的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设计分享系列:
一些设计上的基本常识
谈谈泛化式扩展与组合式扩展
分享到:
相关推荐
3. **负载均衡**:Dubbo内置了多种负载均衡策略,如轮询、随机、权重优先等,可以自动分配请求到不同的服务实例,提高系统性能和可用性。 4. **容错机制**:Dubbo提供了多种容错策略,如失败快速失败、重试、降级等...
3. **负载均衡**:Dubbo内置了多种负载均衡策略,如随机、轮询、最少活跃调用数等,确保请求在多个服务实例间均匀分布,避免单一节点过载。 4. **容错机制**:Dubbo提供了多种容错策略,如失败快速返回、重试、FIFO...
在Java开发中,Dubbo是一个非常流行的分布式服务框架,它强调服务治理、高性能、轻量级,以及良好的可扩展性。本示例将深入探讨如何在Dubbo项目中使用注解进行服务的定义、消费和服务调用。注解的使用简化了配置,...
Dubbo是由阿里巴巴开源的一款高性能、轻量级的服务治理框架,主要用于Java环境,提供服务注册、服务发现、负载均衡、容错、监控等功能。它基于RPC(Remote Procedure Call)协议,使得不同语言的服务可以相互通信。 ...
本文将深入探讨Java高级工程师在互联网大厂面试中可能遇到的常见问题,包括项目挑战解决、数据结构、数据库索引、消息中间件、服务发现、微服务架构组件、限流策略以及负载均衡等关键知识点。 1. **项目挑战与解决...
重构技术包括静态转动态、早绑定转晚绑定、继承转组合、编译时依赖转运行时依赖、紧耦合转松耦合,这些技术有助于保持代码的可维护性和可扩展性。 在架构风格上,采用了微服务架构,将单一应用程序分解为一组小服务...
java版商城源码下载 SpringBoot+Docker重构宜立方商城 本项目源于宜立方商城项目,重新利用 SpringBoot 2.0.4 框架替代原始的SSM三大框架进行重构项目,采用 ...启动所有Dubbo服务; 服务 模块 guo.ping.e3mall.manage
Java数据压缩与传输实例 1个目标文件 摘要:Java源码,文件操作,数据压缩,文件传输 Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、...
同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...
这些技术的选择有助于实现服务的快速扩展,比如通过复制实例(Scale by cloning)、拆分不同组件(Scale by splitting different things)或相似组件(Scale by splitting similar things)等方式。 #### 架构演进...
3. **异常处理**:理解并熟练应用try-catch-finally语句,以及自定义异常,对异常处理有良好的设计思路。 4. **集合框架**:包括List、Set、Map接口及其具体实现类如ArrayList、LinkedList、HashSet、HashMap等,...
5. **权重分配**:在服务发现中,Nacos允许为服务实例分配权重,实现流量控制和负载均衡。 6. **元数据管理**:Nacos支持服务元数据的管理,包括服务的属性、标签等,方便进行服务分类和检索。 二、Nacos 2.0.0...
同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...
同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...
同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...
同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...
同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...
同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...
同时保持蒸提供全面的支持,无缝集成的IDE(语法着色,代码导航,重构等)的语法和操作代码完全分离。最大限度地减少时间和费用开发自定义的DSL(领域特定语言在Java)要求。 日志服务器 Apache Flume.tar Flume 是...