目录
3.1.我们只需要导入eureka的包即可,不需要单独导如ribbon的包,因为eureka的包导入之后,maven会包含Robbin的包
1:什么是Ribbon
Ribbon的作用是实现负载均衡的,但是ribbon是客户端负载均衡,不同于以往我们所见的nignx服务端负载。它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。
客户端负载均衡:所有客户端节点都维护着自己要访问的服务端清单,而这些服务端端清单来自于服务注册中心,比如上一章我们介绍的Eureka服务端。同服务端负载均衡的架构类似,在客户端负载均衡中也需要心跳去维护服务端清单的健康性,默认会创建针对各个服务治理框架的Ribbon自动化整合配置,
服务端负载均衡:传同的服务端负载均衡,或者是软负载比如nignx后者是应负载F5,都是通过轮询算法,请求到负载服务器,然后在负载道不同的机器上。
2:Ribbon怎么使用
服务消费者直接通过调用被@LoadBalanced注解修饰过的RestTemplate来实现面向服务的接口调用。
客户端负载均衡即是当浏览器向后台发出请求的时候,客户端会向 Eureka Server 读取注册到服务器的可用服务信息列表,然后根据设定的负载均衡策略(没有设置即用默认的),抉择出向哪台服务器发送请求。
3:Ribbon负载均衡代码展示
3.1.我们只需要导入eureka的包即可,不需要单独导如ribbon的包,因为eureka的包导入之后,maven会包含Robbin的包
<!--Springcloud的eureka组件 client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
3.2:eureka的包包含ribbon,如图所示
3.3:需要使用@LoadBalanced注解即可,默认
package com.thit.controller;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @author :huyiju
* @date :2020-04-10 17:11
*/
@Configuration //由多个bean的时候使用
public class RestTemplateTest {
@Bean //方法名字就是bean的名字("方法名字")
@LoadBalanced //此注解用来负载均衡
public RestTemplate restTemplate1(){
return new RestTemplate();
}
}
4:切换不同的负载均衡算法
bobbin的负载均衡算法有以下7中。
4.1:切换指定的负载均称算法
@Configuration
public class MyRule {
@Bean
public IRule newrule(){
//轮询算法 new RoundRobinRule();
// 随机算法 new RandomRule
//过滤多次故障 选择最小并发 new BestAvailableRule();
return new RandomRule();
}
}
4.2:主启动类
@SpringBootApplication
@ComponentScan(basePackages= {"com.thit"})
@EnableEurekaClient //客户端需要EnableEurekaClient注解
@RibbonClient(name = "CLIENT",configuration = MyRule.class) //自定义负载均称
public class Consumer1Application {
public static void main(String[] args) {
SpringApplication.run(Consumer1Application.class,args);
}
}
5:新增负载均衡算法
5. 1:新增算法类实现负载均称算法
/**
* @author :huyiju
* @date :2020-04-22 19:26
*/
public class MyRule1 extends AbstractLoadBalancerRule {
//自定义原子类
private AtomicInteger nextServerCyclicCounter;
private static Logger log = LoggerFactory.getLogger(MyRule1.class);
//构造函数为0
public MyRule1() {
this.nextServerCyclicCounter = new AtomicInteger(0);
}
public MyRule1(ILoadBalancer lb) {
this();
this.setLoadBalancer(lb);
}
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
log.warn("no load balancer");
return null;
} else {
Server server = null;
int count = 0;
while(true) {
if (server == null && count++ < 10) {
//获取存活的服务
List<Server> reachableServers = lb.getReachableServers();
//获取所有服务
List<Server> allServers = lb.getAllServers();
int upCount = reachableServers.size();
int serverCount = allServers.size();
if (upCount != 0 && serverCount != 0) {
//取模 获取下标
int nextServerIndex = this.incrementAndGetModulo(serverCount);
//获取下标
server = (Server)allServers.get(nextServerIndex);
if (server == null) {
Thread.yield();
} else {
if (server.isAlive() && server.isReadyToServe()) {
return server;
}
server = null;
}
continue;
}
log.warn("No up servers available from load balancer: " + lb);
return null;
}
if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: " + lb);
}
return server;
}
}
}
//核心算法 随机数
private int incrementAndGetModulo(int modulo) {
Random r=new Random();
//随机数
int current;
//求膜
int next;
current = r.nextInt(10000);
System.out.println("随机数是:"+current);
next = (current + 1) % modulo;
System.out.println("服务节点是:"+next);
return next;
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
5. 1:主类启动类
@SpringBootApplication
@ComponentScan(basePackages= {"com.thit"})
@EnableEurekaClient //客户端需要EnableEurekaClient注解
@RibbonClient(name = "CLIENT",configuration = MyRule1.class) //自定义负载均称
public class Consumer1Application {
public static void main(String[] args) {
SpringApplication.run(Consumer1Application.class,args);
}
}
6:注意事项
官方文档指出:
这个自定义的类不能放在@ComponentScan所扫描的当前包以及子包下,否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,也就是我们达不到特殊化指定的目的了。