SpringCloud與微服務Ⅵ --- Ribbon負載均衡

一.Ribbon是什麼java

Sping Cloud Ribbon是基於Netflix Ribbon實現的一套客戶端負載均衡的工具。mysql

簡單的說,Ribbon是Netflix發佈的開源項目,主要功能是提供客戶端的軟件負載均衡算法,將Netflix的中間層服務鏈接在一塊兒。Ribbon客戶端組件提供一系列完整的配置項如鏈接超時,重試等。簡單地說,就是在配置文件中列出Load Balancer(簡稱LB) 後面全部的機器, Ribbon會自動的幫助你基於某種規則(如簡單輪詢,隨機鏈接等)去鏈接這些機器。咱們也很容易使用Ribbon實現自定義的負載均衡算法。nginx

負載均衡git

LB,即負載均衡(Load Balancer),在微服務或分佈式集羣中常常用的一種應用。github

負載均衡簡單的說就是將用戶的請求平攤的分配到多個服務上,從而達到系統的HA(高可用)。web

常見的負載均衡軟件有Nginx,LVS,硬件F5等。算法

相應的中間件,例如:dubbo和SpringCloud中均給咱們提供了負載均衡,SpringCloud的負載均衡算法能夠自定義。spring

  • 集中式LBsql

    即在服務的消費方和提供方之間使用獨立的LB設施(能夠是硬件F5(好用可是貴),也能夠說軟件,如nginx),由該設施負責把訪問請求經過某種策略轉發至服務的提供方。數據庫

  • 進程內LB

    將LB邏輯集成到消費方,消費方從服務註冊中心獲知有哪些地址可用,而後本身再從這些地址中選擇出一個合適的服務器。Ribbon就屬於進程內LB,它只是一個類庫,集成消費方進程,消費方經過它來獲取到服務提供方的地址。

官網資料:https://github.com/Netflix/ribbon/wiki

 

二.Ribbon的初步配置

修改microservice-consumer-dept-80項目。

1.修改pom文件:

<!-- Ribbon相關 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

2.修改yml配置文件:

eureka: client: register-with-eureka: false service-url: #defaultZone: http://localhost:7001/eureka
      defaultZone: http://localhost:7001/eureka,http://localhost:7002/eureka,http://localhost:7002/eureka

3.在RestTemplate上標註@LoadBalanced:

實現負載均衡

@Configuration public class MyApplicationConfig { @Bean @LoadBalanced //負載均衡
    public RestTemplate getRestTemplate(){ return new RestTemplate(); } } 

4.主啓動類註解@EnableEurekaClient

@SpringBootApplication @EnableEurekaClient public class DeptConsumer80 { public static void main(String[] args) { SpringApplication.run(DeptConsumer80.class,args); } }

5.修改微服務訪問地址

修改DeptController類中的REST_URL_PREFIX,使得消費端經過微服務名稱來訪問提供端的接口。

//private static final String REST_URL_PREFIX = "http://localhost:8001";
 private static final String REST_URL_PREFIX = "http://MICROSERVICE-DEPT";

結論:Ribbon和Eureka整合後Consumer能夠直接調用服務而不用再關心地址和端口號。

 

三.Ribbon的負載均衡

架構圖:

Ribbon在工做時分爲兩步

第一步先選擇EurekaServer,它優先選擇在同一個區域內負載較少的server。

第二步再根據用戶指定的策略,在從server取到的服務註冊列表中選擇一個地址。

其中Ribbon提供了多種策略:好比輪詢、隨機和根據響應時間加權。

搭建步驟:

1.新建兩個服務提供者microservice-provider-dept-800二、microservice-provider-dept-8003,項目能夠參考microservice-provider-dept-8001。

2.新建兩個數據庫cloudDB02,cloudDB03,表結構與cloudDB01數據庫一致

DROP DATABASE IF EXISTS cloudDB02; CREATE DATABASE cloudDB01 CHARACTER SET UTF8; USE cloudDB01; CREATE TABLE dept ( deptno BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT, dname VARCHAR(60), db_source VARCHAR(60) ); INSERT INTO dept(dname,db_source) VALUES('開發部',DATABASE()); INSERT INTO dept(dname,db_source) VALUES('人事部',DATABASE()); INSERT INTO dept(dname,db_source) VALUES('財務部',DATABASE()); INSERT INTO dept(dname,db_source) VALUES('市場部',DATABASE()); INSERT INTO dept(dname,db_source) VALUES('運維部',DATABASE());

3.分別修改microservice-provider-dept-800二、microservice-provider-dept-8003的yml文件。

主要修改的是端口號,數據庫。

server: port: 8002 spring: application: name: microservice-dept datasource: type: com.alibaba.druid.pool.DruidDataSource #數據源類型 driver-class-name: org.gjt.mm.mysql.Driver #數據庫驅動 url: jdbc:mysql://localhost:3306/cloudDB02 #數據庫url 

4.啓動全部項目,分別訪問:

http://localhost:8001/dept/get/1

http://localhost:8002/dept/get/1

http://localhost:8003/dept/get/1

若都能訪問,說明全部服務都已經啓用。

5.啓動客戶端項目microservice-consumer-dept-80,訪問http://localhost/consumer/dept/list。觀察返回的數據,並刷新頁面。能夠看到刷新後的數據分別來自不一樣數據庫,說明已經啓用了負載均衡。Ribbon默認採用的算法是輪詢算法。

總結:Ribbon其實就是一個軟負載均衡的客戶端組件,他能夠和其餘所需請求的客戶端結合使用,和eureka結合只是其中的一個實例。

 

四.Ribbon的核心組件IRule

Ribbon自帶的七種負載均衡算法

  1. RoundRobinRule:輪詢

  2. RandomRule:隨機

  3. AvailabilityFilteringRule:先過濾因爲屢次訪問故障而處於斷路器跳閘狀態的服務,還有併發的鏈接數量超過閾值的服務,而後對剩餘的服務列表按照輪詢策略進行訪問。

  4. WeightedReponseTimeRule:根據平均響應時間計算全部服務的權重,響應時間越短服務權重大被選中的機率高,剛啓動時若是統計信息不足,則使用輪詢策略,等統計信息足夠,會切換到WeightedReponseTimeRule

  5. RetryRule:先按照輪詢策略獲取服務,若是獲取服務失敗則在指定時間內會進行重試,獲取可用的服務

  6. BestAvailableRule:先過濾因爲屢次訪問故障而處於斷路器跳閘狀態的服務,而後選擇一個併發量最小的服務

  7. ZoneAvoidanceRule:默認規則,複合判斷server所在區域的性能和server的可用性選擇服務器

切換成隨機的負載均衡算法

須要換哪一種算法,只須要在config類裏注入該算法的bean,而後重啓服務就會生效了。

@Configuration public class MyApplicationConfig { @Bean @LoadBalanced //負載均衡
    public RestTemplate getRestTemplate(){ return new RestTemplate(); } @Bean public IRule myIRule(){ return new RandomRule(); } }

 經過上面的例子咱們知道,Ribbon默認採用的算法是輪詢算法,那麼如何配置自定義負載均衡算法呢?

 

五.自定義負載均衡算法

修改microservice-consumer-dept-80項目。

規則描述

要求每臺服務器被調用5次,而後輪詢以下一臺一樣被調用5次,全部服務器輪詢以後又從最初的服務器開始從新調用五次輪詢。

1.自定義算法規則

public class MyRandomRule extends AbstractLoadBalancerRule { // total = 0 // 當total==5之後,咱們指針才能往下走, // index = 0 // 當前對外提供服務的服務器地址, // total須要從新置爲零,可是已經達到過一個5次,咱們的index = 1 // 分析:咱們5次,可是微服務只有8001 8002 8003 三臺 // 
    
    private int total = 0;             // 總共被調用的次數,目前要求每臺被調用5次
    private int currentIndex = 0;    // 當前提供服務的機器號

    public Server choose(ILoadBalancer lb, Object key) { if (lb == null) { return null; } Server server = null; while (server == null) { if (Thread.interrupted()) { return null; } List<Server> upList = lb.getReachableServers(); List<Server> allList = lb.getAllServers(); int serverCount = allList.size(); if (serverCount == 0) { /* * No servers. End regardless of pass, because subsequent passes only get more * restrictive. */
                return null; } // int index = rand.nextInt(serverCount);// java.util.Random().nextInt(3); // server = upList.get(index); // private int total = 0; // 總共被調用的次數,目前要求每臺被調用5次 // private int currentIndex = 0; // 當前提供服務的機器號
            if(total < 5) { server = upList.get(currentIndex); total++; }else { total = 0; currentIndex++; if(currentIndex >= upList.size()) { currentIndex = 0; } } if (server == null) { /* * The only time this should happen is if the server list were somehow trimmed. * This is a transient condition. Retry after yielding. */ Thread.yield(); continue; } if (server.isAlive()) { return (server); } // Shouldn't actually happen.. but must be transient or a bug.
            server = null; Thread.yield(); } return server; } @Override public Server choose(Object key) { return choose(getLoadBalancer(), key); } @Override public void initWithNiwsConfig(IClientConfig clientConfig) { // TODO Auto-generated method stub
 } }

2.自定義規則的配置類:

@Configuration public class MySelfRule { @Bean public IRule myRule(){ return new MyRandomRule();  //自定義算法策略
 } }

注意:這個自定義配置類MySelfRule.class不能放在@ComponentScan所掃描的包下以及子包下.不然咱們自定義的這個配置類就會被全部Ribbon客戶端共享。

3.主啓動類添加@RibbonClient

在啓動該微服務的時候就能去加載咱們自定義Ribbon配置類,從而使配置生效

@SpringBootApplication @EnableEurekaClient @RibbonClient(name = "MICROSERVICE-DEPT",configuration = MySelfRule.class) public class DeptConsumer80 { public static void main(String[] args) { SpringApplication.run(DeptConsumer80.class,args); } }

以上步驟完成後,重啓全部服務器,調用客戶端microservice-consumer-dept-80項目的接口。這裏須要注意的是,若出現錯誤,等待一段時間,服務註冊的時候會有必定緩衝時間,而後再次訪問服務,而後測試負載均衡的策略是否符合自定義的規則。

相關文章
相關標籤/搜索