1. 程式人生 > >SpringCloud 服務負載均衡和呼叫 Ribbon、OpenFeign

SpringCloud 服務負載均衡和呼叫 Ribbon、OpenFeign

# 1、Ribbon Spring Cloud Ribbon是基於Netflix Ribbon實現的—套客戶端―負載均衡的工具。 簡單的說,Ribbon是Netlix釋出的開源專案,主要功能是提供客戶端的軟體負載均衡演算法和服務呼叫。Ribbon客戶端元件提供一系列完善的配置項如連線超時,重試等。簡單的說,就是在配置檔案中列出Load Balancer(簡稱LB)後面所有的機器,Ribbon會自動的幫助你基於某種規則(如簡單輪詢,隨機連線等)去連線這些機器。我們很容易使用Ribbon實現自定義的負載均衡演算法。 目前Ribbon和Eureka進入到維護模式。停更不停用 > 負載均衡: **LB負載均衡(Load Balance)是什麼?** 簡單的說就是將使用者的請求平攤的分配到多個服務上,從而達到系統的HA(高可用)。1 常見的負載均衡有軟體Nginx,LVS,硬體F5等。 **Ribbon本地負載均衡客戶端VS Nginx服務端負載均衡區別** Nginx是伺服器負載均衡,客戶端所有請求都會交給nginx,然後由nginx實現轉發請求。即負載均衡是由服務端實現的。 Ribbon本地負載均衡,在呼叫微服務介面時候,會在註冊中心上獲取註冊資訊服務列表之後快取到VM本地,從而在本地實現RPC遠 程服務呼叫技術。 1、集中式LB 即在服務的消費方和提供方之間使用獨立的LB設施(可以是硬體,如F5,也可以是軟體,如nginx)由該設施負責把訪問請求通過某種策咯轉發至服務的提供方; 2、程序內LB 將LB邏輯整合到消費方,消費方從服務註冊中心獲知有哪些地址可用,然後自己再從這些地址中選擇出一個合適的伺服器。Ribbon就屬於程序內LB,它只是一個類庫,集成於消費方程序,消費方通過它來獲取到服務提供方的地址。 負載均衡 +RestTemplate 配合使用 > 架構 總結:Ribbon其實就是一個軟負載均衡的客戶端元件,他可以和其他所需請求的客戶端結合使用,和eureka結合只是其中的一個例項. ![image-20200822132451805](https://img2020.cnblogs.com/blog/1557466/202009/1557466-20200904153047847-1993260186.png) Ribbon在工作時分成兩步 第一步先選擇EurekaServer ,它優先選擇在同一個區域內負載較少的server. 第二步再根據使用者指定的策略,在從server取到的服務註冊列表中選擇一個地址。 其中Ribbon提供了多種策略:比如輪詢、隨機和根據響應時間加權。 ``` pom 依賴 spring-cloud-starter-netflix-eureka-client 自身 就集成了 ribbon 。 ``` RestTemplate說明: ![image-20200822133134902](https://img2020.cnblogs.com/blog/1557466/202009/1557466-20200904153047598-1476550294.png) > Ribbon負載均衡規則 繼承結構 ![image-20200822134205708](https://img2020.cnblogs.com/blog/1557466/202009/1557466-20200904153047403-1220822072.png) 自帶7種: ![image-20200822134245453](https://img2020.cnblogs.com/blog/1557466/202009/1557466-20200904153047194-2122039660.png) 如何使用?負載均衡策略替換。 官方文件明確給出了**警告**: 這個自定義配置類不能放在@ComponentScan所掃描的當前包下以及子包下, 否則我們自定義的這個配置類就會被所有的Ribbon客戶端所共享,達不到特殊化定製的目的了。 增加rule配置類 ```java 包路徑: com.fage.rules @Configuration public class MyRibbonRule { @Bean public IRule randomRule() { return new RandomRule(); } } ``` boot啟動類增加註解 ``` @RibbonClient(name = "cloud-payment-service", configuration = {MyRibbonRule.class}) ``` > 負載均衡輪詢演算法原理 負載均衡演算法: rest介面第幾次請求數%伺服器叢集總數量=實際呼叫伺服器位置下標,每次服務重啟動後rest介面計數從1開始。 List instances = discoveryClient.getlnstances(CLOUD-PAYMENT-SERVICE"); 如:List [o] instances = 127.0.0.1:8002 List [1] instances = 127.0.0.1:8001 8001+8002組合成為叢集,它們共計2臺機器,叢集總數為2,按照輪詢演算法原理: 當總請求數為1時:1%2=1對應下標位置為1,則獲得服務地址為127.0.0.1:8001 當總請求數位2時: 2%2=O對應下標位置為0,則獲得服務地址為127.0.0.1:8002 當總請求數位3時:3%2=1對應下標位置為1,則獲得服務地址為127.0.0.1:8001 當總請求數位4時:4%2=0對應下標位置為0,則獲得服務地址為127.0.0.1:8002 如此類推...... 原始碼: 從0開始取餘獲取提供者服務。 **內部使用cas+自旋鎖。** > 手寫一個負載均衡演算法,實現輪詢 1、服務提供者增加介面 ```java @GetMapping("/payment/loadBalanced") public CommonResult getLoadBalanced() { return new CommonResult<>(200, "呼叫成功", port); } ``` 2、服務消費者改造 將 @LoadBalanced 註解去掉 增加MyLoadBalanced介面,只有一個方法ServiceInstance instance(List serviceInstances);用於得到當前演算法後要使用的例項物件。 實現類MyLib原始碼如下: ```java @Component @Slf4j public class MyLib implements MyLoadBalanced { private final AtomicInteger nextServerCyclicCounter = new AtomicInteger(0); public final int getAndIncrement() { // 方案 1 cas // int current; // int next; // do { // current = this.nextServerCyclicCounter.get(); // next = current >= 2147483647 ? 0 : current + 1; // } while (!this.nextServerCyclicCounter.compareAndSet(current, next)); // log.info("**********第幾次訪問,次數next:" + next); // return next; // 方案 2 JUC 提供的 自增方法 log.info("**********第幾次訪問,次數next:" + nextServerCyclicCounter.getAndIncrement()); return nextServerCyclicCounter.get(); } /** * 負載均衡演算法:rest介面第幾次請求書 % 伺服器叢集總數量 = 實際呼叫伺服器位置下標,每次服務重啟動後rest介面計數從1開始 * * @param serviceInstances 叢集中的 服務 例項 * @return 叢集中的一個例項 */ @Override public ServiceInstance instance(List serviceInstances) { return serviceInstances.get(getAndIncrement() % serviceInstances.size()); } } ``` 3、改造消費者呼叫方法 ```java @GetMapping(value = "/consumer/payment/loadBalanced") public CommonResult getLoadBalanced() { ServiceInstance instance = myLoadBalanced.instance(discoveryClient.getInstances(PAYMENT_URL.split("//")[1])); return restTemplate.getForObject(instance.getUri()+"/payment/loadBalanced", CommonResult.class); } ``` # 2、OpenFeign **只需要一個介面並在介面上添加註解即可。** feign不再更新,直接學習openFeign。都是用於負載均衡。 Feign是一個宣告式WebService客戶端。使用Feign能讓編寫Web Service客戶端更加簡單。 它的使用方法是定義一個服務介面然後在上面添加註解。Feign也支援可拔括式的編碼羆和解碼器。Spring Cloud對Feign進行了封裝,使其支援了Spring MVC標準註解和HttpMessageConverters。Feign和ribbon組合使用以支援負載均衡。 > Feign能幹什麼 Feign旨在使編寫Java Http客戶端變得更容易。 前面在使用Ribbon+RestTemplate時,利用RestTemplate對http請求的封裝處理,形成了一套模版化的呼叫方法。但是在實際開發 中,由於對服務依賴的呼叫可能不止一處,往往一個介面會被多處呼叫,所以通常都會針對每個微服務自行封裝一些客戶端類來包裝 這些依賴服務的呼叫。所以,Feign在此基礎上做了進一步封裝,由他來幫助我們定義和實現依賴服務介面的定義。在Feign的實現下 ,我們只需建立一個介面並使用註解的方式來配置它(以前是Dao介面上面標註Mapper註解,現在是一個微服務介面上面標註一個 Feign註解即可),即可完成對服務提供方的介面繫結,簡化了使用Spring cloud Ribbon時,自動封裝服務呼叫客戶端的開發量。 > Feign集成了Ribbon 利用Ribbon維護了Payment的服務列表資訊,並且通過輪詢實現了客戶端的負載均衡。而與Ribbon不同的是,通過feign只需要定義 服務繫結介面且以宣告式的方法,優雅而簡單的實現了服務呼叫 > Feign和openFeign的區別 ![image-20200825164601061](https://img2020.cnblogs.com/blog/1557466/202009/1557466-20200904153046880-1761915737.png) > 搭建openFeign模組 cloud-consumer-openfeign-order80 ![image-20200825170608310](https://img2020.cnblogs.com/blog/1557466/202009/1557466-20200904153046447-618999062.png) ```pom org.springframework.cloud
spring-cloud-starter-openfeign
``` 啟動類增加註解@EnableFeignClients 增加feign介面 ```java @Component @FeignClient(value = "cloud-payment-service") public interface OpenFeignService { @GetMapping("/payment/loadBalanced") public CommonResult getLoadBalanced(); } ``` 增加controller ```java @RestController @Slf4j public class OrderController implements OpenFeignService { @Resource OpenFeignService openFeignService; @Override @GetMapping("/consumer/payment/loadBalanced") public CommonResult getLoadBalanced() { return openFeignService.getLoadBalanced(); } } ``` 註冊中心使用eureka。跟之前一樣。 >**OpenFeign超時控制** OpenFeign預設等待時間為1ms。 設定超時時間 ![image-20200825172459483](https://img2020.cnblogs.com/blog/1557466/202009/1557466-20200904153045828-632946743.png) ```yml ###設定 超時時間 方式 1 # 設定 feign客戶端超時時間 ( openFeign 預設支援 ribbon ) ribbon: # 指的是建立連線所用的時間,適用於網路狀況正常的情況下,倆端連線所用的時間 單位是秒 ReadTimeout: 6000 # 指的是建立連線後從伺服器讀取到可用資源的時間 ConnectTimeout: 5000 ###設定 超時時間 方式 2 #feign: # client: # config: # default: # connectTimeout: 5000 # readTimeout: 6000 # loggerLevel: full ``` >**OpenFeign日誌增強** Feign提供了日誌列印功能,我們可以通過配置來調整日誌級別,從而瞭解Feign中Http請求的細節。 說白了就是對Feign介面的呼叫情況進行監控和輸出 日誌級別: NONE:預設的,不顯示任何日誌; BASIC:僅記錄請求方法、URL、響應狀態碼及執行時間; HEADERS:除了BASIC中定義的資訊之外,還有請求和響應的頭資訊; FULL:除HEADERS中定義的資訊之外,還有請求和響應的正文及元資料。 配置日誌bean: ```java @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } ``` yml開啟日誌 ![image-20200825174833260](https://img2020.cnblogs.com/blog/1557466/202009/1557466-20200904153045408-792793172.png) ```pom # 設定 feign客戶端超時時間 ( openFeign 預設支援 ribbon ) ribbon: # 指的是簡歷連線所用的時間,適用於網路狀況正常的情況下,倆端連線所用的時間 單位是秒 ReadTimeout: 8000 # 指的是建立連線後從伺服器讀取到可用資源的時間 ConnectTimeout: 6000 # 開啟 feign 日誌列印 logging: level: ## feign 日誌 以什麼級別 監控那個介面 com.fage.springcloud.feign.OpenFeignService: debug ``` 結果: ```log 2020-08-25 17:55:26.667 DEBUG 56624 --- [p-nio-80-exec-2] c.f.springcloud.feign.OpenFeignService : [OpenFeignService#getLoadBalanced] ---> GET http://cloud-payment-service/payment/loadBalanced HTTP/1.1 2020-08-25 17:55:26.667 DEBUG 56624 --- [p-nio-80-exec-2] c.f.springcloud.feign.OpenFeignService : [OpenFeignService#getLoadBalanced] ---> END HTTP (0-byte body) 2020-08-25 17:55:26.682 DEBUG 56624 --- [p-nio-80-exec-2] c.f.springcloud.feign.OpenFeignService : [OpenFeignService#getLoadBalanced] <--- HTTP/1.1 200 (14ms) 2020-08-25 17:55:26.682 DEBUG 56624 --- [p-nio-80-exec-2] c.f.springcloud.feign.OpenFeignService : [OpenFeignService#getLoadBalanced] connection: keep-alive 2020-08-25 17:55:26.682 DEBUG 56624 --- [p-nio-80-exec-2] c.f.springcloud.feign.OpenFeignService : [OpenFeignService#getLoadBalanced] content-type: application/json 2020-08-25 17:55:26.682 DEBUG 56624 --- [p-nio-80-exec-2] c.f.springcloud.feign.OpenFeignService : [OpenFeignService#getLoadBalanced] date: Tue, 25 Aug 2020 09:55:26 GMT 2020-08-25 17:55:26.682 DEBUG 56624 --- [p-nio-80-exec-2] c.f.springcloud.feign.OpenFeignService : [OpenFeignService#getLoadBalanced] keep-alive: timeout=60 2020-08-25 17:55:26.682 DEBUG 56624 --- [p-nio-80-exec-2] c.f.springcloud.feign.OpenFeignService : [OpenFeignService#getLoadBalanced] transfer-encoding: chunked 2020-08-25 17:55:26.682 DEBUG 56624 --- [p-nio-80-exec-2] c.f.springcloud.feign.OpenFeignService : [OpenFeignService#getLoadBalanced] 2020-08-25 17:55:26.683 DEBUG 56624 --- [p-nio-80-exec-2] c.f.springcloud.feign.OpenFeignService : [OpenFeignService#getLoadBalanced] {"code":200,"message":"呼叫成功","data":"8001"} 2020-08-25 17:55:26.683 DEBUG 56624 --- [p-nio-80-exec-2] c.f.springcloud.feign.OpenFeignService : [OpenFeignService#getLoadBalanced] <--- END HTTP (51-byte body) ``` > **公眾號**:**發哥講** > > 這是一個稍偏基礎和偏技術的公眾號,甚至其中包括一些可能閱讀量很低的包含程式碼的技術文,不知道你是不是喜歡,期待你的關注。 > > 程式碼分享 > > https://gitee.com/naimaohome > > 微信公眾號 點選關於我,加入QQ群,即可獲取到程式碼以及高階進階視訊和電子書!! ![img](https://mmbiz.qpic.cn/mmbiz_jpg/Ific2yZib8JTag5GL8hvicT4iaY1OFiaYVQNjNo0M6Jzr4WaicqfN9cZFBM9jg0YHVF4E5uiat8dYQXkMlMxT4icJELWZQ/640?wx_fmt=jpeg) 如果你覺得文章還不錯,就請點選右上角選擇傳送給朋友或者轉發到朋友圈~ **● 掃碼關注我們** **據說看到好文章不推薦的人,伺服器容易宕機!** **本文版權歸 [發哥講](https://www.cnblogs.com/naimao/) 和 [部落格園](http://www.cnblogs.com/) 共有,原創文章,未經允許不得轉載,否則保留追究法律責任的權