<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] ***** # 1. 傳統的負載均衡方式 ``` 1-1. 服務端負載均衡 1-2. 客戶端負載均衡 ``` **1-1 服務端負載均衡** ``` ngnix是部署在服務端的,故稱為服務端負載均衡 ``` ![](https://img.kancloud.cn/e9/21/e9213e60fdea046cdaafafebd08368fe_548x321.png) **1-2 客戶端負載均衡** ``` 在內容中心中獲取用戶中心的實例,在內容中心中定義負載均衡的規則,故稱為客戶端負載均衡 ``` ![](https://img.kancloud.cn/f8/79/f879e8b1a2bc9b01b435bdeb6b4f0926_701x439.png) # 2. 手寫一個客戶端負載均衡器 ``` 目標: 隨機選擇實例 思路: 1. 通過nacos獲取服務端實例列表 2. 通過算法隨機選擇 3. 代碼如下: //獲取nacos上ali-pay-service所有的實例 List<ServiceInstance> instances = discooveryClient.getInstances("ali-pay-service"); //獲取請求地址 List<String> targetURLS = instances.stream().map(instance -> instance.getUri().toString() + "/users/{id}").collect(Collectors.toList()); //寫隨機算法,獲取隨機下標 int i = ThreadLocalRandom.current().nextInt(targetURLS.size()); //使用restTemplate請求 restTemplate.getForObject(targetURLS.get(i), null); ``` # 3. Ribbon實現負載均衡 **3-1 什么是Ribbon?** ``` Ribbon是Netflix發布的開源項目,主要功能是提供客戶端的軟件負載均衡算法,將Netflix的中間層服務連接在一起. Ribbon客戶端組件提供一系列完善的配置項如連接超時,重試等. Ribbon負載均衡主要是輪詢算法,分為以下幾步: 1.根據服務別名,從eureka / nacos獲取服務提供者的客戶端列表 2.將列表緩存到本地,即消費者客戶端的jvm中 3.獲取提供者客戶端下標(總請求數%服務提供者數), 得到調用的服務客戶端的實際地址 ``` ![](https://img.kancloud.cn/42/76/4276d1e51432482a42245ea23f765c47_740x357.png) **3-2 Ribbon實現負載均衡** ``` 1. 添加Ribbon依賴 2. 在RestTemplate定義的bean上添加注解 @LoadBalanced 3. 添加配置(可以默認配置) 4. 修改代碼 restTemplate.getForObject("http://ali-pay-service/users/{userId}", null); ``` **3-3 Ribbon的組成** ![](https://img.kancloud.cn/98/5e/985eb6ffd9d5ae60f88f91a23a891e5a_887x401.png) **3-4 Ribbon內置的負載均衡規則** ![](https://img.kancloud.cn/b0/a3/b0a34e51ee967d144552093188c1a80b_860x496.png) **3-5 細粒度配置自定義** **01-Java代碼方式** ``` /** * 修改Ribbon負載均衡規則 * 注: 此類要建在啟動類之外 * 父子上下文: * 1. 啟動類上有@ComponentScan掃描注解,默認會掃描當前類及下屬所有包中相關注解(父上下文) * 2. Ribbon規則配置有@Configuration注解為子上下文,若在父包下,會出現父子上下文重疊 * 會導致事務不生效,重點: 因此配置ribbon規則時,不要讓RibbonConfiguration被@ComponentScan掃描到 * */ @Configuration public class RibbonConfiguration { @Bean public IRule ribbonRule() { return new RandomRule(); } } ``` ``` /** * java代碼修改ribbon的負載均衡規則 */ @Configuration @RibbonClient(name = "ali-pay-service", configuration = RibbonConfiguration.class) public class UerCenterRibbonConfiguration { } ``` **02-配置屬性方式** ``` ali-pay-service: ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule ``` **03-倆種配置方式對比** ``` [配置屬性的方式] 比 [代碼配置方式] 的優先級更高!!! ``` ![](https://img.kancloud.cn/f3/ce/f3ce24e46ee544f7cf5c35be16174029_795x302.png) **04-ribbon負載均衡規則全局配置** ``` /** * java代碼修改ribbon負載均衡規則全局配置 * RibbonConfiguration 類就可以放在啟動類下被@ComponentScan掃描到 */ @Configuration @RibbonClients(defaultConfiguration = RibbonConfiguration.class) public class UerCenterRibbonConfiguration { } ``` **05-ribbon饑餓加載** ``` Ribbon默認是懶加載的, 就是當restTemplate.getForObject("http://ali-pay-service/users/{userId}", null); 這段代碼被調用時,才會加載,因此會導致首次請求過慢的問題. ``` ``` 解決方案: 通過饑餓加載解決, 添加配置如下: #饑餓加載配置 ribbon: eager-load: enabled: true #開啟饑餓加載 clients: ali-pay-service #為哪些名稱的client開啟,多個用逗號分隔 ``` **3-6 擴展Ribbon** ``` 3-6-1. 擴展Ribbon-支持Nacos權重 取值在0到1之間, 值越大代表這個實例被調用的幾率越大 Ribbon默認負載均衡規則不支持Nacos權重,所以擴展實現負載均衡權重的規則 ``` ``` /** * 基于權重的負載均衡算法 */ public class NacosWeightedRule extends AbstractLoadBalancerRule { @Autowired private NacosDiscoveryProperties nacosDiscoveryProperties; //讀取配置文件并初始化 @Override public void initWithNiwsConfig(IClientConfig clientConfig) { } @Override public Server choose(Object key) { try { ILoadBalancer loadBalancer = this.getLoadBalancer(); BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer)loadBalancer; //想要請求的微服務的名稱 String name = baseLoadBalancer.getName(); //實現負載均衡的算法, 借助nacos已有的算法, 拿到服務發現相關的API NamingService namingService = nacosDiscoveryProperties.namingServiceInstance(); //nacos client 自動通過基于權重的負載均衡算法,給我們選擇一個實例 Instance instance = namingService.selectOneHealthyInstance(name); return new NacosServer(instance); } catch (NacosException e) { return null; } } } ``` ![](https://img.kancloud.cn/8c/ef/8cef9b6e9f37d70214aa7f3b2d84f8b6_826x459.png) ``` 3-6-2. 擴展Ribbon-同一集群優先調用(同機房優先調用) 基于0.9.0版本,官方可能在下個版本加入此功能 public class NacosSameClusterWeightRule extends AbstractLoadBalancerRule { @Autowired private NacosDiscoveryProperties nacosDiscoveryProperties; @Override public void initWithNiwsConfig(IClientConfig clientConfig) { } @Override public Server choose(Object key) { try { //拿到配置文件中的集群名稱(DL) spring.cloud.nacos.discovery.cluster-name=DL String clusterName = nacosDiscoveryProperties.getClusterName(); ILoadBalancer loadBalancer = this.getLoadBalancer(); BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer)loadBalancer; //想要請求的微服務的名稱 String name = baseLoadBalancer.getName(); //實現負載均衡的算法, 借助nacos已有的算法, 拿到服務發現相關的API NamingService namingService = nacosDiscoveryProperties.namingServiceInstance(); // 1. 找到指定服務的所有實例(true代表健康的實例) -- A List<Instance> instances = namingService.selectInstances(name, true); // 2. 過濾出相同集群下的所有實例 -- B List<Instance> sameClusterInstances = instances.stream().filter(instance -> Objects.equals(instance.getClusterName(), clusterName)) .collect(Collectors.toList()); // 3. 如果B是空就用A List<Instance> instancesToBeChosen = Lists.newArrayList(); if (CollectionUtils.isEmpty(sameClusterInstances)) { instancesToBeChosen = instances; //發生跨集群的調用 } else { instancesToBeChosen = sameClusterInstances; } // 4. 基于權重的負載均衡算法,返回1個實例 Instance instance = ExtendBalancer.getHostByRandomWeight2(instancesToBeChosen); return new NacosServer(instance); } catch (NacosException e) { return null; } } } class ExtendBalancer extends Balancer { public static Instance getHostByRandomWeight2(List<Instance> hosts) { return getHostByRandomWeight(hosts); } } ``` ``` 3-6-3. 擴展Ribbon-基于元數據的版本控制 場景: 服務間調用可能存在版本控制,如 服務A 的 V1版本必須調用服務B 的 V1版本, 服務A的V2版本必須調用服務B的V2版本 實現微服務之間的版本控制 代碼參考: https://gitee.com/itmuch/spring-cloud-study/tree/master/2019-Spring-Cloud-Alibaba/microservice-consumer-movie-ribbon-rule-with-nacos-2 ``` **元數據就是一堆的描述信息,以map存儲。舉個例子:** ``` spring: cloud: nacos: metadata: # 自己這個實例的版本 version: v1 # 允許調用的提供者版本 target-version: v1 ``` **需求分析:** ``` 我們需要實現的有兩點: 1. 優先選擇同集群下,符合metadata的實例 2. 如果同集群加沒有符合metadata的實例,就選擇所有集群下,符合metadata的實例 ``` ``` @Slf4j public class NacosFinalRule extends AbstractLoadBalancerRule { @Autowired private NacosDiscoveryProperties nacosDiscoveryProperties; @Override public Server choose(Object key) { // 負載均衡規則:優先選擇同集群下,符合metadata的實例 // 如果沒有,就選擇所有集群下,符合metadata的實例 // 1. 查詢所有實例 A // 2. 篩選元數據匹配的實例 B // 3. 篩選出同cluster下元數據匹配的實例 C // 4. 如果C為空,就用B // 5. 隨機選擇實例 try { String clusterName = this.nacosDiscoveryProperties.getClusterName(); String targetVersion = this.nacosDiscoveryProperties.getMetadata().get("target-version"); DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer(); String name = loadBalancer.getName(); NamingService namingService = this.nacosDiscoveryProperties.namingServiceInstance(); // 所有實例 List<Instance> instances = namingService.selectInstances(name, true); List<Instance> metadataMatchInstances = instances; // 如果配置了版本映射,那么只調用元數據匹配的實例 if (StringUtils.isNotBlank(targetVersion)) { metadataMatchInstances = instances.stream() .filter(instance -> Objects.equals(targetVersion, instance.getMetadata().get("version"))) .collect(Collectors.toList()); if (CollectionUtils.isEmpty(metadataMatchInstances)) { log.warn("未找到元數據匹配的目標實例!請檢查配置。targetVersion = {}, instance = {}", targetVersion, instances); return null; } } List<Instance> clusterMetadataMatchInstances = metadataMatchInstances; // 如果配置了集群名稱,需篩選同集群下元數據匹配的實例 if (StringUtils.isNotBlank(clusterName)) { clusterMetadataMatchInstances = metadataMatchInstances.stream() .filter(instance -> Objects.equals(clusterName, instance.getClusterName())) .collect(Collectors.toList()); if (CollectionUtils.isEmpty(clusterMetadataMatchInstances)) { clusterMetadataMatchInstances = metadataMatchInstances; log.warn("發生跨集群調用。clusterName = {}, targetVersion = {}, clusterMetadataMatchInstances = {}", clusterName, targetVersion, clusterMetadataMatchInstances); } } Instance instance = ExtendBalancer.getHostByRandomWeight2(clusterMetadataMatchInstances); return new NacosServer(instance); } catch (Exception e) { log.warn("發生異常", e); return null; } } @Override public void initWithNiwsConfig(IClientConfig iClientConfig) { } } /**負載均衡算法**/ public class ExtendBalancer extends Balancer { /** * 根據權重,隨機選擇實例 * * @param instances 實例列表 * @return 選擇的實例 */ public static Instance getHostByRandomWeight2(List<Instance> instances) { return getHostByRandomWeight(instances); } } ``` ``` 3-6-4. 深入理解Nacos的Namespace Nacos通過Namespace做了環境隔離,只能調用相同Namespace下的實例,而不能跨Namespace調用. ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看