通常所說的負(fù)載均衡愿题,一般來說都是在服務(wù)器端使用 Ngnix 或 F5 做 Server 的負(fù)載均衡策略堪旧,在 Ribbon 中提到的負(fù)載均衡涩禀,一般來說是指的客戶端負(fù)載均衡
,即 ServiceA 調(diào)用 ServiceB咆繁,有多個 ServiceB 的情況下讳推,由 ServiceA 選擇調(diào)用哪個 ServiceB。
負(fù)載均衡與 Ribbon
負(fù)載均衡(Load Balance)玩般,是一種利用特定方式银觅,將流量分?jǐn)偟蕉鄠€操作單元上的手段,它對系統(tǒng)吞吐量坏为、系統(tǒng)處理能力有著質(zhì)的提升究驴。最常見的負(fù)載均衡分類方式有:軟負(fù)載、硬負(fù)載匀伏,對應(yīng) Ngnix洒忧、F5;集中式負(fù)載均衡够颠、進(jìn)程內(nèi)負(fù)載均衡熙侍。集中式負(fù)載均衡是指位于網(wǎng)絡(luò)和服務(wù)提供者之間,并負(fù)責(zé)把忘了請求轉(zhuǎn)發(fā)到各個提供單位履磨,代表產(chǎn)品有 Ngnix蛉抓、F5;進(jìn)程負(fù)載均衡是指從一個實(shí)例庫選取一個實(shí)例進(jìn)行流量導(dǎo)入剃诅,在微服務(wù)范疇巷送,實(shí)例庫一般是存儲在 Eureka、Consul矛辕、Zookeeper 等注冊中心笑跛,此時的負(fù)載均衡器類似 Ribbon 的 IPC(進(jìn)程間通信)組件付魔,因此進(jìn)程內(nèi)負(fù)載均衡也叫做客戶端負(fù)載均衡。
Ribbon 是一個客戶端負(fù)載均衡器堡牡,賦予了應(yīng)用一些支配 HTTP 與 TCP 行為的能力抒抬,由此可以得知,這里的客戶端負(fù)載均衡也是進(jìn)程內(nèi)負(fù)載均衡的一周晤柄。 Ribbon 在 SpringCloud 生態(tài)內(nèi)的不可缺少的組件,沒有了 Ribbon妖胀,服務(wù)就不能橫向擴(kuò)展芥颈。Feign、Zuul 已經(jīng)集成了 Ribbon赚抡。
示例
Eureka Server 不再贅述爬坑,可以直接使用 spring-cloud-eureka-server-simple
。
Consumer
yml:
spring:
application:
name: spring-cloud-ribbon-consumer
server:
port: 9999
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
instance:
prefer-ip-address: true
instance-id: ${spring.application.name}:${server.port}
配置類:
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
@LoadBalanced
:對 RestTemplate 啟動負(fù)載均衡
Consumer Controller
@RestController
public class ConsumerController {
private final RestTemplate restTemplate;
@Autowired
public ConsumerController(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@GetMapping(value = "/check")
public String checkRibbonProvider(){
return restTemplate.getForObject("http://spring-cloud-ribbon-provider/check", String.class);
}
}
provider
pom 依賴:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
</dependencies>
配置文件:
spring:
application:
name: spring-cloud-ribbon-provider
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
instance:
prefer-ip-address: true
instance-id: ${spring.application.name}:${server.port}
ProviderContr
@RestController
public class ProviderController {
@Value("${server.port}")
private int port;
@GetMapping(value = "/check")
public String providerPort(){
return "Provider Port: " + port;
}
}
驗(yàn)證
分別啟動 Eureka Server涂臣、Consumer盾计、Provider,其中赁遗,Provider 以 mvn 形式啟動贴唇,綁定不同的端口號:
mvn spring-boot:run -Dserver.port=8080
mvn spring-boot:run -Dserver.port=8081
postman 訪問 Consumer
可以看到舰绘,Provider 兩次返回值不一樣,驗(yàn)證了負(fù)載均衡成功。
負(fù)載均衡策略
Ribbon 中提供了 七種
負(fù)載均衡策略
策略類 | 命名 | 描述 |
---|---|---|
RandomRule | 隨機(jī)策略 | 隨機(jī)選擇 Server |
RoundRobinRule | 輪詢策略 | 按照順序循環(huán)選擇 Server |
RetryRule | 重試策略 | 在一個配置時間段內(nèi)贸毕,當(dāng)選擇的 Server 不成功,則一直嘗試選擇一個可用的 Server |
BestAvailableRule | 最低并發(fā)策略 | 逐個考察 Server晶伦,如果 Server 的斷路器被打開而芥,則忽略,在不被忽略的 Server 中選擇并發(fā)連接最低的 Server |
AvailabilityFilteringRule | 可用過濾測試 | 過濾掉一直連接失敗耕姊,并被標(biāo)記未 circuit tripped(即不可用) 的 Server桶唐,過濾掉高并發(fā)的 Server |
ResponseTimeWeightedRule | 響應(yīng)時間加權(quán)策略 | 根據(jù) Server 的響應(yīng)時間分配權(quán)重,響應(yīng)時間越長茉兰,權(quán)重越低尤泽,被選擇到的幾率就越低 |
ZoneAvoidanceRule | 區(qū)域權(quán)衡策略 | 綜合判斷 Server 所在區(qū)域的性能和 Server 的可用性輪詢選擇 Server,并判定一個 AWS Zone 的運(yùn)行性能是否可用邦邦,剔除不可用的 Zone 中的所有 Server |
Ribbon 默認(rèn)的負(fù)載均衡策略是 輪詢策略
安吁。
設(shè)置負(fù)載均衡策略
設(shè)置全局負(fù)載均衡
創(chuàng)建一個聲明式配置,即可實(shí)現(xiàn)全局負(fù)載均衡配置:
@Configuration
public class RibbonConfig {
/**
* 全局負(fù)載均衡配置:隨機(jī)策略
*/
@Bean
public IRule ribbonRule(){
return new RandomRule();
}
}
重啟 Consumer燃辖,訪問測試
基于注解的配置
空注解
聲明一個空注解鬼店,用于使用注解配置 Ribbon 負(fù)載均衡
public @interface RibbonAnnotation {
}
負(fù)載均衡配置類
@Configuration
@RibbonAnnotation
public class RibbonAnnoConfig {
private final IClientConfig clientConfig;
@Autowired(required = false)
public RibbonAnnoConfig(IClientConfig clientConfig) {
this.clientConfig = clientConfig;
}
@Bean
public IRule ribbonRule(IClientConfig clientConfig){
return new RandomRule();
}
}
啟動類
@SpringBootApplication
@EnableDiscoveryClient
@RibbonClient(name = "spring-cloud-ribbon-provider", configuration = RibbonAnnoConfig.class)
@ComponentScan(excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = RibbonAnnotation.class)})
public class SpringCloudRibbonConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudRibbonConsumerApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
@RibbonClient
:針對 spring-cloud-ribbon-provider
服務(wù),使用負(fù)載均衡黔龟,配置類是 configuration
標(biāo)注的類妇智。
@ComponentScan
:讓 Spring 不去掃描被 @RibbonAnnotation
類標(biāo)記的配置類滥玷,因?yàn)槲覀兊呐渲脤蝹€服務(wù)生效,不能應(yīng)用于全局巍棱,如果不排除惑畴,啟動就會報錯
如果需要對多個服務(wù)進(jìn)行配置,可以使用 @RibbonClients
注解
@RibbonClients(value = {
@RibbonClient(name = "spring-cloud-ribbon-provider", configuration = RibbonAnnoConfig.class)
})
重啟 Consumer航徙,驗(yàn)證基于注解的負(fù)載均衡是否成功
基于配置文件的負(fù)載均衡策略
語法:
{instance-id}: # instance-id 即被調(diào)用服務(wù)名稱
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
Ribbon 配置
源碼:https://gitee.com/laiyy0728/spring-cloud/tree/master/spring-cloud-ribbon/spring-cloud-ribbon-config
超時與重試
HTTP 請求難免會出現(xiàn)請求超時如贷,此時對調(diào)用進(jìn)行時限的控制以及在時限之后的重試尤為重要。對于超時重試的配置如下:
{instance-id}: # instance-id 指的是被調(diào)用者的服務(wù)名稱
ribbon:
ConnectTimeout: 30000 # 鏈接超時時間
ReadTimeout: 30000 # 讀超時時間
MaxAutoRetries: 1 # 對第一次請求的服務(wù)的重試次數(shù)
MaxAutoRetriesNextServer: 1 # 要重試的下一個服務(wù)的最大數(shù)量(不包括第一個服務(wù))
OkToRetryOnAllOperations: true # 是否對 連接超時到踏、讀超時杠袱、寫超時 都進(jìn)行重試
Ribbon 饑餓加載
Ribbon 在進(jìn)行負(fù)載均衡時,并不是啟動時就加載上線文窝稿,而是在實(shí)際的請求發(fā)送時楣富,才去請求上下文信息,獲取被調(diào)用者的 ip伴榔、端口纹蝴,這種方式在網(wǎng)絡(luò)環(huán)境較差時,往往會使得第一次引起超時踪少,導(dǎo)致調(diào)用失敗塘安。此時需要指定 Ribbon 客戶端,進(jìn)行饑餓加載
秉馏,即:在啟動時就加載好上下文耙旦。
ribbon:
eager-load:
enabled: true
clients: spring-cloid-ribbon-provider
此時啟動 consumer,會看到控制打印信息如下:
Client: spring-cloid-ribbon-provider instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=spring-cloid-ribbon-provider,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
Using serverListUpdater PollingServerListUpdater
DynamicServerListLoadBalancer for client spring-cloid-ribbon-provider initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=spring-cloid-ribbon-provider,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@79e7188e
可以看到啟動時就加載了 spring-cloid-ribbon-provider
萝究,并綁定了LoadBalancer
Ribbon 常用配置
配置項(xiàng) | 說明 |
---|---|
{instance-id}:ribbon.NFLoadBalancerClassName | 指負(fù)載均衡器類路徑 |
{instance-id}:ribbon:NFLoadBalancerRuleClassName | 指定負(fù)載均衡算法類路徑 |
{instance-id}:ribbom:NFLoadBalancerPingClassName | 指定檢測服務(wù)存活的類路徑 |
{instance-id}:ribbon:NIWSServerListClassName | 指定獲取服務(wù)列表的實(shí)現(xiàn)類路徑 |
{instance-id}:ribbon:NIWSServerListFilterClassName | 指定服務(wù)的 Filter 實(shí)現(xiàn)類路徑 |
Ribbon 脫離 Eureka
默認(rèn)情況下免都,Ribbon 客戶端會從 Eureka Server 讀取服務(wù)注冊信息列表,達(dá)到動態(tài)負(fù)載均衡的功能帆竹。如果 Eureka 是一個提供多人使用的公共注冊中心(如 SpringCloud 中文社區(qū)公益 Eureka:http://eureka.springcloud.cn)绕娘,此時極易產(chǎn)生服務(wù)侵入問題,此時就不能從 Eureka 中讀取服務(wù)列表栽连,而應(yīng)該在 Ribbon 客戶端自行制定源服務(wù)地址
ribbon:
eureka:
enabled: false # Ribbon 脫離 Eureka 使用
{instance-id}:
ribbon:
listOfServers: http://localhost:8888 # 制定源服務(wù)地址