springcloud 服務間通訊方式 Ribbon
阿新 • • 發佈:2018-11-16
檢視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; }
[email protected]註解
新增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的實現類裡面可以選擇,也可以自定義