ribbon 来完成负载均衡
RibbonLoadBalanceClient 类,是用来 进行负载均衡的;
其中有个 choose 的方法,源码如下:
》
意思是,对serverId 进行实例化;
创建测试类;
那么对其进行详解下:
RibbonLoadBalanceClient 中有getServer( )这个获取服务的方法:
@Override
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
Server server = getServer(loadBalancer);
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
}
RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
serviceId), serverIntrospector(serviceId).getMetadata(server));
return execute(serviceId, ribbonServer, request);
}
点击 getServer 跟进去,底层维护了 chooseServer()的一个方法,继续点
protected Server getServer(ILoadBalancer loadBalancer) {
if (loadBalancer == null) {
return null;
}
return loadBalancer.chooseServer("default"); // TODO: better handling of key
}
进入chooseServer 跟踪到 ILoadBalancer
Ctrl alt B 查看, 该接口的一个 实现类 BaseLoadBalancer
public class BaseLoadBalancer extends AbstractLoadBalancer implements PrimeConnectionListener, IClientConfigAware {
private static Logger logger = LoggerFactory.getLogger(BaseLoadBalancer.class);
// rule的默认值
private static final IRule DEFAULT_RULE = new RoundRobinRule();
private static final BaseLoadBalancer.SerialPingStrategy DEFAULT_PING_STRATEGY = new BaseLoadBalancer.SerialPingStrategy();
private static final String DEFAULT_NAME = "default";
private static final String PREFIX = "LoadBalancer_";
// IRule 类
protected IRule rule;
protected IPingStrategy pingStrategy;
protected IPing ping;
@Monitor(
name = "LoadBalancer_AllServerList",
type = DataSourceType.INFORMATIONAL
)
private static final IRule DEFAULT_RULE = new RoundRobinRule();
可以得知,IRule rule 的默认值是 RoundRobinRule 的一个对象,即轮询的对象,即默认的规则是轮询的方式;
public Server choose(Object key) {
ILoadBalancer lb = this.getLoadBalancer();
Optional<Server> server = this.getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
return server.isPresent() ? (Server)server.get() : null;
}
在服务的消费者添加@LoadBalanced 注解;
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {
@Bean
@LoadBalanced //添加负载均衡
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class,args);
}
}
直接使用服务名来查询服务:
@RestController
@RequestMapping("consumer")
public class ConsumerController {
/**
* 注入 springCloud 的DiscoveryClient
*/
// @Autowired
// private DiscoveryClient discoveryClient;
@Autowired
private RestTemplate restTemplate;
@GetMapping("{id}")
public User get(@PathVariable("id")Long id){
// 从eureka 中取出一个服务
// List instances = discoveryClient.getInstances("user-service");
// ServiceInstance serviceInstance = instances.get(0);
// 从服务中 获取 port 以及host 组成url 、 进行查询
// String url = String.format("http://%s:%s/user/%s", serviceInstance.getHost(), serviceInstance.getPort(), id);
// String url="http://localhost:8081/user/"+id;
// return restTemplate.getForObject(url, User.class, id);
String url="http://user-service/user/"+id;
return restTemplate.getForObject(url,User.class );
}
}
访问 http://localhost:8080/consumer/1
创建测试类,重写RibbonLoadBalanceClient 类 中的choose 方法,进行测试;
/**
* @auther SyntacticSugar
* @data 2018/11/29 0029下午 9:04
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ConsumerApplication.class)
public class LoadBalancedTest {
@Autowired
RibbonLoadBalancerClient loadBalancerClient;
@Test
public void test() {
for (int i = 0; i < 10; i++) {
ServiceInstance instance = loadBalancerClient.choose("user-service");
System.out.println(instance.getPort());
}
}
}
对配置文件进行更改,可以更改IRule 的实现类,从而修改规则;
user-service:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule