1. 程式人生 > >springcloud 服務間通訊方式 Ribbon

springcloud 服務間通訊方式 Ribbon

檢視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的實現類裡面可以選擇,也可以自定義