springboot+Ribbon实现负载均衡 Ribbon官网地址https://github.com/Netflix/ribbon/wiki/Getting-Started Ribbon虽然现在也进入到了维护阶段,但是由于有很多的项目还在使用它所以还是很有潜力的一个工具。 Ribbon是一个属于进程内的负载均衡工具,这个和ngnix是不一样的,ngnix是一个集中式的负载均衡器。 这里举个例子:ngnix就是我们进入学校的一个大门,Ribbon就相当于我们进入学校后要去到的班级。 Ribbon默认采用的是轮询的算法,负载均衡+RestTemplate调用,Ribbon主要就是和RestTemplate进行配合使用。如果想要实现负载均衡只需要在客户端的RestTemplate类中配置注解 @LoadBalanced即可实现轮询的算法
@Configuration
public class ApplicationContextConfig {
@Bean
//使用轮询的负载均衡 @LoadBalanced
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
总结:Ribbon其实就是一个软负载均衡的客户端组件,他可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例。 在新的spring-cloud-starter-netflix-eureka-client中默认是有Ribbon的所以不用再添加pom
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
在spring-cloud-starter-consul-discovery也是默认存在Ribbon的
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
在 spring-cloud-starter-zookeeper-discovery也是默认存在Ribbon的
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
后续如果还有别的默认Ribbon的将再更新 Ribbon出了默认的轮询还有哪些负载均衡算法
com.netflix.loadbalancer.RoundRobinRule 轮询
com.netflix.loadbalancer.RandomRule 随机
com.netflix.loadbalancer.RetryRule 先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试
WeightedResponseTimeRule 对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择
BestAvailableRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
AvailabilityFilteringRule 先过滤掉故障实例,再选择并发较小的实例
ZoneAvoidanceRule默认规则,复合判断server所在区域的性能和server的可用性选择服务器
这些算法都可以通过替换轮询来自定义实现Ribbon的负载均衡
下面就是如何来替换默认的轮询算法 这里需要特别注意的是不要将其他算法的实现配置类放到能被@ComponentScan扫描到的包下,如果放到能被扫描到的包下那么我们自定义的这个Ribbon的配置类就会被Ribbon的客户端共享,这样就起不到自定义的效果了。 比如@ComponentScan能扫描到的包为com.cn.ribbon,那么我们在自定义配置类时最少也得到com.cn.ribbon1路径的上一次或者干脆就写个不一样的路径。 生产者就不再重复新建了需要的请看
消费者需要修改 这里我就将修改的部分贴出需要其他内容的看上面的连接 新建一个不被@ComponentScan扫描到的路径然后在该路径下新建一个配置类MySelfRule
@Configuration
public class MySelfRule {
@Bean
public IRule myRule(){
return new RandomRule();//定义为随机
}
}
然后在启动类上添加注解@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class) 这样就表示使用自定义的负载均衡算法代替默认的轮询算法
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
public class OrderMain {
public static void main(String[] args) {
SpringApplication.run(OrderMain.class,args);
}
}
启动项目运行接口就可以看到随机访问。
手写一个简单的负载均衡算法
服务器轮询负载均衡原理
Ribbon各种算法的结构树
手写一个简单的轮询算法
在生产者的controller中添加一个获取当前端口号的方法
@GetMapping(value = "/payment/lb")public String getPaymentLB(){ return serverPort;}
消费者端先将ApplicationContextBean去掉@LoadBalanced 写一个LoadBalancer接口
public interface LoadBalancer {
//收集服务器总共有多少台能够提供服务的机器,并放到list里面
ServiceInstance instances(List<ServiceInstance> serviceInstances);}
实现LoadBalancer接口
@Component
public class MyLB implements LoadBalancer {
private AtomicInteger atomicInteger = new AtomicInteger(0); //坐标
private final int getAndIncrement(){
int current;
int next;
do {
current = this.atomicInteger.get();
next = current >= 2147483647 ? 0 : current + 1;
}while (!this.atomicInteger.compareAndSet(current,next)); //第一个参数是期望值,第二个参数是修改值是
System.out.println("*******第几次访问,次数next: "+next); return next; }
@Override
public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
//得到机器的列表
int index = getAndIncrement() %serviceInstances.size();
//得到服务器的下标位置
return serviceInstances.get(index); }}
controller类
@GetMapping(value = "/consumer/payment/lb")
public String getPaymentLB(){
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
if (instances == null || instances.size() <= 0){
return null;
}
ServiceInstance serviceInstance = loadBalancer.instances(instances);
URI uri = serviceInstance.getUri();
return restTemplate.getForObject(uri+"/payment/lb",String.class); }