*Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端 负载均衡的工具。
*简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如:连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。
*LB(负载均衡)
*在微服务或分布式集群中经常使用的一种应用。
*负载均衡简单的说就是将用户的请求平摊的分配到多个服务商,从而达到系统的HA(高可用)
*常见的负载均衡有软件Nginx,LVS,硬件F5等
*相应的在中间件,例如:dubbo和SpringCloud中君给我们提供了负载均衡,SpringCloud的负载均衡算法可以自定义。
*集中式LB 偏硬件
*即在服务的消费方和提供方之间使用独立的LB设施(可以使硬件,如F5,也可以是软件,如Nginx),由该设施负责把访问请求通过某种策略转发至服务的提供方;(F5很强大,但是贵)
*进程内LB 偏软件
*将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择一个合适发服务器。
*Ribbon就属于进程内LB,它只是一个类库,集成与消费方进程,消费方通过它来获取到服务提供方的地址。
*Ribbon初步配置
**修改pom.xml 添加依赖
1.修改消费者yml配置文件
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
2.对ConfigBean进行新注解@LoadBalanced 获得Rest时加入Ribbon的配置
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced //Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端 负载均衡的工具。
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
//选择其他算法
@Bean
public IRule myRule(){
//用我们重新选择的随机算法覆盖默认的轮询
return new RandomRule();
}
}
3.修改启动类
name为服务名 configuration 读取配置MySelfRule类 可暂时不配 自定义算法所用 下面配置
@RibbonClient(name = "MICROSERVICECLOUD-DEPT",configuration = MySelfRule.class)
4.修改DeptController_Consumer 直接用服务名字
*完成真正的通过微服务名字从Eureka上找到并访问
private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT";
5.启动测试
*小结:Ribbon和Eureka整合后Consumer可以直接调用服务而不用再关心地址和端口号
1.*创建项目microservicecloud-provider-dept-8002
*创建项目microservicecloud-provider-dept-8003
2.修改yml配置,创建新的数据库cloudDB02、cloudDB03
*复制粘贴8001,修改部分配置,端口,url等
3.简单测试 02,03
4.启动80,Ribbon默认轮询复杂均衡算法
*Ribbon在工作时分成两步
*选择EurekaServer,优先选择在用一个区域内负载较少的Server
*根据用户指定的策略,在从Server取到的服务注册列表中选择一个地址;不指定则轮询
*Ribbon就是一个负载均衡的客户端组件,可以和其他所需请求的客户端结合使用,和Eureka结合只是其中的一个实例
*Ribbon核心组件:IRule
*根据特定算法中从服务列表中选取一个要访问的服务
*七种负载均衡算法
*自定义Ribbon
*在启动该微服务的时候就能去加载我们的自定义Ribbon配置类,从而使配置生效,形如:
@RibbonClient(name = "MICROSERVICECLOUD-DEPT",configuration = MySelfRule.class)
*创建MySelfRule类 自定义算法:每个服务器要求被调用五次
@Configuration
public class MySelfRule {
@Bean
public IRule myRule(){
// return new RandomRule();//Ribbon默认是轮询,自定义为随机
//指向自定义的算法类RandomRule_***
return new RandomRule_***();
}
}
*创建RandomRule_***
*源码地址:
https://github.com/Netflix/ribbon/blob/master/ribbon-loadbalancer/src/main/java/com/netflix/loadbalancer/RandomRule.java
import java.util.List;
public class RandomRule_*** extends AbstractLoadBalancerRule{
//total = 0 //当前total==5以后,我们指针才能往下走
//index = 0 //当前对外提供服务的服务器地址,
//total需要重新置为零,但是已经达到过一次5,index= 1
//分析:我们定义5次,但是微服务只有8001,8002,8003三台
//index<=3
private int total = 0; //总共被调用的次数,目前要求每台被调用5次
private int currentIndex = 0; //当前提供服务的机器号
//是netflix.loadbalancer的service包
public Server choose(ILoadBalancer lb , Object key) {
if(lb == null){
return null;
}
//设置初始服务端口为null
Server server = null;
//while循环判断
while (server == null){
//如果线程中断 则返回null
if(Thread.interrupted()){
return null;
}
//获取可用端口
List
//获取全部端口
List
//获取当前端口数量
int serverCount = allList.size();
//如果为0 则返回null
if(serverCount == 0){
return null;
}
// private int total = 0; //总共被调用的次数,目前要求每台被调用5次
// private int currentIndex = 0; //当前提供服务的机器号
//自定义算法
//如果被调用次数小于5
if(total < 5){
//第一次 total < 5 0号机被调用
server = uplist.get(currentIndex);
total++;
}else{ //调用次数>=5
//初始化total调用次数
total = 0;
//当前提供服务的机器号++
currentIndex++;
//服务器号是否大于机器总数量
if(currentIndex >= uplist.size()){
//当服务器号>服务总台数 重置为0
currentIndex = 0;
}
}
//server为空
if(server == null){
//停掉走下一次
Thread.yield();
continue;
}
//server还活着
if(server.isAlive()){
//返回当前server
return (server);
}
//走完上面程序如果还没不返回server,就返回null 并
server = null;
//使当前线程从执行状态(运行状态)变为可执行态(就绪状态)
Thread.yield();
}
return server;
}
@Override
public Server choose(Object key) {
//调用choose
return choose(getLoadBalancer(),key);
}
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
}
*官方文档明确给出了警告:
*这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,也就是说我们达不到特殊化制定的目的了。
*而@SpringBootApplication 就包含了@ComponentScan注解,所以,不能在主启动类下的包内创建