1.Ribbon目前也進入維護模式
1.1 Ribbon介紹
Spring Cloud Ribbon是基於Netflix Ribbon實現的一套客戶端負載均衡的工具。
簡單的說,Ribbon是Netflix釋出的開源專案,主要功能是提供客戶端的軟體負載均衡演算法和服務呼叫。Ribbon客戶端元件提供一系列完善的配置項如連線超時,重試等。簡單的說,就是在配置檔案中列出Load Balancer(簡稱LB)後面所有的機器,Ribbon會自動的幫助你基於某種規則(如簡單輪詢,隨機連線等)去連線這些機器。我們很容易使用Ribbon實現自定義的負載均衡演算法。
https://github.com/Netflix/ribbon
1.2 Ribbon替代方案
spring-cloud-loadbalancer
2.spring-cloud-loadbalancer概述
2.1 官網
2.2 是什麼
LB負載均衡(Load Balance)是什麼
簡單的說就是將使用者的請求平攤的分配到多個服務上,從而達到系統的HA(高可用)
,常見的負載均衡有軟體Nginx
,LVS
,硬體F5
等
spring-cloud-starter-loadbalancer元件是什麼
Spring Cloud LoadBalancer是由SpringCloud官方提供的一個開源的、簡單易用的客戶端負載均衡器,它包含在SpringCloud-commons中用它來替換了以前的Ribbon元件。相比較於Ribbon,SpringCloud LoadBalancer不僅能夠支援RestTemplate,還支援WebClient(WeClient是Spring Web Flux中提供的功能,可以實現響應式非同步請求)。
https://docs.spring.io/spring-cloud-commons/reference/spring-cloud-commons/loadbalancer.html
2.3 面試題
loadbalancer本地負載均衡客戶端 VS Nginx服務端負載均衡區別
Nginx是伺服器負載均衡,客戶端所有請求都會交給nginx,然後由nginx實現轉發請求,即負載均衡是由服務端實現的。
loadbalancer本地負載均衡,在呼叫微服務介面時候,會在註冊中心上獲取註冊資訊服務列表之後快取到JVM本地,從而在本地實現RPC遠端服務呼叫技術。
個人理解,客戶端負載均衡,是由客戶端,選擇向那臺機器發起請求,並獲得響應。而服務端負載均衡,是由伺服器端(nginx),決定某個請求,由那臺機器處理,然後響應給客戶端。
3.spring-cloud-loadbalancer負載均衡解析
3.1 理論
LoadBalancer 在工作時分成兩步:
第一步,先選擇ConsulServer從服務端查詢並拉取服務列表,知道了它有多個服務(上圖3個服務),這3個實現是完全一樣的,
預設輪詢呼叫誰都可以正常執行。類似生活中求醫掛號,某個科室今日出診的全部醫生,客戶端你自己選一個。
第二步,按照指定的負載均衡策略從server取到的服務註冊列表中由客戶端自己選擇一個地址,所以LoadBalancer是一個客戶端的負載均衡器。
3.2 實操
3.2.1 官網參考如何正確使用
https://docs.spring.io/spring-cloud-commons/reference/spring-cloud-commons/loadbalancer.html
3.2.2 按照8001複製新建8002
略
3.2.3 啟動Consul,然後啟動8001和8002
啟動Consul
consul agent -dev
獲取在consul中配置的測試資訊,透過8001或8002介面
略
bug
在consul中的配置重啟後,消失了
3.2.4 Consul資料持久化配置並註冊為Window服務
1.在consul.exe的同級目錄下,新建mydata資料夾
2.新建consul_start.bat檔案
@echo.Consul Start......
@echo off
@sc create Consul binpath= "D:\Develop\consul\consul.exe agent -server -ui -bind=127.0.0.1 -client=0.0.0.0 -bootstrap-expect 1 -data-dir D:\Develop\consul\mydata "
@net start Consul
@sc config Consul start= AUTO
@echo.Consul start is OK......success
@pause
3.管理員許可權開啟
4.啟動結果
5.win後臺
會多出consul服務
6.後續consul的配置資料會儲存到mydata資料夾
3.2.5 修改Order模組
1.引入依賴
<!--loadbalancer-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
2.新增介面
@GetMapping(value = "/consumer/pay/get/info")
public String getInfoByConsul() {
return restTemplate.getForObject(PAYMENT_SRV_URL + "/pay/get/info", String.class);
}
3.consul服務
4.測試
http://localhost:8080/consumer/pay/get/info
訪問改介面,可見交替訪問8001和8002
3.3 小總結
3.3.1 使用DiscoveryClient動態獲取上線的服務列表
3.3.2 訂單模組新增程式碼
@Resource
private DiscoveryClient discoveryClient;
@GetMapping("/discovery")
public String discovery() {
//獲取所有的consul中的服務名
List<String> services = discoveryClient.getServices();
for (String element : services) {
System.out.println(element);
}
System.out.println("===================================");
//獲取key服務的所有服務例項
List<ServiceInstance> instances = discoveryClient.getInstances("cloud-payment-service");
for (ServiceInstance element : instances) {
//服務例項名 + 服務主機名 + 服務埠號 + 服務url
System.out.println(element.getServiceId() + "\t" + element.getHost() + "\t" + element.getPort() + "\t" + element.getUri());
}
return instances.get(0).getServiceId() + ":" + instances.get(0).getPort();
}
輸出資訊
cloud-consumer-order
cloud-payment-service
consul
===================================
cloud-payment-service x 8001 http://x:8001 x是主機名
cloud-payment-service x 8002 http://x:8002
3.3.3 負載均衡原理小總結
負載均衡演算法:rest介面第幾次請求數 % 伺服器叢集總數量 = 實際呼叫伺服器位置下標 ,每次服務重啟動後rest介面計數從1開始。
List<ServiceInstance> instances = discoveryClient.getInstances("cloud-payment-service");
//如
List [0] 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 =0 對應下標位置為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
如此類推......
4.負載均衡演算法原理
4.1 預設演算法,有幾種
4.1.1 官網
https://docs.spring.io/spring-cloud-commons/reference/spring-cloud-commons/loadbalancer.html#switching-between-the-load-balancing-algorithms
4.1.2 預設兩種
輪詢
public class RoundRobinLoadBalancer implements ReactorServiceInstanceLoadBalancer
隨機
public class RoundRobinLoadBalancer implements ReactorServiceInstanceLoadBalancer
原始碼
略,見org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer
介面
4.2 演算法切換
@LoadBalancerClient(value = "cloud-payment-service",configuration = RestTemplateConfig.class)
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
@Bean
ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RandomLoadBalancer(loadBalancerClientFactory
.getLazyProvider(name, ServiceInstanceListSupplier.class),
name);
}
}
The classes you pass as
@LoadBalancerClient
or@LoadBalancerClients
configuration arguments should either not be annotated with@Configuration
or be outside component scan scope.在RestTemplateConfig的類上,有@LoadBalancerClient或者@LoadBalancerClients,就不該在使用@Configuration註解了,包含了。
Configuration(proxyBeanMethods = false)
@Import(LoadBalancerClientConfigurationRegistrar.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LoadBalancerClient
@Configuration(proxyBeanMethods = false)
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
@Documented
@Import(LoadBalancerClientConfigurationRegistrar.class)
public @interface LoadBalancerClients
只是為了記錄自己的學習歷程,且本人水平有限,不對之處,請指正。