SpringCloud微服務架構第三篇

原文連接:https://www.javazhiyin.com/5130.htmlhtml

微服務開發專欄:https://www.javazhiyin.com/category/springcloudjava

 

Ribbon是什麼?mysql

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

簡單的說,Ribbon是Netflix發佈的開源項目,主要功能是提供客戶端的軟件負載均衡算法,將Netflix的中間層服務鏈接在一塊兒。Ribbon客戶端組件提供一系列完善的配置項如鏈接超時,重試等。git

簡單的說,就是在配置文件中列出Load Balancer(簡稱LB)後面全部的機器,Ribbon會自動的幫助你基於某種規則(如簡單輪詢,隨機鏈接等)去鏈接這些機器。咱們也很容易使用Ribbon實現自定義的負載均衡算法。github

Ribbon能幹什麼?

LB,即負載均衡(Load Balance),在微服務或分佈式集羣中常常用的一種應用。 
負載均衡簡單的說就是將用戶的請求平攤的分配到多個服務上,從而達到系統的HA。 算法

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

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

集中式LB:數據庫

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

進程內LB:

將LB邏輯集成到消費方,消費方從服務註冊中心獲知有哪些地址可用,而後本身再從這些地址中選擇出一個合適的服務器。

Ribbon就屬於進程內LB,它只是一個類庫,集成於消費方進程,消費方經過它來獲取到服務提供方的地址。

Ribbon的相關資料

https://github.com/Netflix/ribbon/wiki/Getting-Started

Ribbon初步的配置

1.修改microservicecloud-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>

  

2.修改application.yml 追加eureka的服務註冊地址

2).修改application.yml資源文件,增長如下內容:

eureka:

 client:

   register-with-eureka: false

   service-url:

     defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

  

3.對ConfigBean類進行新註解@LoadBalanced 得到Rest時加入Ribbon的配置。

3).修改ConfigBean類,增長如下內容:

@Bean @LoadBalanced //要求客戶端經過Rest去訪問微服務的時候自帶負載均衡

public RestTemplate getRestTemplate(){ return new RestTemplate(); }

 

4.主啓動類DeptConsumer80_App添加@EnableEurekaClient註解。

4).修改主啓動類DeptConsumer80_App,增長如下內容:

@SpringBootApplication

@EnableEurekaClient  

public class DeptConsumer80_App {

public static void main(String[] args) {

SpringApplication.run(DeptConsumer80_App.class, args);

 

}

}

  

5.修改DeptController_Consumer客戶端訪問類。

5).修改DeptController_Consumer,增長如下內容:

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

//從Eureka上面有一個叫MICROSERVICECLOUD-DEPT微服務名字,按名字訪問的微服務

private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT";

  

 

6.測試:

1).先啓動3個eureka集羣,也就是microservicecloud-eureka-7001,microservicecloud-eureka-7002和microservicecloud-eureka-7003。

2).再啓動microservicecloud-provider-dept-8001並註冊進eureka。

3).再啓動microservicecloud-consumer-dept-80。

輸入到瀏覽器: http://localhost/consumer/dept/get/1 進行測試

SpringCloud微服務架構第三篇

輸入到瀏覽器: http://localhost/consumer/dept/list 進行測試

SpringCloud微服務架構第三篇

輸入到瀏覽器: http://localhost/consumer/dept/add?dname=大數據部 進行測試

SpringCloud微服務架構第三篇

查看咱們的mysql數據庫看是否添加了大數據部:

添加成功效果圖:

SpringCloud微服務架構第三篇

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

Ribbon負載均衡

Ribbon負載均衡架構圖:

SpringCloud微服務架構第三篇

Ribbon在工做時分紅兩步 

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

  • 第二步再根據用戶指定的策略,在從server取到的服務註冊列表中選擇一個地址。 
    其中Ribbon提供了多種策略:好比輪詢、隨機和根據響應時間加權。

1.在總父工程下建立microservicecloud-provider-dept-8002的maven Module

1).而後再參考microservicecloud-provider-dept-8001的pom文件,將pom文件裏的配置複製一份到microservicecloud-provider-dept-8002 pom文件中

2.在總父工程下再建立microservicecloud-provider-dept-8003的maven Module

1).而後再參考microservicecloud-provider-dept-8001的pom文件,將pom文件裏的配置複製一份到microservicecloud-provider-dept-8003 pom文件中

3.將microservicecloud-provider-dept-8001的java源碼複製兩份分別給microservicecloud-provider-dept-8002和microservicecloud-provider-dept-8003,而且分別修改主啓動類名字

修改爲功後的效果圖:

SpringCloud微服務架構第三篇

4.而後再將microservicecloud-provider-dept-8001工程下的resources資源文件夾裏面的兩個配置文件都複製到microservicecloud-provider-dept-8002和microservicecloud-provider-dept-8003

效果圖以下:

SpringCloud微服務架構第三篇

而後咱們修改microservicecloud-provider-dept-8002和microservicecloud-provider-dept-8003的application.yml文件裏面的端口,都分別改成8002和8003端口。

5.新建兩個數據庫給microservicecloud-provider-dept-8002和microservicecloud-provider-dept-8003這兩個工程鏈接和使用

備註:建立cloudDB02數據庫,執行如下sql語句

DROP DATABASE IF EXISTS cloudDB02;

 

CREATE DATABASE cloudDB02 CHARACTER SET UTF8;

 

USE cloudDB02;

 

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());

 

SELECT * FROM dept;

  

再建立一個名爲cloudDB03的數據庫,執行如下sql語句。

DROP DATABASE IF EXISTS cloudDB03;

 

CREATE DATABASE cloudDB03 CHARACTER SET UTF8;

 

USE cloudDB03;

 

 

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());

 

SELECT * FROM dept;

  

而後再改microservicecloud-provider-dept-8002和microservicecloud-provider-dept-8003這兩個工程的application.yml文件下的數據庫源的url指定的數據庫名字

  • microservicecloud-provider-dept-8002工程連 cloudDB02,

  • microservicecloud-provider-dept-8003工程連 cloudDB03。

好了,咱們作了那麼多配置和修改,如今要進入測試咱們的負載均衡了!!!!

測試的步驟:

1.啓動3個eureka集羣配置(microservicecloud-eureka-7001系列)

2.啓動3個Dept微服務並各自測試經過(microservicecloud-provider-dept-8001系列)

 啓動3個Dept微服務成功後先進行一次測試

 1).先在瀏覽器輸入第一個網址:http://localhost:8001/dept/list 進行測試

 2).再從瀏覽器中輸入第二個網址:http://localhost:8002/dept/list 進行測試

 3).再從瀏覽器中輸入第三個網址:http://localhost:8003/dept/list 進行測試

 若是三個網址都成功出現JSON字符串,而且db_source的數據都不一樣,那麼說明成功了!!!

3.啓動microservicecloud-consumer-dept-80

啓動成功之後,在瀏覽器輸入:http://localhost/consumer/dept/list

就能夠體現負載均衡的效果了。

啓動成功後的負載均衡效果圖: 這是第一次訪問的結果,

SpringCloud微服務架構第三篇

咱們在http://localhost/consumer/dept/list 這個頁面上刷新一次該頁面就會看到clouddb03會變成clouddb02再刷新一次就會變成clouddb01。依次這樣,這種模式採用的是輪詢算法,這裏就不演示了。

備註:注意觀察看到返回的數據庫名字,各不相同,負載均衡實現

而後再打開http://eureka7001.com:7001/ 你就能夠看到在一個微服務下面掛着三個實例

SpringCloud微服務架構第三篇

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

Ribbon核心組件之IRule

根據特定算法中從服務列表中選取一個要訪問的服務。

SpringCloud結合Ribbon,它默認出廠自帶了7種算法。

第一種是:RoundRobinRule 輪詢

第二種是:RandomRule 隨機

第三種是:AvailabilityFilteringRule 會先過濾掉因爲屢次訪問故障而處於斷路器跳閘狀態的服務, 

還有併發的鏈接數量超過閾值的服務,而後對剩餘的服務列表按照輪詢策略進行訪問。

第四種是:WeightedResponseTimeRule 根據平均響應時間計算全部服務的權重,響應時間越快服務權重越大被選中的機率越高。剛啓動時若是統計信息不足,則使用RoundRobinRule策略,等統計信息足夠, 
會切換到WeightedResponseTimeRule。

第五種是:RetryRule 先按照RoundRobinRule的策略獲取服務,若是獲取服務失敗則在指定時間內會進行重試,獲取可用的服務。

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

第七種是:ZoneAvoidanceRule 默認規則,複合判斷server所在區域的性能和server的可用性選擇服務器。

那麼目前,咱們實現了第一種算法RoundRobinRule 輪詢的方式。

那咱們就來作第二種隨機算法的實現吧。

在microservicecloud-consumer-dept-80工程ConfigBean類下作一個隨機算法的方法

@Bean

public IRule myRule(){

//用從新選擇的隨機算法替代默認的輪詢算法。

return new RandomRule();

}

  

咱們來測試一下:

1.啓動3個eureka集羣配置(microservicecloud-eureka-7001系列)。

2.啓動3個Dept微服務並各自測試經過(microservicecloud-provider-dept-8001系列)。

3.啓動microservicecloud-consumer-dept-80工程進行隨機算法的測試。

請在瀏覽器輸入:http://localhost/consumer/dept/list

隨機的效果我不截圖了,由於用了隨機算法,隨機的效果的體現大家就能體會的到。

那麼其餘的一些算法,我就不一一進行展現了。

Ribbon自定義算法

若是上面的7種算法,都不夠出來業務邏輯,那麼能夠來自定義算法。

1.修改microservicecloud-consumer-dept-80的主啓動類

1).在主啓動類上添加一個註解@RibbonClient()

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

而且官方文檔明確給出了警告:

   這個自定義配置類不能放在@ComponentScan所掃描的當前包下以及子包下,

   不然咱們自定義的這個配置類就會被全部的Ribbon客戶端所共享,也就是說

   咱們達不到特殊化定製的目的了。*/

 

//那麼解決方案是從新在java包下再建一個包名,並把MySelfRule類放入該包內。

@RibbonClient(name="MICROSERVICECLOUD-DEPT",configuration=MySelfRule.class)

請看下面的效果圖:

SpringCloud微服務架構第三篇

編寫MySelfRule自定義配置類的:

@Configuration

public class MySelfRule{

@Bean

public IRule myRule()

 {

return new RandomRule();//Ribbon默認是輪詢,我自定義爲隨機

}

}

  

而後進行測試:

1.啓動3個eureka集羣配置(microservicecloud-eureka-7001系列)。

2.啓動3個Dept微服務並各自測試經過(microservicecloud-provider-dept-8001系列)。

3.啓動microservicecloud-consumer-dept-80工程進行隨機算法的測試。

請在瀏覽器輸入:http://localhost/consumer/dept/get/1

測試的效果我不截圖了,由於用的是自定義隨機算法,隨機的效果的實現大家就能體會的到。

自定義規則深度解析

需求:依舊輪詢策略,可是加上新需求,每一個服務器要求被調用5次。也即之前是每臺機器一次,如今是每臺機器5次。

需求代碼實現: 在MySelfRule類中的myRule方法裏面添加如下內容:

@Configuration

public class MySelfRule {

@Bean

public IRule myRule()

   {

//return new RandomRule();//Ribbon默認是輪詢,自定義爲隨機

return new RandomRule();

}

  

而後在myrule包下建立一個RandomRule_hhf的類,而且添加如下內容:

解析源碼:https://github.com/Netflix/ribbon/blob/master/ribbon-loadbalancer/src/main/java/com/netflix/loadbalancer/RandomRule.java

import com.netflix.client.config.IClientConfig;

import com.netflix.loadbalancer.AbstractLoadBalancerRule;

import com.netflix.loadbalancer.ILoadBalancer;

import com.netflix.loadbalancer.Server;

 

import java.util.List;

import java.util.concurrent.ThreadLocalRandom;

 

//需求是5次,可是微服務只有8001,8002,8003三臺機器

public class RandomRule_hhf extends AbstractLoadBalancerRule {

 

//總共被調用的次數,目前要求每臺被調用5次  

private int total = 0;

//當前提供服務的機器號

private int currentIndex = 0;

 

public Server choose(ILoadBalancer lb, Object key) {

//ILoadBalancer哪種負載均衡算法若是等於null的話就返回null,那麼天然而然,它確定會加載一種算法,因此它不會變成null。

if (lb == null) {

return null;

}

//如今還不知道是哪一個算法來響應server

Server server = null;

 

//若是說server等於null,那麼就看線程是否中斷了,若是被中斷的話就返回null

while (server == null) {

if (Thread.interrupted()) {

return null;

}

//upList的意思就是如今活着的能夠對外提供的機器,而後.get()方法經過

//int index = rand.nextInt(serverCount); 那麼就是隨機到幾就返回第幾的值

List<Server> upList = lb.getReachableServers();

List<Server> allList = lb.getAllServers();

 

//若是serverCount目前有三臺,那麼就不等於0,那麼就是flase。

int serverCount = allList.size();

if (serverCount == 0) {

/*

                * No servers. End regardless of pass, because subsequent passes

                * only get more restrictive.

                */

return null;

}

//這個的意思就是說若是serverCount有三臺,那麼index就獲得了從下標0和1和2數組

// int index = rand.nextInt(serverCount);

// server = upList.get(index);

 

//當第一次total < 5的時候

//當第二次total < 5的時候

//當第五次total < 5的時候(那麼第五次就不小於5),那麼if(total < 5)這段裏面的代碼就不執行了

if(total < 5){

//那麼第一次的server是0號機

//那麼第二次的server也是0號機

 

server = upList.get(currentIndex);

//第一次的總的計數次數是加一個1

//第二次的總的計數次數是再加一個1

total++;

//當第五次total < 5的時候就走else

}else {

//那麼total等於0

total = 0;

//而currentIndex就加一個1

currentIndex++;

//那麼1大於等於upList.size(),目前假設有三臺機器,那麼1就不大於等於upList.size()

//那麼如今就是給0號機給1號機進行服務了,以此類推。。

//可是若是currentIndex等於下標3的時候而且>= upList.size(),但咱們按照數組下標來算的話只               //有0和1和2的下標,那麼當currentIndex等於下標3的時候這樣就是超過第三臺了,那麼                        //currentIndex就從新等於0。以此類推。。

if(currentIndex >= upList.size())

{

currentIndex = 0;

}

}

 

//若是這個server等於null,那麼線程中斷一會,下一輪繼續

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;

}

//若是活着好好的,那麼就返回server回去

if (server.isAlive()) {

return (server);

}

 

// Shouldn't actually happen.. but must be transient or a bug.

server = null;

Thread.yield();

}

 

//返回對應該響應服務是8001,仍是8002仍是8003

return server;

 

}

 

protected int chooseRandomInt(int serverCount) {

return ThreadLocalRandom.current().nextInt(serverCount);

}

 

@Override

public Server choose(Object key) {

return choose(getLoadBalancer(), key);

}

 

@Override

public void initWithNiwsConfig(IClientConfig clientConfig) {

 

 

}

}

那麼咱們的自定義算法定義好了之後,咱們再回到MySelfRule類中添加RandomRule_hhf類進行自定義算法的測試了

在MySelfRule類中添加RandomRule_hhf類:

@Configuration

public class MySelfRule {

@Bean

public IRule myRule()

   {

//return new RandomRule();//Ribbon默認是輪詢,自定義爲隨機

//return new RandomRule();

return new RandomRule_hhf();  //自定義每臺機器5次

}

}

進入測試:

1.啓動3個eureka集羣配置(microservicecloud-eureka-7001系列)。

2.啓動3個Dept微服務並各自測試經過(microservicecloud-provider-dept-8001系列)。

3.啓動microservicecloud-consumer-dept-80工程進行自定義負載均衡算法的測試。

請在瀏覽器輸入:http://localhost/consumer/dept/get/1

測試的效果我不截圖了,只要在頁面刷新5次便可看出效果!!

相關文章
相關標籤/搜索