ribbon是一个负载均衡工具,在springcloud的很多组件的中都将它融合进去了,所以有时候会出现很多让人蛋疼的版本冲突问题,笔者在学习的过程中就遇到了一些问题,其中最难受的就是yml文件中无法配置ribbon的连接超时时间,也翻看了一些源码,发现是底层有个配置类写死了,但又没有什么好的解决方案,如果您有幸略过此篇文章并有遇到过类似的问题,非常希望您提点下我_。
好(o)/~ 先记录下怎么搭建的吧
ribbon一般用于消费者的负载均衡,这里就略过服务提供者的那部分了
一、引入pom依赖
eureka整合了ribbon,所以只要引入eureka的依赖即可
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
二、主启动类记得打开@EnableEurekaClient注解哦
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
@EnableEurekaClient
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class,args);
}
}
其实到这里ribbon已经开始了负载均衡,但是默认的负载算法是轮询,是不是完全无感知,说白了@EnableEurekaClient已经开启了ribbon 哈哈
三、修改默认的负载均衡策略
新建一个配置类,这个类一定不能在主启动类同级别或主启动类级别的包下面(官网有明确要求)
package com.atguigu.ribbon;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.WeightedResponseTimeRule;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
@Configurable
public class RibbonConfiguration {
@Bean
public IRule ribbonRule(IClientConfig clientConfig) {
// 注册别的默认负载均衡方法
return new WeightedResponseTimeRule();
}
}
同时在主启动类级别的包下添加另外一个配置类,给RestTemplate添加负载均衡功能
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ApplicationContentConfig {
@Bean
@LoadBalanced //开启ribbon自带负载均衡
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
这样就妥了
四、自己写负载均衡策略
这里给个案例
接口 不多说
package com.atguigu.springcloud.lb;
import org.springframework.cloud.client.ServiceInstance;
import java.util.List;
public interface LoderBalancer {
ServiceInstance instances(List<ServiceInstance> instances);
}
AtomicInteger 原子类存储请求个数
自己写逻辑获取要调用的服下标
package com.atguigu.springcloud.lb;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@Component
public class MYLB implements LoderBalancer {
private AtomicInteger atomicInteger = new AtomicInteger(0);
public final int getAndIncrement(){
int current;
int next;
do {
current = atomicInteger.get();
next = current >= 2147483647 ? 0 : current+1;
} while (!this.atomicInteger.compareAndSet(current,next));
return next;
}
@Override
public ServiceInstance instances(List<ServiceInstance> instances) {
int index = getAndIncrement()%instances.size();
return instances.get(index);
}
}
获取所有的服务
调用上述方法获取下标,调用对用的服务
package com.atguigu.springcloud.controller;
import com.atguigu.springcloud.entities.CommenResult;
import com.atguigu.springcloud.entities.Payment;
import com.atguigu.springcloud.lb.LoderBalancer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.net.URI;
import java.util.List;
@RestController
@Slf4j
public class OrderController {
@Autowired
RestTemplate restTemplate;
@Autowired
LoderBalancer loderBalancer;
@Autowired
DiscoveryClient discoveryClient;
// private String url = "http://CLOUD-PAYMEN-SERVICE/";
@GetMapping(value = "consumer/payment/lb")
public CommenResult<Payment> getPaymentLB(@PathVariable("id") long id){
List<ServiceInstance> instances = discoveryClient.getInstances("服务提供者名称");
if (null == instances || instances.size()<=0){
return null;
}
ServiceInstance serviceInstance = loderBalancer.instances(instances);
URI uri = serviceInstance.getUri();
return restTemplate.getForObject(uri+"payment/get/"+id,CommenResult.class);
}
}