Ribbon介紹
Spring Cloud Ribbon是基於Netflix Ribbon實現的一套客戶端負載均衡的工具
Ribbon是Netflix發布的開源項目,主要功能是提供客戶端的軟件負載均衡算法和服務調用。Ribbon客戶端組件提供一系列完善的配置項如連接超時、重試等。簡單的說,就是在配置文件中列出Load Balance(簡稱LB)后面所有的機器,Ribbon會自動的幫組你基於某種規則(如簡單輪詢,隨機連接等)去連接這些機器,我們很容易使用Ribbon實現自定義的負載均衡算法
LB負載均衡(Load Balance)
簡單的說就是將用戶的請求平攤到分配到多個服務上,從而達到系統的HA(高可用)。
常見的負載均衡有軟件Nginx、LVS、硬件FS等
Ribbon本地負載均衡客戶端 VS Nginx服務端負載均衡區別
Nginx是服務器負載均衡,客戶端所有請求都會教給Nginx,然后由nginx實現轉發請求,即負載均衡是由服務端實現的
Ribbon本地負載均衡,在調用微服務接口時候,會在注冊中心上獲取注冊信息服務列表之后緩存到JVM本地,從而本地實現RPC遠程調用技術
官網:https://github.com/Netflix/ribbon
Ribbon使用
1、搭建項目、參考【SpringCloud】服務提供者集群與服務發現Discovery(三) 的示例
采用Eureka作為注冊中心,且有2個服務提供者
架構如下:
2、Ribbon依賴,依賴如下:
1 <dependency> 2 <groupId>org.springframework.cloud</groupId> 3 <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> 4 <version>2.2.2.RELEASE</version> 5 <scope>compile</scope> 6 </dependency>
通過查看示例項目,調用者order項目依賴,發現在Eureka依賴中,默認含有依賴Ribbon的依賴
3、查看RibbonClientConfiguration.java,Ribbon自動裝載類。
1 @Configuration(proxyBeanMethods = false) 2 @EnableConfigurationProperties 3 @Import({ HttpClientConfiguration.class, OkHttpRibbonConfiguration.class, 4 RestClientRibbonConfiguration.class, HttpClientRibbonConfiguration.class }) 5 public class RibbonClientConfiguration { 6 7 ... 8 9 // 自動注入IRule接口用來代表負責負載均衡的策略 10 @Bean 11 @ConditionalOnMissingBean 12 public IRule ribbonRule(IClientConfig config) { 13 if (this.propertiesFactory.isSet(IRule.class, name)) { 14 return this.propertiesFactory.get(IRule.class, config, name); 15 } 16 ZoneAvoidanceRule rule = new ZoneAvoidanceRule(); 17 rule.initWithNiwsConfig(config); 18 return rule; 19 } 20 21 // 自動注入ILoadBalance接口用來代表負責均衡的操作 22 @Bean 23 @ConditionalOnMissingBean 24 public ILoadBalancer ribbonLoadBalancer(IClientConfig config, 25 ServerList<Server> serverList, ServerListFilter<Server> serverListFilter, 26 IRule rule, IPing ping, ServerListUpdater serverListUpdater) { 27 if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) { 28 return this.propertiesFactory.get(ILoadBalancer.class, config, name); 29 } 30 return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList, 31 serverListFilter, serverListUpdater); 32 } 33 34 ... 35 }
其中自動注入IRule接口用來代表負責負載均衡的策略(默認策略:ZoneAvoidanceRule),和自動注入ILoadBalance接口用來代表負責均衡的操作(默認均衡:ZoneAwareLoadBalancer)
4、查看ILoadBalance接口(負責均衡的操作)
繼承關系如下:
內容如下:
1 public interface ILoadBalancer { 2 3 public void addServers(List<Server> newServers); 4 5 // 根據key選擇一個服務 6 public Server chooseServer(Object key); 7 8 public void markServerDown(Server server); 9 10 public List<Server> getServerList(boolean availableOnly); 11 12 public List<Server> getReachableServers(); 13 14 public List<Server> getAllServers(); 15 }
5、查看IRule接口(負責均衡的策略)
實現關系:
內容如下:
1 public interface IRule{ 2 3 // 根據key選擇一個服務 4 public Server choose(Object key); 5 6 public void setLoadBalancer(ILoadBalancer lb); 7 8 public ILoadBalancer getLoadBalancer(); 9 }
通過查看實例類,可以看到具體的實現了,可以知道負責均衡的策略
6、Ribbon工作原理
查看LoadBalancerAutoConfiguration自動配置類
1 @Configuration(proxyBeanMethods = false) 2 @ConditionalOnClass(RestTemplate.class) 3 @ConditionalOnBean(LoadBalancerClient.class) 4 @EnableConfigurationProperties(LoadBalancerRetryProperties.class) 5 public class LoadBalancerAutoConfiguration { 6 7 8 ... 9 10 11 @Configuration(proxyBeanMethods = false) 12 @ConditionalOnClass(RetryTemplate.class) 13 public static class RetryInterceptorAutoConfiguration { 14 15 @Bean 16 @ConditionalOnMissingBean 17 public RetryLoadBalancerInterceptor ribbonInterceptor( 18 LoadBalancerClient loadBalancerClient, 19 LoadBalancerRetryProperties properties, 20 LoadBalancerRequestFactory requestFactory, 21 LoadBalancedRetryFactory loadBalancedRetryFactory) { 22 return new RetryLoadBalancerInterceptor(loadBalancerClient, properties, 23 requestFactory, loadBalancedRetryFactory); 24 } 25 26 // RestTemplate定制器 27 @Bean 28 @ConditionalOnMissingBean 29 public RestTemplateCustomizer restTemplateCustomizer( 30 final RetryLoadBalancerInterceptor loadBalancerInterceptor) { 31 return restTemplate -> { 32 List<ClientHttpRequestInterceptor> list = new ArrayList<>( 33 restTemplate.getInterceptors()); 34 list.add(loadBalancerInterceptor); 35 // 給restTemplate,設置攔截器 36 restTemplate.setInterceptors(list); 37 }; 38 } 39 40 } 41 42 }
其中自動配置了一個LoadBalancerInterceptor,LoadBalancerInterceptor是個ClientHttpRequestInterceptor客戶端請求攔截器。它的作用是在客戶端發起請求之前攔截,進而實現客戶端的負載均衡。
以下是RestTemplate注入,加@LoadBalanced,的配置方法
1 @Configuration 2 public class AppConfig { 3 4 /** 5 * 注入restTemplate,請用請求rest接口 6 * @return 7 */ 8 @Bean 9 // 標注此注解后,RestTemplate就具有了客戶端負載均衡能力 10 // 負載均衡技術依賴於的是Ribbon組件~ 11 // RestTemplate都塞入一個loadBalancerInterceptor 讓其具備有負載均衡的能力 12 @LoadBalanced 13 public RestTemplate restTemplate(){ 14 return new RestTemplate(); 15 } 16 }
7、測試Ribbon,是否根據對於的負責均衡的策略,實現負載
1)調試模式啟動項目,使用地址:http://localhost:8000/consumer/payment/get/1,進行訪問
返回內容為提供者2個節點分別交替返回的,到達負載均衡目的。
2)在ZoneAvoidanceRule類中添加斷點,通過運行程序,可以看到程序會運行到ZoneAvoidanceRule類中。
自帶負載均衡規則說明
策略名 | 策略聲明 | 策略描述 | 實現說明 |
BestAvailableRule | public class BestAvailableRule extends ClientConfigEnabledRoundRobinRule | 選擇一個最小的並發請求的server | 逐個考察Server,如果Server被tripped了,則忽略,在選擇其中ActiveRequestsCount最小的server |
AvailabilityFilteringRule | public class AvailabilityFilteringRule extends PredicateBasedRule | 過濾掉那些因為一直連接失敗的被標記為circuit tripped的后端server,並過濾掉那些高並發的的后端server(active connections 超過配置的閾值) | 使用一個AvailabilityPredicate來包含過濾server的邏輯,其實就就是檢查status里記錄的各個server的運行狀態 |
WeightedResponseTimeRule | public class WeightedResponseTimeRule extends RoundRobinRule | 根據相應時間分配一個weight,相應時間越長,weight越小,被選中的可能性越低。 | 一個后台線程定期的從status里面讀取評價響應時間,為每個server計算一個weight。Weight的計算也比較簡單responsetime 減去每個server自己平均的responsetime是server的權重。當剛開始運行,沒有形成statas時,使用roubine策略選擇server。 |
RetryRule | public class RetryRule extends AbstractLoadBalancerRule | 對選定的負載均衡策略機上重試機制。 | 在一個配置時間段內當選擇server不成功,則一直嘗試使用subRule的方式選擇一個可用的server |
RoundRobinRule | public class RoundRobinRule extends AbstractLoadBalancerRule | roundRobin方式輪詢選擇server | 輪詢index,選擇index對應位置的server |
RandomRule | public class RandomRule extends AbstractLoadBalancerRule | 隨機選擇一個server | 在index上隨機,選擇index對應位置的server |
ZoneAvoidanceRule | public class ZoneAvoidanceRule extends PredicateBasedRule | 復合判斷server所在區域的性能和server的可用性選擇server | 使用ZoneAvoidancePredicate和AvailabilityPredicate來判斷是否選擇某個server,前一個判斷判定一個zone的運行性能是否可用,剔除不可用的zone(的所有server),AvailabilityPredicate用於過濾掉連接數過多的Server。 |