Ribbon 客户端负载均衡
文章目錄
- 零、懶漢式改為餓漢式
- 一、基于配置文件
- 二、基于Bean配置
- 三、自定義規則
- 1 權重優先調用
- 2 集群優先調用
- 3 元數據優先調用
零、懶漢式改為餓漢式
【consumer-springboot-80子模塊】
Ribbon默認使用懶漢式加載服務列表,更改為懶漢式
application.yml
一、基于配置文件
2、【consumer-springboot-80子模塊】
按照SpringCloud 所給出的官方文檔來講,所有Ribbon相關的負載均衡策略全部都可以在application.yml配置文件之中進行定義,對于定義的模型采用的是“ServiceID.ribbon.類型=處理子類”,本次開發之中所使用的“dept.provider”名稱就屬于一個ServicelD,如果要想為項目進行 application.yml配置就采用如下的方式定義了。
修改application.yml配置文件,追加一個隨機訪問算法。
dept.provider: # 微服務的IDribbon:NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # IRule子類按照現在所給出的代碼的形式應該已經可以成功的進行了訪問處理了,所以官方文檔所提供的配置項是可以使用的。
3、【consumer-springboot-80子模塊】修改application.yml配置文件,追加自定義負載均衡配置實現,現在默認情況下可以見到的負載均衡的算法為“DynamicServerListLoadBalancer”類型,本次配置同樣的類型。
dept.provider: # 微服務的IDribbon:NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # IRule子類NFLoadBalancerClassName: com.netflix.loadbalancer.DynamicServerListLoadBalancer # ILoadBalancer二、基于Bean配置
重要提醒:
不要與應用程序組件包重合。雖然之前所有配置的Bean都是放在了SpringBoot啟動類的CLASSPATH環境之中,但是Ribbon的配置類不能夠放在被直接掃描的路徑下,因為會有可能造成配置的沖突。
package muyan.yootk.config.ribbon; // 該包不在應用程序啟動類的掃描包路徑下import com.netflix.loadbalancer.IRule; import muyan.yootk.loadbalancer.rule.NacosVersionRule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;@Configuration // 這個類必須使用該注解定義 public class DeptProviderRibbonConfig {@Bean // Bean注冊public IRule ribbonRule() { // 自定義負載均衡規則return new RandomRule(); // 隨機讀取} }在沒有進行該規則Bean配置的時候,之前采用的是一種輪詢的處理模式:按照實例的數量(1,2,3,1,2,3)輪番調用,但是現在變為了隨機調用。
package com.yootk.consumer;import muyan.yootk.config.ribbon.DeptProviderRibbonConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.ribbon.RibbonClient; import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication @EnableDiscoveryClient // 如果此時要有多個配置項,可以使用@RibbonClients注解,該注解可以配置多個@RibbonClient @RibbonClient(name = "dept.provider", configuration = DeptProviderRibbonConfig.class) // 自定義Ribbon配置 @EnableFeignClients("com.yootk.service") // Feign掃描包 public class StartConsumerApplication {public static void main(String[] args) {SpringApplication.run(StartConsumerApplication.class, args);} }三、自定義規則
既然在Ribbon里面提供了如此多的默認的規則算法,那么也就可以由用戶自己來進行自定義規則算法的使用了,此時直接定義配置Bean即可。
重要提醒:
不要與應用程序組件包重合。雖然之前所有配置的Bean都是放在了SpringBoot啟動類的CLASSPATH環境之中,但是Ribbon的配置類不能夠放在被直接掃描的路徑下,因為會有可能造成配置的沖突。
1 權重優先調用
修改權重可以通過Nacos控制臺的模型完成(一般是用于動態修改之中的操作),也可以直接通過微服務application.yml的方式來進行權重的配置。修改完成之后再次通過消費端來進行部門微服務的調用,這個時候發現并沒有根據權重的大小來實現定義,這主要是因為Ribbon消費端的負載均衡的算法沒有進行有效的配置
1.【provider-dept-*子模塊】既然要觀察權重可以考慮為所有部門微服務的節點來配置權重的內容,修改每一個微服務之中的application.yml 配置文件,編輯權重的內容:
provider-dept-8001配置:
spring:application: # 配置應用信息name: dept.provider # 是微服務的名稱cloud: # Cloud配置nacos: # Nacos注冊中心配置discovery: # 發現服務weight: 10provider-dept-8002配置: weight: 50
provider-dept-8003配置: weight: 80
2、【consumer-springboot-80子模塊】創建一個新的負載均衡算法,該算法將基于權重的高低進行調度。
package muyan.yootk.loadbalancer.rule;import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.ribbon.NacosServer; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.pojo.Instance; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.*; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired;// 如果要想進行規則的定義常見的做法是直接使用IRule接口完成 // 推薦的做法是使用IRule接口對應的抽象子類AbstractLoadBalancerRule @Slf4j public class NacosWeightRule extends AbstractLoadBalancerRule { // Nacos權重規則@Autowiredprivate NacosDiscoveryProperties nacosDiscoveryProperties; // Nacos配置屬性private IClientConfig clientConfig;@Overridepublic void initWithNiwsConfig(IClientConfig clientConfig) {this.clientConfig = clientConfig;}@Overridepublic Server choose(Object key) { // 選擇服務實例BaseLoadBalancer loadBalancer = (BaseLoadBalancer) super.getLoadBalancer(); // 獲取負載均衡器String name = loadBalancer.getName(); // 調用微服務名稱// 此時的場景就變為了原生項目的NacosClient組件進行處理的操作了NamingService namingService = this.nacosDiscoveryProperties.namingServiceInstance(); // 發現服務// 根據指定的服務名稱以及分組名稱獲取服務的實例try {Instance instance = namingService.selectOneHealthyInstance(name, this.nacosDiscoveryProperties.getGroup());// 整個的代碼是工作在SpringCloud之中的,所以需要將獲取到的Instance對象實例轉為Server對象實例return new NacosServer(instance); // NacosServer是Server子類} catch (NacosException e) {log.error("獲取Nacos注冊的微服務實例出錯,異常為:" + e);return null;}} }3、【consumer-springboot-80子模塊】DeptProviderRibbonConfig
package muyan.yootk.config.ribbon; // 該包不在應用程序啟動類的掃描包路徑下import com.netflix.loadbalancer.IRule; import muyan.yootk.loadbalancer.rule.NacosVersionRule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;@Configuration // 這個類必須使用該注解定義 public class DeptProviderRibbonConfig {@Bean // Bean注冊public IRule ribbonRule() { // 自定義負載均衡規則return new NacosWeightRule(); // 隨機讀取} }啟動類
package com.yootk.consumer;import muyan.yootk.config.ribbon.DeptProviderRibbonConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.ribbon.RibbonClient; import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication @EnableDiscoveryClient // 如果此時要有多個配置項,可以使用@RibbonClients注解,該注解可以配置多個@RibbonClient @RibbonClient(name = "dept.provider", configuration = DeptProviderRibbonConfig.class) // 自定義Ribbon配置 @EnableFeignClients("com.yootk.service") // Feign掃描包 public class StartConsumerApplication { // 沐言科技:www.yootk.compublic static void main(String[] args) {SpringApplication.run(StartConsumerApplication.class, args);} }2 集群優先調用
1、【consumer-springboot-80子模塊】NacosClusterWeightRule
package muyan.yootk.loadbalancer.rule;import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.ribbon.ExtendBalancer; import com.alibaba.cloud.nacos.ribbon.NacosServer; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.pojo.Instance; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.AbstractLoadBalancerRule; import com.netflix.loadbalancer.BaseLoadBalancer; import com.netflix.loadbalancer.Server; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils;import java.util.List; import java.util.Objects; import java.util.stream.Collectors;@Slf4j public class NacosClusterWeightRule extends AbstractLoadBalancerRule {// 如果要想按照集群調用,那么首先一定要知道當前消費端的集群名稱是什么@Autowiredprivate NacosDiscoveryProperties nacosDiscoveryProperties; // 注入Nacos發現服務配置項@Autowiredprivate IClientConfig clientConfig;@Overridepublic void initWithNiwsConfig(IClientConfig clientConfig) {this.clientConfig = clientConfig;}@Overridepublic Server choose(Object key) { // 核心關鍵BaseLoadBalancer loadBalancer = (BaseLoadBalancer) super.getLoadBalancer();// 如果此時沒有這個調用的微服務名稱,那么是無法實現最終的服務查詢的String name = loadBalancer.getName();// 獲取服務名稱NamingService namingService = this.nacosDiscoveryProperties.namingServiceInstance();// 獲取指定服務名稱的全部的實例列表數據try {// 根據指定的服務名稱以及分組查詢所有健康的服務實例列表,此時的列表包含有所有的集群信息List<Instance> instances = namingService.selectInstances(name, this.nacosDiscoveryProperties.getGroup(), true);// 理論上現在應該采用的是迭代的處理形式,將全部的集合列表進行迭代處理,隨后進行集群名稱的判斷List<Instance> clusterInstance = instances.stream().filter(instance -> Objects.equals(instance.getClusterName(), this.nacosDiscoveryProperties.getClusterName())).collect(Collectors.toList());List<Instance> instancesChoose = null; // 保存最終的返回的列表// 如果以上的處理可以獲取指定集群名稱下的全部的服務實例數據,那么就可以隨意返回一個,但是如果不能夠獲取?if (CollectionUtils.isEmpty(clusterInstance)) { // 此時集群下的實例列表為空// 此時在指定集群名稱下沒有查找到任何的實例列表,所以就把所獲取到的全部實例列表instancesChoose = instances;} else { // 如果已經查找到了指定集群名稱下的實例列表instancesChoose = clusterInstance; // 保存集群實例列表}// 因為最終所需要的是一個Server實例信息,所以這個時候可以考慮隨機讀取一個,或者按照權重返回一個Instance selectedInstance = ExtendBalancer.getHostByRandomWeight2(instancesChoose);return new NacosServer(selectedInstance); // 指定集群名稱下的一個實例} catch (NacosException e) {log.error("服務實例查詢時出現了錯誤,異常為:{}", e);}return null;} }2、【consumer-springboot-80子模塊】DeptProviderRibbonConfig
package muyan.yootk.config.ribbon; // 該包不在應用程序啟動類的掃描包路徑下import com.netflix.loadbalancer.IRule; import muyan.yootk.loadbalancer.rule.NacosVersionRule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;@Configuration // 這個類必須使用該注解定義 public class DeptProviderRibbonConfig {@Bean // Bean注冊public IRule ribbonRule() { // 自定義負載均衡規則return new NacosClusterWeightRule (); // 隨機讀取} }3 元數據優先調用
1、【consumer-springboot-80子模塊】NacosVersionRule
package muyan.yootk.loadbalancer.rule;import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.ribbon.ExtendBalancer; import com.alibaba.cloud.nacos.ribbon.NacosServer; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.pojo.Instance; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.AbstractLoadBalancerRule; import com.netflix.loadbalancer.BaseLoadBalancer; import com.netflix.loadbalancer.Server; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils;import java.util.List; import java.util.Objects; import java.util.stream.Collectors;@Slf4j public class NacosVersionRule extends AbstractLoadBalancerRule {// 如果要想按照集群調用,那么首先一定要知道當前消費端的集群名稱是什么@Autowiredprivate NacosDiscoveryProperties nacosDiscoveryProperties; // 注入Nacos發現服務配置項@Autowiredprivate IClientConfig clientConfig;@Overridepublic void initWithNiwsConfig(IClientConfig clientConfig) {this.clientConfig = clientConfig;}@Overridepublic Server choose(Object key) {BaseLoadBalancer loadBalancer = (BaseLoadBalancer) super.getLoadBalancer();// 如果此時沒有這個調用的微服務名稱,那么是無法實現最終的服務查詢的String name = loadBalancer.getName();// 獲取服務名稱NamingService namingService = this.nacosDiscoveryProperties.namingServiceInstance();try {// 根據指定的服務名稱以及分組的名稱獲取全部的可用實例數據List<Instance> instances = namingService.selectInstances(name, this.nacosDiscoveryProperties.getGroup(), true);// 對獲取到的實例集合進行迭代處理,篩選出所需要的與當前版本匹配的實例數據List<Instance> metadataVersionMatchInstance = instances.stream().filter(instance -> Objects.equals(this.nacosDiscoveryProperties.getMetadata().get("version"), // 消費端配置的元數據版本項instance.getMetadata().get("version"))) // 注冊微服務實例配置的元數據版本項.collect(Collectors.toList());// 必須考慮沒有匹配版本下的實例篩選操作List<Instance> selectedInstances = null; // 最終所使用的實例集合if (CollectionUtils.isEmpty(metadataVersionMatchInstance)) { // 沒有查詢到匹配的集合selectedInstances = instances;} else {selectedInstances = metadataVersionMatchInstance; // 版本匹配}Instance instance = ExtendBalancer.getHostByRandomWeight2(selectedInstances);return new NacosServer(instance);} catch (NacosException e) {log.error("獲取Nacos注冊的微服務實例出錯,異常為:" + e);}return null;} }3、【consumer-springboot-80子模塊】DeptProviderRibbonConfig
package muyan.yootk.config.ribbon; // 該包不在應用程序啟動類的掃描包路徑下import com.netflix.loadbalancer.IRule; import muyan.yootk.loadbalancer.rule.NacosVersionRule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;@Configuration // 這個類必須使用該注解定義 public class DeptProviderRibbonConfig {@Bean // Bean注冊public IRule ribbonRule() { // 自定義負載均衡規則return new NacosVersionRule (); // 隨機讀取} }總結
以上是生活随笔為你收集整理的Ribbon 客户端负载均衡的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎样更改电脑的声音模式呢?
- 下一篇: 剑网三需要的笔记本电脑配置?