查看Ribbon :https://blog.csdn.net/qq_32534855/article/details/84111188
1.Eureka服务发现
product 启动了两个实例
2.RestTemplate
RestTemplate
参考:https://blog.csdn.net/madmk/article/details/76431486
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject("http://localhost:9001/msg",String.class);
log.info("response={}",response);
这种方式,调用很简单,但是访问地址写死,不方便,所以这种方式很少用。
并且,当服务启动多个时,很难做到调用多个服务实例。
3.LoadBalancerClient + RestTemplate
我们通过loadBalancerClient根据应用名获取url
@Autowired
LoadBalancerClient loadBalancerClient;
/**
* LoadBalancerClient + RestTemplate方式
*
* @return
*/
@GetMapping("/msg2")
public String helloMsg2() {
RestTemplate restTemplate = new RestTemplate();
ServiceInstance instance = loadBalancerClient.choose("product");
String storesUri = String.format("http://%s:%s", instance.getHost(), instance.getPort());
String response = restTemplate.getForObject(storesUri + "/msg", String.class);
log.info("response={}", response);
return response;
}
4.@LoadBalanced注解
添加RestTemplateConfig 配置文件,重点在方式上添加**@LoadBalanced**注解
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
使用
@Autowired
private RestTemplate restTemplate;
/**
* LoadBalancerClient + RestTemplate方式
*
* @return
*/
@GetMapping("/msg3")
public String helloMsg3() {
//通过应用名+访问地址
String response = restTemplate.getForObject("http://product/msg", String.class);
log.info("response={}", response);
return response;
}
5.Ribbon实现客户端负载均衡原理
5.1主要概念
- 服务发现 :根据服务名字,把该服务下所以实力查询出来
- 服务选择规则:根据服务选择规则,选择出一条有效服务
- 服务监听:检测失效的服务,高效剔除
5.2主要组件
- ServerList
- IRule
- ServerListFilter
流程:通过ServerList获取可用服务列表,然后通过ServerListFilter过滤掉一部分服务,最后通过IRule选择出一个最终目标结果。
5.3源码分析
5.3.1类间关系
5.3.2 获取可用服务列表
ServiceInstance instance = loadBalancerClient.choose("product");
我们按住CTRL跟进到choose方法里面
public ServiceInstance choose(String serviceId) {
return this.choose(serviceId, (Object)null);
}
public ServiceInstance choose(String serviceId, Object hint) {
Server server = this.getServer(this.getLoadBalancer(serviceId), hint);
return server == null ? null : new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
}
然后跟进CTRL this.getLoadBalancer(serviceId) 跟进得到的方法是
protected ILoadBalancer getLoadBalancer(String serviceId) {
return this.clientFactory.getLoadBalancer(serviceId);
}
我们现在查看ILoadBalancer
public interface ILoadBalancer {
void addServers(List<Server> var1);
Server chooseServer(Object var1);
void markServerDown(Server var1);
/** @deprecated */
@Deprecated
List<Server> getServerList(boolean var1);
List<Server> getReachableServers();
List<Server> getAllServers();
}
我们猜测gelAllServers是获取所有可用服务列表的集合,现在我们查看一下其实现方法BaseLoadBalancer打一个断点查看一下
public List<Server> getAllServers() {
return Collections.unmodifiableList(this.allServerList);
}
结果
这个刚好就是我们选择的PRODUCT的两个服务,就此我们可以判断,gelAllServers是根据服务名称获取服务列表的方法。
现在我们获取到服务列表了,下一步就应该根据规则选择一个服务进行返回。
5.3.3选择一个服务
现在跟进 this.getServer方法
protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
return loadBalancer == null ? null : loadBalancer.chooseServer(hint != null ? hint : "default");
}
然后跟进chooseServer方法
public Server chooseServer(Object key) {
if (this.counter == null) {
this.counter = this.createCounter();
}
this.counter.increment();
if (this.rule == null) {
return null;
} else {
try {
return this.rule.choose(key);
} catch (Exception var3) {
logger.warn("LoadBalancer [{}]: Error choosing server for key {}", new Object[]{this.name, key, var3});
return null;
}
}
}
我们可以看见Server svr = this.rule.choose(key); 这个方法,这个就是根据规则选择一个服务
我们查看一下规则rule
protected IRule rule;
构造函数
this.rule = DEFAULT_RULE;
private static final IRule DEFAULT_RULE = new RoundRobinRule();
通过名字我们可以看出来,负责均衡的方法规则是轮询的方式。
查看测试结果
第一次
第二次
第三次
我们跟进choose方法
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;
}
debug看到
lb变量里面的
我们可以看见所有服务列表,跟校验规则
然后根据
Optional<Server> server = this.getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
返回一个服务对象
5.4 修改规则
需要在application.yml
product: #访问服务名称
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
规则在IRule的实现类里面可以选择,也可以自定义
本文同步分享在 博客“DencyCheng”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。