成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

深入理解微服務中的負載均衡算法與配置策略

開發 前端
盡管實踐是增長知識的一部分,但是在真實的生產環境中,尤其是跨多個數據中心部署的情況下,我們無法簡單地將問題簡化為本地集群的測試環境。

上一期我們詳細探討了微服務之間的通信,特別是介紹了如何集成Ribbon。簡單來說,通過使用resttemplate類進行RPC調用時,我們內部增加了一個攔截器來實現負載均衡。然而,我們并未深入討論具體的負載均衡算法。因此,本章節的重點是介紹如何從多個副本中選擇合適的節點進行服務調用。這將幫助大家更好地理解在微服務架構中如何有效地實現負載均衡。

好的,今天我們依舊會涉及源碼,但希望大家能把注意力集中在理念層面,而不是深究每個具體的過程調用。無需糾結于代碼的具體行數,因為重要的是理解整體架構和流程,這樣才能更好地掌握主題的實質。

負載均衡算法

我們首先來探討一下默認情況下Ribbon使用的負載均衡算法。有些人可能會說它使用輪詢算法,因為在本地測試時,我們經常會看到輪詢的效果。然而,簡單地依賴這種表面的觀察來回答面試題是有風險的。實際上,忽略了深入理解源代碼可能會導致嚴重的誤解。

盡管實踐是增長知識的一部分,但是在真實的生產環境中,尤其是跨多個數據中心部署的情況下,我們無法簡單地將問題簡化為本地集群的測試環境。

獲取服務器ip

我們接著上一篇內容,討論如何選擇服務器的步驟如下復述:

public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
            throws IOException {
        ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
        Server server = getServer(loadBalancer, hint);
        if (server == null) {
            throw new IllegalStateException("No instances available for " + serviceId);
        }
        RibbonServer ribbonServer = new RibbonServer(serviceId, server,
                isSecure(server, serviceId),
                serverIntrospector(serviceId).getMetadata(server));

        return execute(serviceId, ribbonServer, request);
    }

獲取負載均衡器——ZoneAwareLoadBalancer

我們來看看getServer方法,突然間出現這么多負載均衡器,應該怎么處理呢?這時候最好的方法就是查看自動配置,看看哪些被注入進來了。

圖片圖片

中間步驟大家就不用再找了,我已經事先找好了,就在這里:

圖片圖片

這張圖包含兩個關鍵信息:首先是注入了一個IRule規則,其次是將該IRule規則應用到了ZoneAwareLoadBalancer負載均衡器中。好的,現在我們清楚了接下來的步驟。接下來我們繼續查看

public Server chooseServer(Object key) {
        if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() <= 1) {
            logger.debug("Zone aware logic disabled or there is only one zone");
            return super.chooseServer(key);
        }
        Server server = null;
        try {
            //省略多余代碼
            Set<String> availableZones = ZoneAvoidanceRule.getAvailableZones(zoneSnapshot, triggeringLoad.get(), triggeringBlackoutPercentage.get());
            logger.debug("Available zones: {}", availableZones);
            if (availableZones != null &&  availableZones.size() < zoneSnapshot.keySet().size()) {
                String zone = ZoneAvoidanceRule.randomChooseZone(zoneSnapshot, availableZones);
                logger.debug("Zone chosen: {}", zone);
                if (zone != null) {
                    BaseLoadBalancer zoneLoadBalancer = getLoadBalancer(zone);
                    server = zoneLoadBalancer.chooseServer(key);
                }
            }
        } catch (Exception e) {
            logger.error("Error choosing server using zone aware logic for load balancer={}", name, e);
        }
        //省略多余代碼
    }

如果是在我們本地環境,通常會執行第一個if分支;但如果是在生產環境并配置了多個區域,那么會執行下面的分支。讓我們一起來看看。

無配置區域情況

讓我們來看看第一種情況,即如果沒有區域或者只有一個區域,負載均衡規則是如何應用的。我們將查看父類負載均衡器BaseLoadBalancer的代碼。

public class BaseLoadBalancer extends AbstractLoadBalancer implements
        PrimeConnections.PrimeConnectionListener, IClientConfigAware {   
    private final static IRule DEFAULT_RULE = new RoundRobinRule();

    protected IRule rule = DEFAULT_RULE;
    
    public Server chooseServer(Object key) {
        if (counter == null) {
            counter = createCounter();
        }
        counter.increment();
        if (rule == null) {
            return null;
        } else {
            try {
                return rule.choose(key);
            } catch (Exception e) {
                logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", name, key, e);
                return null;
            }
        }
    }
    
     void initWithConfig(IClientConfig clientConfig, IRule rule, IPing ping, LoadBalancerStats stats) {
        // 省略部分代碼
        setRule(rule);
        // 省略部分代碼
    }
}

這里可以看到是有默認的IRule規則的——RoundRobinRule,但是別沖動,因為我們Spring自動托管的IRule規則還沒用上,不可能這么簡單的走輪訓。我們可以看到這里是有設置的地方的。我也抓出來了。

最后讓我們再來看看我們的ZoneAwareLoadBalancer生成構造器,因為在注入時我們是會帶入規則的。以下是相關的代碼示例:

public ZoneAwareLoadBalancer(IClientConfig clientConfig, IRule rule,
                                 IPing ping, ServerList<T> serverList, ServerListFilter<T> filter,
                                 ServerListUpdater serverListUpdater) {
        super(clientConfig, rule, ping, serverList, filter, serverListUpdater);
    }

在這里,當super父類構造器執行完畢后,最終會調用BaseLoadBalancer類的initWithConfig方法。我沒有一一追蹤下去,但最后ZoneAvoidanceRule的負載均衡代碼也相當復雜。不過,你可以將其理解為在沒有區域的情況下類似于輪詢。

配置多區域情況

在這個階段,程序將會執行第二個分支,實際上,主要的代碼如下所示:

String zone = ZoneAvoidanceRule.randomChooseZone(zoneSnapshot, availableZones);
if (zone != null) {
    BaseLoadBalancer zoneLoadBalancer = getLoadBalancer(zone);
    server = zoneLoadBalancer.chooseServer(key);
}

目的仍然是選擇一個服務器,但是限定在當前區域內。關于這部分的詳細討論略去,因為接下來的方法都是關于ZoneAvoidanceRule的負載均衡算法代碼。

如何配置其他算法

在這種情況下,如果我想使用其他負載均衡算法而不是當前的算法,應該如何配置呢?實際上,可以查看注入的源代碼,有兩種方法可以實現這一點。首先,可以通過在配置類中添加一個配置項來指定所需的負載均衡算法。

if (this.propertiesFactory.isSet(IRule.class, name)) {
    return this.propertiesFactory.get(IRule.class, config, name);
}

局部配置

在這里可以看到我們也是通過配置文件來進行配置的,不過配置文件的方式使我們能夠進行局部微服務負載均衡的選擇。讓我們先來看一下源代碼:

public PropertiesFactory() {
        classToProperty.put(ILoadBalancer.class, "NFLoadBalancerClassName");
        classToProperty.put(IPing.class, "NFLoadBalancerPingClassName");
        classToProperty.put(IRule.class, "NFLoadBalancerRuleClassName");
        classToProperty.put(ServerList.class, "NIWSServerListClassName");
        classToProperty.put(ServerListFilter.class, "NIWSServerListFilterClassName");
    }

    public boolean isSet(Class clazz, String name) {
        return StringUtils.hasText(getClassName(clazz, name));
    }

在調用特定的微服務時,可以根據需要使用相應的負載均衡策略來配置 application.yml 文件。

#被調用的微服務名
mall‐order:
 ribbon:
    #指定使用Nacos提供的負載均衡策略(優先調用同一集群的實例,基于隨機&權重)
    NFLoadBalancerRuleClassName:com.alibaba.cloud.nacos.ribbon.NacosRule

全局配置

在全局情況下更為簡單,可以觀察到在自動注入時使用了 @ConditionalOnMissingBean 注解。如果我們在Spring中手動加載了相應的bean,那么這個注解就不會生效了。

@Bean
    public IRule ribbonRule() {
        // 指定使用Nacos提供的負載均衡策略(優先調用同一集群的實例,基于隨機權重)
        return new NacosRule();
    }

相當簡單了,那么這樣的的話,其實我們也可以進行自定義一個策略的。畢竟照先有的抄下固定實現方法后,自己在實現方法內寫上自己的業務邏輯不就完了。

自定義策略

看起來,對于實現其他的負載均衡算法策略,有幾個關鍵點。首先,需要繼承 AbstractLoadBalancerRule 父類,并且實現其抽象方法。接下來,我們可以開始編寫我們的實現代碼:

@Slf4j
public class XiaoYuRandomWithWeightRule extends AbstractLoadBalancerRule { 

    @Override
    public Server choose(Object key) {
        //這里實現自己的邏輯即可
        return server;
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }
}

OK,剩下的就按照局部配置或者全局配置下,讓我們的規則生效即可。

在這里只講述了算法規則的配置和自定義方法,實際上負載均衡器的操作也是類似的套路。這里就不重復演示了。

總結

今天,我們主要補充了上一章關于微服務通信的內容,并深入探討了負載均衡算法的重要性。我們首先詳細討論了Ribbon默認使用的負載均衡算法。盡管在本地測試時可能會觀察到輪詢的效果,但簡單依賴這種表面的觀察是不夠的。在真實的生產環境中,特別是在跨多個數據中心部署時,負載均衡策略的選擇需要更加深入的理解和分析。

我們進一步分析了如何通過配置和自定義負載均衡規則來靈活應對各種場景。不論是局部配置還是全局配置,我們都能根據具體需求調整負載均衡的行為。同時,我們展示了如何通過自定義算法擴展Ribbon的負載均衡能力,以更好地適應特定業務場景的需求。

責任編輯:武曉燕 來源: 靈墨AI探索室
相關推薦

2018-11-27 12:31:39

負載均衡高可用架構

2021-10-10 13:31:14

Java負載均衡算法

2021-10-21 10:02:37

Java開發代碼

2020-01-14 09:40:00

Nginx負載均衡正向代理

2023-10-08 08:53:36

數據庫MySQL算法

2023-11-29 09:57:23

微服務容器

2024-11-29 13:37:56

2019-02-21 09:18:27

服務路由負載均衡微服務

2024-07-18 10:12:04

2011-08-24 13:45:49

HAProxy負載均衡負載均衡器

2020-12-26 16:51:12

Python操作符開發

2010-03-12 08:55:06

Java內省反射

2020-07-10 08:15:19

遞歸算法函數

2024-07-08 09:29:07

2023-12-31 12:56:02

C++內存編程

2024-06-28 10:25:18

2018-07-09 15:11:14

Java逃逸JVM

2020-12-16 09:47:01

JavaScript箭頭函數開發

2016-08-31 15:50:50

PythonThreadLocal變量

2010-06-28 10:12:01

PHP匿名函數
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产剧情一区 | 精品一区二区三区免费毛片 | 野狼在线社区2017入口 | 黄色免费在线观看 | 91精品国产乱码久久久 | 91视频国产一区 | 免费在线日韩 | 久久久精品一区 | 无毛av | 成人水多啪啪片 | 精品视频在线观看 | 久久久久黄色 | 黄网站在线播放 | 日韩成人在线观看 | 福利在线观看 | 一片毛片 | 国产亚洲精品精品国产亚洲综合 | 国产成人精品一区二区三区在线 | 成人在线观看网址 | 久久精品欧美一区二区三区不卡 | 国产在线小视频 | 成人免费网站 | 欧美精品久久久久 | 99久久99 | 亚洲va欧美va天堂v国产综合 | 日本视频免费 | 久久丝袜| 中文字幕av在线播放 | 欧美aⅴ| 国产精品久久久久无码av | 亚洲久草视频 | 色屁屁在线观看 | 久久综合一区 | 亚洲永久免费观看 | 国产精品一区二区三区在线 | 成人av电影在线 | 亚洲精品久久久一区二区三区 | 国产韩国精品一区二区三区 | 久久久噜噜噜久久中文字幕色伊伊 | 欧美成人免费在线 | 在线日韩欧美 |