最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

從零帶你手寫(xiě)Java七種負(fù)載均衡算法實(shí)現(xiàn)方案

 更新時(shí)間:2026年02月13日 09:27:35   作者:大黃評(píng)測(cè)  
在分布式系統(tǒng),微服務(wù)架構(gòu)以及高并發(fā)場(chǎng)景中,負(fù)載均衡是一項(xiàng)至關(guān)重要的技術(shù)本文將帶你純手寫(xiě)實(shí)現(xiàn)七種常見(jiàn)的負(fù)載均衡算法,全部使用?Java?編寫(xiě),不依賴任何第三方框架,幫助你深入理解其核心原理與適用場(chǎng)景

在分布式系統(tǒng)、微服務(wù)架構(gòu)以及高并發(fā)場(chǎng)景中,負(fù)載均衡(Load Balancing) 是一項(xiàng)至關(guān)重要的技術(shù)。它能夠?qū)⒄?qǐng)求合理地分發(fā)到多個(gè)服務(wù)節(jié)點(diǎn)上,從而提升系統(tǒng)整體的吞吐量、可用性和容錯(cuò)能力。

本文將帶你純手?jǐn)]實(shí)現(xiàn)七種常見(jiàn)的負(fù)載均衡算法,全部使用 Java 編寫(xiě),不依賴任何第三方框架,幫助你深入理解其核心原理與適用場(chǎng)景。

準(zhǔn)備工作

首先定義一個(gè)通用的服務(wù)節(jié)點(diǎn)接口:

public class Server {
    private String host;
    private int port;
    private int weight; // 權(quán)重,用于加權(quán)類算法

    public Server(String host, int port) {
        this(host, port, 1);
    }

    public Server(String ??host, int port, int weight) {
        this.host = host;
        this.port = port;
        this.weight = weight;
    }

    // getters & setters
    public String getHost() { return host; }
    public int getPort() { return port; }
    public int getWeight() { return weight; }
    public void setWeight(int weight) { this.weight = weight; }

    @Override
    public String toString() {
        return host + ":" + port + "(w=" + weight + ")";
    }
}

所有算法都將實(shí)現(xiàn)以下接口:

public interface LoadBalancer {
    Server select(List<Server> servers);
}

1. 隨機(jī)(Random)

最簡(jiǎn)單的策略:從可用節(jié)點(diǎn)中隨機(jī)選擇一個(gè)。

public class RandomLoadBalancer implements LoadBalancer {
    private final Random random = new Random();

    @Override
    public Server select(List<Server> servers) {
        if (servers == null || servers.isEmpty()) return null;
        int index = random.nextInt(servers.size());
        return servers.get(index);
    }
}

優(yōu)點(diǎn):簡(jiǎn)單、無(wú)狀態(tài)

缺點(diǎn):無(wú)法保證請(qǐng)求分布均勻(尤其在短時(shí)間窗口內(nèi))

2. 輪詢(Round Robin)

按順序依次選擇節(jié)點(diǎn),循環(huán)往復(fù)。

public class RoundRobinLoadBalancer implements LoadBalancer {
    private AtomicInteger index = new AtomicInteger(0);

    @Override
    public Server select(List<Server> servers) {
        if (servers == null || servers.isEmpty()) return null;
        int i = index.getAndIncrement() % servers.size();
        // 處理負(fù)數(shù)(雖然 unlikely)
        if (i < 0) i += servers.size();
        return servers.get(i);
    }
}

優(yōu)點(diǎn):請(qǐng)求分布均勻

缺點(diǎn):未考慮服務(wù)器性能差異

3. 加權(quán)輪詢(Weighted Round Robin)

為每個(gè)節(jié)點(diǎn)分配權(quán)重,高權(quán)重節(jié)點(diǎn)被選中的頻率更高。

實(shí)現(xiàn)思路:采用“最大公約數(shù) + 當(dāng)前輪次”方式,避免預(yù)生成列表(節(jié)省內(nèi)存)。

public class WeightedRoundRobinLoadBalancer implements LoadBalancer {
    private AtomicInteger currentPos = new AtomicInteger(0);

    @Override
    public Server select(List<Server> servers) {
        if (servers == null || servers.isEmpty()) return null;

        // 計(jì)算總權(quán)重
        int totalWeight = servers.stream().mapToInt(Server::getWeight).sum();
        if (totalWeight <= 0) {
            // 退化為普通輪詢
            return new RoundRobinLoadBalancer().select(servers);
        }

        int current = currentPos.getAndIncrement() % totalWeight;
        if (current < 0) current += totalWeight;

        // 遍歷找到對(duì)應(yīng)節(jié)點(diǎn)
        for (Server server : servers) {
            if (current < server.getWeight()) {
                return server;
            }
            current -= server.getWeight();
        }

        // 理論上不會(huì)走到這里
        return servers.get(servers.size() - 1);
    }
}

注意:上述實(shí)現(xiàn)是簡(jiǎn)化版。工業(yè)級(jí)實(shí)現(xiàn)(如 Nginx)通常使用更復(fù)雜的平滑加權(quán)輪詢(Smooth Weighted Round Robin),以避免連續(xù)選中高權(quán)重節(jié)點(diǎn)。

4. 平滑加權(quán)輪詢(Smooth Weighted Round Robin)

由 Nginx 提出,解決加權(quán)輪詢中“高權(quán)重節(jié)點(diǎn)連續(xù)被選中”的問(wèn)題。

public class SmoothWeightedRoundRobinLoadBalancer implements LoadBalancer {

    private final Map<Server, Integer> currentWeights = new ConcurrentHashMap<>();

    @Override
    public Server select(List<Server> servers) {
        if (servers == null || servers.isEmpty()) return null;

        int totalWeight = 0;
        Server best = null;
        int max = Integer.MIN_VALUE;

        for (Server server : servers) {
            int weight = server.getWeight();
            if (weight <= 0) weight = 1;

            totalWeight += weight;
            int current = currentWeights.getOrDefault(server, 0) + weight;
            currentWeights.put(server, current);

            if (current > max) {
                max = current;
                best = server;
            }
        }

        if (best != null) {
            currentWeights.put(best, max - totalWeight);
        }

        return best;
    }
}

優(yōu)點(diǎn):權(quán)重分配更平滑,高權(quán)重節(jié)點(diǎn)不會(huì)連續(xù)被選中

示例:A(w=5), B(w=1) → 順序?yàn)?A,A,A,A,A,B,... 而非 A,A,A,A,A,A,...

5. 最少連接(Least Connections)

將請(qǐng)求分發(fā)給當(dāng)前連接數(shù)最少的節(jié)點(diǎn)。

為簡(jiǎn)化,我們用一個(gè) Map<Server, AtomicInteger> 模擬連接計(jì)數(shù)。

public class LeastConnectionsLoadBalancer implements LoadBalancer {
    private final Map<Server, AtomicInteger> connectionCounts = new ConcurrentHashMap<>();

    @Override
    public Server select(List<Server> servers) {
        if (servers == null || servers.isEmpty()) return null;

        Server best = null;
        int minConn = Integer.MAX_VALUE;

        for (Server server : servers) {
            int conn = connectionCounts.computeIfAbsent(server, k -> new AtomicInteger(0)).get();
            if (conn < minConn) {
                minConn = conn;
                best = server;
            }
        }

        // 模擬增加連接(實(shí)際使用需配合請(qǐng)求完成后的 decrement)
        if (best != null) {
            connectionCounts.get(best).incrementAndGet();
        }

        return best;
    }

    // 供外部調(diào)用:請(qǐng)求完成后減少連接數(shù)
    public void release(Server server) {
        AtomicInteger count = connectionCounts.get(server);
        if (count != null) {
            count.decrementAndGet();
        }
    }
}

適用于長(zhǎng)連接或處理時(shí)間差異大的場(chǎng)景

需要維護(hù)連接狀態(tài),有額外開(kāi)銷

6. 源地址哈希(IP Hash / Source Hash)

根據(jù)客戶端 IP(或其他唯一標(biāo)識(shí))做哈希,保證同一客戶端始終路由到同一節(jié)點(diǎn)。

public class SourceHashLoadBalancer implements LoadBalancer {
    private String source; // 可通過(guò)構(gòu)造函數(shù)傳入 client IP

    public SourceHashLoadBalancer(String source) {
        this.source = source;
    }

    @Override
    public Server select(List<Server> servers) {
        if (servers == null || servers.isEmpty() || source == null) return null;
        int hash = source.hashCode();
        int index = (hash & 0x7FFFFFFF) % servers.size(); // 避免負(fù)數(shù)
        return servers.get(index);
    }
}

優(yōu)點(diǎn):會(huì)話保持(Session Stickiness)

缺點(diǎn):節(jié)點(diǎn)增減會(huì)導(dǎo)致大量映射失效(可改用一致性哈希)

7. 一致性哈希(Consistent Hashing)

解決普通哈希在節(jié)點(diǎn)動(dòng)態(tài)變化時(shí)緩存/會(huì)話大量失效的問(wèn)題。

public class ConsistentHashingLoadBalancer implements LoadBalancer {
    private final SortedMap<Integer, Server> circle = new TreeMap<>();
    private final int virtualNodes; // 虛擬節(jié)點(diǎn)數(shù)

    public ConsistentHashingLoadBalancer(int virtualNodes) {
        this.virtualNodes = virtualNodes;
    }

    public void addServer(Server server) {
        for (int i = 0; i < virtualNodes; i++) {
            int hash = hash(server.getHost() + ":" + server.getPort() + "#" + i);
            circle.put(hash, server);
        }
    }

    public void removeServer(Server server) {
        for (int i = 0; i < virtualNodes; i++) {
            int hash = hash(server.getHost() + ":" + server.getPort() + "#" + i);
            circle.remove(hash);
        }
    }

    private int hash(String key) {
        return key.hashCode(); // 簡(jiǎn)化,生產(chǎn)建議用 MD5 或 MurmurHash
    }

    @Override
    public Server select(List<Server> servers) {
        if (circle.isEmpty()) {
            // 動(dòng)態(tài)構(gòu)建環(huán)(實(shí)際應(yīng)提前構(gòu)建)
            servers.forEach(this::addServer);
        }
        if (circle.isEmpty()) return null;

        // 假設(shè) source 為請(qǐng)求 ID 或 IP
        String requestKey = "request_" + System.nanoTime(); // 實(shí)際應(yīng)由調(diào)用方提供
        int hash = hash(requestKey);

        if (!circle.containsKey(hash)) {
            SortedMap<Integer, Server> tailMap = circle.tailMap(hash);
            hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey();
        }
        return circle.get(hash);
    }
}

節(jié)點(diǎn)增減只影響局部數(shù)據(jù)

廣泛用于緩存、分布式存儲(chǔ)系統(tǒng)

總結(jié)對(duì)比

算法是否考慮權(quán)重是否有狀態(tài)適用場(chǎng)景
隨機(jī)??簡(jiǎn)單快速分發(fā)
輪詢??(位置)請(qǐng)求均勻、節(jié)點(diǎn)同質(zhì)
加權(quán)輪詢??節(jié)點(diǎn)性能不同
平滑加權(quán)輪詢??更公平的加權(quán)分發(fā)
最少連接?(但看負(fù)載)?長(zhǎng)連接、異構(gòu)任務(wù)
源地址哈希??會(huì)話保持
一致性哈希?(可擴(kuò)展支持)?(哈希環(huán))緩存、分布式存儲(chǔ)

結(jié)語(yǔ)

通過(guò)手寫(xiě)這七種負(fù)載均衡算法,我們不僅掌握了其實(shí)現(xiàn)細(xì)節(jié),也理解了它們各自的優(yōu)劣和適用邊界。在真實(shí)項(xiàng)目中,可根據(jù)業(yè)務(wù)需求靈活選擇或組合使用(例如:先一致性哈希定位節(jié)點(diǎn)組,再在組內(nèi)輪詢)。

提示:生產(chǎn)環(huán)境建議使用成熟組件(如 Ribbon、Spring Cloud LoadBalancer、Nginx、LVS),但理解底層原理永遠(yuǎn)是工程師的核心競(jìng)爭(zhēng)力。

以上就是從零帶你手寫(xiě)Java七種負(fù)載均衡算法實(shí)現(xiàn)方案的詳細(xì)內(nèi)容,更多關(guān)于Java負(fù)載均衡算法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Spring的連接數(shù)據(jù)庫(kù)以及JDBC模板(實(shí)例講解)

    Spring的連接數(shù)據(jù)庫(kù)以及JDBC模板(實(shí)例講解)

    下面小編就為大家?guī)?lái)一篇Spring的連接數(shù)據(jù)庫(kù)以及JDBC模板(實(shí)例講解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-10-10
  • Java爬蟲(chóng)爬取漫畫(huà)示例

    Java爬蟲(chóng)爬取漫畫(huà)示例

    這篇文章主要介紹了Java爬蟲(chóng)爬取漫畫(huà)示例,大部分的爬蟲(chóng)入門(mén)教學(xué)都是爬取圖片的,本文就來(lái)測(cè)試一下爬取網(wǎng)站的漫畫(huà),需要的朋友可以參考下
    2023-04-04
  • IntelliJ IDEA中代碼一鍵生成方法

    IntelliJ IDEA中代碼一鍵生成方法

    EasyCode 是基于 IntelliJ IDEA 開(kāi)發(fā)的代碼生成插件,支持自定義任意模板(Java,html,js,xml),這篇文章主要介紹了IntelliJ IDEA中代碼一鍵生成方法,需要的朋友可以參考下
    2020-02-02
  • Java中覆蓋finalize()方法實(shí)例代碼

    Java中覆蓋finalize()方法實(shí)例代碼

    這篇文章主要介紹了Java中覆蓋finalize()方法實(shí)例代碼,分享了相關(guān)代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-02-02
  • 關(guān)于JFormDesigner的安裝及破姐超詳細(xì)教程

    關(guān)于JFormDesigner的安裝及破姐超詳細(xì)教程

    JFormDesigner是一種先進(jìn)的圖形用戶界面Swing?的設(shè)計(jì)工具(非開(kāi)源),具有一個(gè)獨(dú)立的開(kāi)發(fā)工具產(chǎn)品和基于不同開(kāi)發(fā)工具如Eclipse、NetBeans等的開(kāi)發(fā)插件,本文給大家介紹JFormDesigner安裝破解教程,感興趣的朋友一起看看吧
    2023-12-12
  • Spring @ExceptionHandler注解統(tǒng)一異常處理和獲取方法名

    Spring @ExceptionHandler注解統(tǒng)一異常處理和獲取方法名

    這篇文章主要介紹了Spring注解之@ExceptionHandler 統(tǒng)一異常處理和獲取方法名,在實(shí)際項(xiàng)目中,合理使用@ExceptionHandler能夠提高代碼的可維護(hù)性和用戶體驗(yàn),通過(guò)本文的解析和實(shí)踐,讀者可以更好地理解和掌握@ExceptionHandler的用法和原理
    2023-09-09
  • spring整合redis以及使用RedisTemplate的方法

    spring整合redis以及使用RedisTemplate的方法

    本篇文章主要介紹了spring整合redis以及使用RedisTemplate的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Java中三種零拷貝的實(shí)現(xiàn)示例以及對(duì)比詳解

    Java中三種零拷貝的實(shí)現(xiàn)示例以及對(duì)比詳解

    這篇文章主要介紹了Java中三種零拷貝的實(shí)現(xiàn)示例以及對(duì)比詳解,本文主要是介紹幾種零拷貝的實(shí)現(xiàn)示例,以及與最傳統(tǒng)的做一個(gè)對(duì)比,看看在效率上到底有多大的提升,需要的朋友可以參考下
    2023-12-12
  • Struts2 自定義下拉框Tag標(biāo)簽

    Struts2 自定義下拉框Tag標(biāo)簽

    這篇文章主要介紹了Struts2 自定義下拉框Tag標(biāo)簽的相關(guān)資料,需要的朋友可以參考下
    2016-02-02
  • Java Web中常用的分頁(yè)組件(Java端實(shí)現(xiàn))

    Java Web中常用的分頁(yè)組件(Java端實(shí)現(xiàn))

    本文通過(guò)使用場(chǎng)景分析給大家介紹了Java Web中常用的分頁(yè)組件(Java端實(shí)現(xiàn)),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧
    2017-05-05

最新評(píng)論

河曲县| 霍林郭勒市| 炉霍县| 安塞县| 枝江市| 仙游县| 新野县| 页游| 页游| 合江县| 竹溪县| 兰州市| 贵州省| 买车| 上栗县| 大化| 正阳县| 营山县| 五大连池市| 萍乡市| 黑水县| 蒲城县| 抚顺市| 辽宁省| 从江县| 纳雍县| 罗山县| 乐清市| 卢龙县| 南和县| 罗平县| 谢通门县| 二连浩特市| 双鸭山市| 南通市| 山东| 湘阴县| 漾濞| 龙州县| 延庆县| 宿迁市|