一、什么是負載均衡?
(1)概念:
在基于微服務架構開發的系統里,為了能夠提升系統應對高并發的能力,開發人員通常會把具有相同業務功能的模塊同時部署到多臺的服務器中,并把訪問業務功能的請求均攤到這些服務器上,這種將請求均攤的做法便叫做負載均衡。
(2)負載均衡分為硬件負載均衡和軟件負載均衡兩種:
- 硬件負載均衡的解決方案就是直接在服務器和外部網絡間安裝負載均衡設備,通常這種設備稱為負載均衡器。由專門的設備完成專門的任務,獨立于操作系統,整體性能得到大量提高,加上多樣化的負載均衡策略,智能化的流量統計,可達到最佳的負載均衡效果。
- 軟件負載均衡的解決方案是指在一臺或多臺服務器相應的操作系統上安裝一個或多個附加軟件來實現負載均衡,如DNS Load Balance,CheckPoint Firewall-1 ConnectControl等,它的優點是基于特定環境,配置簡單,使用靈活,成本低廉,可以滿足一般的負載均衡需求。
那么如何才能實現把訪問業務功能的請求均攤到這些服務器上呢?這里就要用到Ribbon組件了。
二、什么是Ribbon組件?
簡單來說,Ribbon是一個客戶端負載均衡器,提供多種負載均衡策略,以便在客戶端選擇最佳的服務實例。同時也是Spring Cloud Alibaba 體系中負責負載均衡的組件,是一組類庫的集合。
它在Spring Cloud體系中扮演著以下幾個角色:
(1)客戶端負載均衡:
Ribbon在客戶端進行負載均衡,而不是依賴服務器端的負載均衡器。
(2)服務調用:
與Eureka等服務發現組件集成,通過服務名稱來調用不同的服務實例。可以保留服務結點訪問的相關統計信息,這樣可以避免向高延遲或低高故障的節點發送請求。
(3)定制策略:
允許用戶定制負載均衡策略,如隨機策略、輪詢策略等。系統便會根據指定的負載均衡算法,從多個服務節點中選取一個結點出來發送請求得到對應的服務。
三、Ribbon的工作原理:
使用Ribbon實現負載均衡時,基本用法是注入一個RestTemplate,并使用@LoadBalanced注解標注RestTemplate,從而使RestTemplate具備負載均衡的能力。
- 當Spring容器啟動時,使用@LoadBalanced注解修飾的RestTemplate會被添加攔截器,攔截器中使用了LoadBalancerClient處理請求,從而達到負載均衡的目的。
- LoadBalancerClient是Spring Cloud提供的一個非常重要的接口,它繼承ServiceInstanceChooser接口,該接口的實現類是RibbonLoadBalanceClient,它們之間的關系如下圖所示。
- LoadBalancerClient提供的兩個execute()方法用于執行請求, reconstructURI()方法用于重構URL。
- RibbonLoadBalanceClient是LoadBalancerClient的實現類,它用來執行最終的負載均衡請求。其中,RibbonLoadBalanceClient的一個choose()方法用于選擇具體的服務實例,其內部是通過getServer()方法交給ILoadBalancer完成的。
- ILoadBalancer是一個接口,該接口定義了一系列實現負載均衡的方法。ILoadBalancer接口的實現類結果如下圖所示。
?默認情況下,Ribbon使用的負載均衡策略是輪詢,實際上,Ribbon提供了很多負載均衡算法,其中IRule接口就是所有負載均衡算法的父接口。
四、Ribbon在處理負載均衡時的核心組件:
(1)IRule:定義負載均衡規則的接口,不同的實現類提供不同的負載均衡策略。
(2)IPing:用于定期檢查服務實例的健康狀況,確保請求不會發送到不可用的實例。
(3)ServerList:維護可用服務實例的列表,可以從服務注冊中心(如Eureka)動態獲取。
(4)ServerListFilter:用于過濾服務實例列表,確保負載均衡器僅考慮健康和可用的實例。
(5)ILoadBalancer:管理服務實例列表,并根據負載均衡規則選擇一個實例來處理請求。
五、Ribbon負載均衡策略:
- Round Robin Rule(輪詢策略):按順序循環選擇每個服務實例,均衡地分配請求。實現了按照線性輪詢的方式依次選擇服務的功能。
- Weighted Response Time Rule(權重響應時間策略): 根據每個實例的響應時間和權重進行分配,響應時間越快,服務權重越大,被選中的概率越高,獲得的請求也會越多。
- Availability Filtering Rule(可用性過濾策略): 簡單來說就是,過濾掉不可用的或并發請求超過閾值的實例,選擇健康的實例。使用Availability Predicate過濾由于多次訪問故障而處于斷路器跳閘狀態的服務,還有并發的連接數超過閥值的服務,然后對剩余的服務列表進行輪詢。
- Random Rule(隨機策略):該策略實現了從服務清單中隨機選擇一個服務的功能。
-
Least Concurrent Connections(最少并發策略):選擇當前并發請求最少的實例,減輕高負載實例的壓力。
- Best Available Rule(最佳可用策略):用于先過濾掉多次訪問故障而處于斷路跳閘狀態的服務,然后選擇一個并發量最小的服務。
- Client Config Enable Round Robin Rule(客戶端配置啟用輪詢策略):該類是一個抽象類,該類本身沒有實現什么特殊的處理邏輯,我們也不會直接使用該策略,但是通過BestAvailableRule和繼承該策略默認實現了線性輪詢,它的內部定義了一個RoundRobinRule策略,
- Zone Avoidance Rule(區域感知策略):它是PredicateBasedRule的具體實現類,其內部通過使用ZoneAvoidancePredicate和AvailabilityPredicate判斷是否選擇某一個服務,前者用于判斷服務所在區域的性能是否可用,后者用于過濾掉連接數過多的服務。
- Predicate Based Rule:繼承了ClientConfigEnableRoundRobinRule,其內部會先通過chooseRoundRobinAfterFiltering()方法篩選服務清單,然后以線性輪詢的方式從過濾后的服務清單中選擇一個服務。
六、實練操作:
Ribbon實現負載均衡:
(1)創建名為ServiceProvider1的服務項目:
-
添加依賴到pom文件.
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency> </dependencies>
-
在resources目錄編寫application.properties配置文件.
nacos.discovery.server-addr=127.0.0.1:8848 spring.application.name=ServiceProvider server.port=1111
-
編寫啟動類,加入注解,說明本項目所包含的服務方法是需要注冊到Nacos注冊中心.
@EnableDiscoveryClient @SpringBootApplication public class SpringBootApp {public static void main(String[] args) {SpringApplication.run(SpringBootApp.class, args);} }
-
編寫Controller.java控制類,編寫對外提供服務方法.
@RestController public class Controller {@RequestMapping("/callServiceByRibbon")public String callServiceByRibbon(){return "return in Service1.";} }
(2)創建名為ServiceProvider2的服務項目:
-
修改pom文件.
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency> </dependencies>
-
修改application.properties配置文件.
nacos.discovery.server-addr=127.0.0.1:8848 spring.application.name=ServiceProvider server.port=2222
-
修改控制類的方法.
@RestController public class Controller {@RequestMapping("/callServiceByRibbon")public String callServiceByRibbon(){return "return in Service2.";} }
(3)創建名為ServiceWithRibbon的maven項目:
-
添加依賴到pom文件.
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-ribbon</artifactId></dependency> </dependencies>
-
在啟動類添加注解.
@EnableDiscoveryClient @SpringBootApplication public class SpringBootApp {public static void main(String[] args) {SpringApplication.run(SpringBootApp.class, args);}@LoadBalanced@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}}
-
修改配置文件.
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 server.port=8080 spring.application.name=ServiceWithRibbon ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RoundRibbonRule
-
編寫controller控制類.
@RestController public class Controller {@Resourceprivate RestTemplate restTemplate;@RequestMapping("/callFuncByRibbon")public String callFuncByRibbon(){return restTemplate.getForObject("http://ServiceProvider/callServiceByRibbon", String.class);} }