springcloud原始碼閱讀3-Ribbon負載均衡(上)
推薦閱讀:
SpringCloud原始碼閱讀0-SpringCloud必備知識
SpringCloud原始碼閱讀1-EurekaServer原始碼的祕密
SpringCloud原始碼閱讀2-Eureka客戶端的祕密
負載均衡提供客戶端的軟體負載均衡演演算法,理解一種負載均衡的內部結構,對理解其他種類負載均衡意義非凡。
1.核心元件
負載均衡元件包括:
- rule: 負載均衡策略
- ping:心跳檢測
- ServerList: 服務列表
- ServerListUpdater: 服務列表更新
- ServerListFilter: 服務列表過濾
Spring Cloud Ribbon 是對 Netflix Ribbon的封裝。
Spring Cloud Ribbon 預設情況下為Ribbon核心元件提供如下的實現:
2.自定義Ribbon客戶端
對個別微服務,我們想替換其個別元件,怎麼辦?
2.1@RibbonClient
1.使用@RibbonClient 指定替換請求哪些服務的哪些元件。
@Configuration
@RibbonClient(name = "user",configuration = UserConfiguration.class)
public class UserRibbonConfiguration {
}
@Configuration
protected static class UserConfiguration{
@Bean
public IPing ribbonPing() {
return new MyPingUrl();
}
}
複製程式碼
使用MyPingUrl 替換user對應的服務的Ribbon 客戶端 中的IPing 元件。
注意: 需要說明的是自定義的類必須加上@Configuration註解且不能包含在@componentscan註解掃描的包中,否則自定義的類將由所有加@ribbonclient註解的地方共享,若用@ComponentScan(或@SpringBootApplication),應該採取措施來避免它被包含到掃描的範圍中。
2.1屬性配置
2.使用屬性配置替換 從1.2.0版本開始,Spring Cloud Netflix支援自定義Ribbon客戶端配置 支援配置的屬性如下:
- .ribbon.NFLoadBalancerClassName: 配置ILoadBalancer的實現類
- .ribbon.NFLoadBalancerRuleClassName:配置IRule的實現類
- .ribbon.NFLoadBalancerPingClassName: 配置IPing的實現類
- .ribbon.NIWSServerListClassName: 配置ServerList的實現類
- .ribbon.NIWSServerListFilterClassName:配置ServerListFilter的實現類
在這些屬性中定義的類優先於使用@RibbonClient()定義的bean和由Spring Cloud Netflix提供的預設值
例如: application.yml.
users:
ribbon:
NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule
複製程式碼
替換users服務客戶端對應的 ServerList 與LoadBalancerRule 元件
3.自定義所有預設Ribbon
3.1@RibbonClients
當我們想替換所有客戶端的某個元件時,@RibbonClient就顯的力不從心了。
@RibbonClients註解用於覆蓋所有客戶端配置。
@RibbonClients(defaultConfiguration = DefaultRibbonConfig.class)
public class RibbonClientDefaultConfigurationTestsConfig {
public static class BazServiceList extends ConfigurationBasedServerList {
public BazServiceList(IClientConfig config) {
super.initWithNiwsConfig(config);
}
}
}
@Configuration
class DefaultRibbonConfig {
@Bean
public IRule ribbonRule() {
return new BestAvailableRule();
}
@Bean
public IPing ribbonPing() {
return new PingUrl();
}
@Bean
public ServerList<Server> ribbonServerList(IClientConfig config) {
return new RibbonClientDefaultConfigurationTestsConfig.BazServiceList(config);
}
@Bean
public ServerListSubsetFilter serverListFilter() {
ServerListSubsetFilter filter = new ServerListSubsetFilter();
return filter;
}
}
複製程式碼
4.與Eureka一起使用
當與Eureka一同使用時,部分元件被替換:
- DiscoveryEnabledNIWSServerList 替換預設的(ribbonServerList)ConfigurationBasedServerList。DiscoveryEnabledNIWSServerList是由Eureka服務治理維護。
- NIWSDiscoveryPing 替換預設的(IPing )DummyPing。 NIWSDiscoveryPing 也是由Eureka維護的。
- 預設情況下安裝的ServerList是一個DomainExtractingServerList(其實這裡DomainExtractingServerList是對coveryEnabledNIWSServerList的一個代理)。其目的是使物理元資料可用於負載平衡器,而不使用AWS AMI元資料(這是Netflix依賴的)
- Spring Cloud Ribbon預設使用eureka例項元資料中提供的“zone”資訊構建伺服器列表,通過設定eureka.instance.metadatamap.zone的值,可以實現跨區域的例項配置
- 如果沒有配置區域,則可以使用伺服器主機名中的域名作為代理用於區域(前提是設定了標誌approximateZoneFromHostname)
- ServerListFilter:服務例項清單過濾機制,預設採用org.springframework.cloud.netflix.ribbon.ZonePreferenceServerListFilter實現,該策略能夠優先過濾出與請求呼叫方處於同區域的服務例項
如果沒有其他的區域資料來源,則基於客戶端配置(與例項配置相反)進行猜測。我們將eureka.client.availabilityZones(從區域名稱對映到區域列表),並將例項自己的區域的第一個區域(即eureka.client.region,其預設為“us-east-1”為與本機Netflix的相容性)。
如何使用呢:
- RestTemplate新增@LoadBalanced註解,啟動RestTemplate客戶端負載均衡
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
複製程式碼
- 直接使用Ribbon的api來實現負載均衡
public class MyClass {
@Autowired
private LoadBalancerClient loadBalancer;
public void doStuff() {
ServiceInstance instance = loadBalancer.choose("stores");
URI storesUri = URI.create(String.format("http://%s:%s",instance.getHost(),instance.getPort()));
// ... do something with the URI
}
}
複製程式碼
5.脫離Eureka使用
當我們單獨使用Ribbon的時候,可以通過禁止Eureka來使用。
application.yml.
ribbon:
eureka:
enabled: false
複製程式碼
6.快取Ribbon配置
所謂快取Ribbon配置,其實就是飢餓載入(eager-load)模式。 Ribbon在第一次啟動時,因為需要從註冊中心獲取服務列表。一般建立比較慢,針對這種情況。 可以通過飢餓模式來,加速客戶端上下文的建立。
application.yml
ribbon:
eager-load:
enabled: true
clients: client1,client2,client3
複製程式碼
參考: