详解Spring Cloud负载均衡重要组件Ribbon中重要类的用法
作者:hsm_computer 发布时间:2023-07-06 02:54:01
Ribbon是Spring Cloud Netflix全家桶中负责负载均衡的组件,它是一组类库的集合。通过Ribbon,程序员能在不涉及到具体实现细节的基础上“透明”地用到负载均衡,而不必在项目里过多地编写实现负载均衡的代码。
比如,在某个包含Eureka和Ribbon的集群中,某个服务(可以理解成一个jar包)被部署在多台服务器上,当多个服务使用者同时调用该服务时,这些并发的请求能被用一种合理的策略转发到各台服务器上。
事实上,在使用Spring Cloud的其它各种组件时,我们都能看到Ribbon的痕迹,比如Eureka能和Ribbon整合,而在后文里将提到的提供网关功能Zuul组件在转发请求时,也可以整合Ribbon从而达到负载均衡的效果。
从代码层面来看,Ribbon有如下三个比较重要的接口。
第一,ILoadBalancer,这也叫负载均衡器,通过它,我们能在项目里根据特定的规则合理地转发请求,常见的实现类有BaseLoadBalancer。
第二,IRule,这个接口有多个实现类,比如RandomRule和RoundRobinRule,这些实现类具体地定义了诸如“随机“和”轮询“等的负载均衡策略,我们还能重写该接口里的方法来自定义负载均衡的策略。
在BaseLoadBalancer类里,我们能通过IRule的实现类设置负载均衡的策略,这样该负载均衡器就能据此合理地转发请求。
第三,IPing接口,通过该接口,我们能获取到当前哪些服务器是可用的,我们也能通过重写该接口里的方法来自定义判断服务器是否可用的规则。在BaseLoadBalancer类里,我们同样能通过IPing的实现类设置判断服务器是否可用的策略。
1 ILoadBalancer:负载均衡器接口
在Ribbon里,我们还可以通过ILOadBalancer这个接口以基于特定的负载均衡策略来选择服务器。
通过下面的ILoadBalancerDemo.java,我们来看下这个接口的基本用法。这个类是放在4.2部分创建的RabbionBasicDemo项目里,代码如下。
//省略必要的package和import代码
public class ILoadBalancerDemo {
public static void main(String[] args){
//创建ILoadBalancer的对象
ILoadBalancer loadBalancer = new BaseLoadBalancer();
//定义一个服务器列表
List<Server> myServers = new ArrayList<Server>();
//创建两个Server对象
Server s1 = new Server("ekserver1",8080);
Server s2 = new Server("ekserver2",8080);
//两个server对象放入List类型的myServers对象里
myServers.add(s1);
myServers.add(s2);
//把myServers放入负载均衡器
loadBalancer.addServers(myServers);
//在for循环里发起10次调用
for(int i=0;i<10;i++){
//用基于默认的负载均衡规则获得Server类型的对象
Server s = loadBalancer.chooseServer("default");
//输出IP地址和端口号
System.out.println(s.getHost() + ":" + s.getPort());
}
}
}
在第5行里,我们创建了BaseLoadBalancer类型的loadBalancer对象,而BaseLoadBalancer是负载均衡器ILoadBalancer接口的实现类。
在第6到第13行里,我们创建了两个Server类型的对象,并把它们放入了myServers里,在第15行里,我们把List类型的myServers对象放入了负载均衡器里。
在第17到22行的for循环里,我们通过负载均衡器模拟了10次选择服务器的动作,具体而言,是在第19行里,通过loadBalancer的chooseServer方法以默认的负载均衡规则选择服务器,在第21行里,我们是用“打印”这个动作来模拟实际的“使用Server对象处理请求”的动作。
上述代码的运行结果如下所示,其中我们能看到,loadBalancer这个负载均衡器把10次请求均摊到了2台服务器上,从中确实能看到 “负载均衡”的效果。
第二,IRule,这个接口有多个实现类,比如RandomRule和RoundRobinRule,这些实现类具体地定义了诸如“随机“和”轮询“等的负载均衡策略,我们还能重写该接口里的方法来自定义负载均衡的策略。
在BaseLoadBalancer类里,我们能通过IRule的实现类设置负载均衡的策略,这样该负载均衡器就能据此合理地转发请求。
第三,IPing接口,通过该接口,我们能获取到当前哪些服务器是可用的,我们也能通过重写该接口里的方法来自定义判断服务器是否可用的规则。在BaseLoadBalancer类里,我们同样能通过IPing的实现类设置判断服务器是否可用的策略。
ekserver2:8080
ekserver1:8080
ekserver2:8080
ekserver1:8080
ekserver2:8080
ekserver1:8080
ekserver2:8080
ekserver1:8080
ekserver2:8080
ekserver1:8080
2 IRule:定义负载均衡规则的接口
在Ribbon里,我们可以通过定义IRule接口的实现类来给负载均衡器设置相应的规则。在下表里,我们能看到IRule接口的一些常用的实现类。
实现类的名字 | 负载均衡的规则 |
RandomRule | 采用随机选择的策略 |
RoundRobinRule | 采用轮询策略 |
RetryRule | 采用该策略时,会包含重试动作 |
AvailabilityFilterRule | 会过滤些多次连接失败和请求并发数过高的服务器 |
WeightedResponseTimeRule | 根据平均响应时间为每个服务器设置一个权重,根据该权重值优先选择平均响应时间较小的服务器 |
ZoneAvoidanceRule | 优先把请求分配到和该请求具有相同区域(Zone)的服务器上 |
在下面的IRuleDemo.java的程序里,我们来看下IRule的基本用法。
//省略必要的package和import代码
public class IRuleDemo {
public static void main(String[] args){
//请注意这是用到的是BaseLoadBalancer,而不是ILoadBalancer接口
BaseLoadBalancer loadBalancer = new BaseLoadBalancer();
//声明基于轮询的负载均衡策略
IRule rule = new RoundRobinRule();
//在负载均衡器里设置策略
loadBalancer.setRule(rule);
//如下定义3个Server,并把它们放入List类型的集合中
List<Server> myServers = new ArrayList<Server>();
Server s1 = new Server("ekserver1",8080);
Server s2 = new Server("ekserver2",8080);
Server s3 = new Server("ekserver3",8080);
myServers.add(s1);
myServers.add(s2);
myServers.add(s3);
//在负载均衡器里设置服务器的List
loadBalancer.addServers(myServers);
//输出负载均衡的结果
for(int i=0;i<10;i++){
Server s = loadBalancer.chooseServer(null);
System.out.println(s.getHost() + ":" + s.getPort());
}
}
}
这段代码和上文里的ILoadBalancerDemo.java很相似,但有如下的差别点。
1 在第5行里,我们是通过BaseLoadBalancer这个类而不是接口来定义负载均衡器,原因是该类包含setRule方法。
2 在第7行定义了一个基于轮询规则的rule对象,并在第9行里把它设置进负载均衡器。
3 在第19行里,我们是把包含3个Server的List对象放入负载均衡器,而不是之前的两个。由于这里存粹是为了演示效果,所以我们就放入一个根本不存在的“ekserver3”服务器。
运行该程序后,我们可以看到有10次输出,而且确实是按“轮询”的规则有顺序地输出3个服务器的名字。如果我们把第7行的代码改成如下,那么就会看到 “随机”地输出服务器名。
IRule rule = new RandomRule();
3 IPing:判断服务器是否可用的接口
在项目里,我们一般会让ILoadBalancer接口自动地判断服务器是否可用(这些业务都封装在Ribbon的底层代码里),此外,我们还可以用Ribbon组件里的IPing接口来实现这个功能。
在下面的IRuleDemo.java代码里,我们将演示IPing接口的一般用法。
//省略必要的package和import代码
class MyPing implements IPing {
public boolean isAlive(Server server) {
//如果服务器名是ekserver2,则返回false
if (server.getHost().equals("ekserver2")) {
return false;
}
return true;
}
}
第2行定义的MyPing类实现了IPing接口,并在第3行重写了其中的isAlive方法。
在这个方法里,我们根据服务器名来判断,具体而言,如果名字是ekserver2,则返回false,表示该服务器不可用,否则返回true,表示当前服务器可用。
public class IRuleDemo {
public static void main(String[] args) {
BaseLoadBalancer loadBalancer = new BaseLoadBalancer();
//定义IPing类型的myPing对象
IPing myPing = new MyPing();
//在负载均衡器里使用myPing对象
loadBalancer.setPing(myPing);
//同样是创建三个Server对象并放入负载均衡器
List<Server> myServers = new ArrayList<Server>();
Server s1 = new Server("ekserver1", 8080);
Server s2 = new Server("ekserver2", 8080);
Server s3 = new Server("ekserver3", 8080);
myServers.add(s1);
myServers.add(s2);
myServers.add(s3);
loadBalancer.addServers(myServers);
//通过for循环多次请求服务器
for (int i = 0; i < 10; i++) {
Server s = loadBalancer.chooseServer(null);
System.out.println(s.getHost() + ":" + s.getPort());
}
}
}
在第12行的main函数里,我们在第15行创建了IPing类型的myPing对象,并在第17行把这个对象放入了负载均衡器。通过第18到第26行的代码,我们创建了三个服务器,并把它们也放入负载均衡器。
在第28行的for循环里,我们依然是请求并输出服务器名。由于这里的负载均衡器loadBalancer中包含了一个IPing类型的对象,所以在根据策略得到服务器后,会根据myPing里的isActive方法来判断该服务器是否可用。
由于在这个方法里,我们定义了ekServer2这台服务器不可用,所以负载均衡器loadBalancer对象始终不会把请求发送到该服务器上,也就是说,在输出结果中,我们不会看到“ekserver2:8080”的输出。
从中我们能看到IPing接口的一般用法,我们可以通过重写其中的isAlive方法来定义“判断服务器是否可用“的逻辑,在实际项目里,判断的依据无非是”服务器响应是否时间过长“或”发往该服务器的请求数是否过多“,而这些判断方法都封装在IRule接口以及它的实现类里,所以在一般的场景中我们用到IPing接口。
来源:http://www.cnblogs.com/JavaArchitect/p/8648420.html


猜你喜欢
- 一、判断一个字符串str不为空的方法有:1、str == null;2、"".equals(str);3、str.len
- (注意:本文基于JDK1.8) 前言包括迭代器中的remove()方法,以及删除单个元素、删除多个元素、删除所有元素、删除不包含的
- #define Testusing System;namespace Wrox.ProCSharp.ParameterTestSample.
- 本文实例讲述了Java正则验证正整数的方法。分享给大家供大家参考,具体如下:package des;import java.util.reg
- 本文实例为大家分享了Android实现下载文件的具体代码,供大家参考,具体内容如下1.实现效果直接上图: 2.代码实现在AndroidMan
- SqlMapConfig.xml的约束,也就是Mybatis主配置文件的约束<?xml version="1.0"
- android中的事件类型分为按键事件和屏幕触摸事件,Touch事件是屏幕触摸事件的基础事件,有必要对它进行深入的了解。 一个最简单的屏幕触
- 1、存储在App内部最简单的一种。在尝试过程中发现,手机中很多文件夹都没有权限读写。我们可以将我们需要写的文件存放到App中的files文件
- Android基础教程数据存储之文件存储将数据存储到文件中并读取数据1、新建FilePersistenceTest项目,并修改activit
- 成为一个优秀的Java程序员,有着良好的代码编写习惯是必不可少的。下面就让我们来看看代码编写的30条建议吧。(1) 类名首字母应该大写。字段
- 在Java解析XML文件的过程中,有时需要获取符合某些特定条件的节点,以下是实现代码。import javax.xml.xpath.XPat
- 本文实例讲述了Android实现ListView控件的多选和全选功能。分享给大家供大家参考,具体如下:主程序代码MainActivity.J
- Kotlin 面向对象这几天一直在准备考试,实在没有时间,已经过去了这么久,终于要到面向对象了!先看看Kotlin中的类长什么样吧.可以看到
- 第一次写技术博客,写一下以前写的一个双色球抽奖随机算法。原理如下:1首先初始化一个待抽奖的数组nums,数组的长度k2. 随机一个1-k之间
- 如下:public Object invokeMethod(String className, String methodName,Obje
- 一、在学习枚举之前,首先来听听枚举的优点。1、枚举能够使代码更加清晰,它允许使用描述性的名称表示整数值。2、枚举使代码更易于维护,有助于确保
- 小伙伴私信我说想要研究下Spring的源码,想让我出一期教程来实现IDEA导入Spring源码,今天它来了~版本 :IDEA 2020.2.
- 前言本文主要学习函数的相关内容。1、函数是什么? * 中对函数的定义:子程序在计算机科学中,子程序(英语:Subroutine, proc
- android仿照qq的顶部栏效果,主要就是利用fragment manager把fragment设置显示内容(1)在activity_ma
- 前言大家都知道网络操作的响应时间是不定的,所有的网络操作都应该放在一个异步操作中处理,而且为了模块解耦,我们希望网络操作由专门的类来处理。所