5中负载均衡算法
本文最后更新于 308 天前,其中的信息可能已经有所发展或是发生改变。

轮询算法

轮询算法按顺序把每个新的连接请求分配给下一个服务器,最终把所有请求平分给所有的服务器。

优点

绝对公平

缺点

无法根据服务器性能去分配,无法合理利用服务器资源。

import com.google.common.collect.Lists;

import java.util.List;

public static void main(String[] args) {
    List<String> ips = Lists.newArrayList("192.168.1.1", "192.168.1.2", "192.168.1.3");
    Round<String> testRoundRobin = new Round<String>();
    for (int i = 0; i < 10; i++) {
        String s = testRoundRobin.roundRobin(ips);
        System.out.println(s);
    }
}


import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class Round<T> {

    private AtomicInteger index = new AtomicInteger(0);

    public <T> T roundRobin(List<T> data) {
        T t;
        if (index.get() >= data.size()) {
            index = new AtomicInteger(0);
        }
        t = data.get(index.get());
        //轮询+1
        index.getAndIncrement();
        return t;
    }
}

加权轮询法

该算法中,每个机器接受的连接数量是按权重比例分配的。这是对普通轮询算法的改进,

比如可以设定:第三台机器的处理能力是第一台机器的两倍,那么负载均衡器会把两倍的连接数量分配给第三台机器,轮询可以将请求顺序按照权重分配到后端。

优点

相较于轮询算法灵活度更高,并且相较于复杂的动态负载均衡算法,加权轮询实现起来相对简单,且具有很好的可预测性和稳定性。

缺点

相比于简单的轮询算法,加权轮询需要额外维护和计算节点权重,对系统开销有一定增加,尤其是在节点数量较多或权重频繁调整的情况下。

public void weightedPolling() throws NoSuchFieldException, IllegalAccessException {
    Weight testWeightRobin = new Weight();
    List<DbConfig> dbConfigList = new ArrayList<>();
    dbConfigList.add(new DbConfig("192.168.1.1", 1));
    dbConfigList.add(new DbConfig("192.168.1.2", 2));
    dbConfigList.add(new DbConfig("192.168.1.3", 4));
    for (int i = 0; i < 10; i++) {
        DbConfig server = (DbConfig) testWeightRobin.weightRobin(dbConfigList);
        System.out.println(server);
    }
}


import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author juiwi
 */
public class Weight<T> {

    private AtomicInteger index = new AtomicInteger(0);


    public List<T> getDataByWeight(List<T> data) throws NoSuchFieldException, IllegalAccessException {
        List<T> ips = new CopyOnWriteArrayList<T>();
        if (CollectionUtils.isEmpty(data)) {
            return data;
        }
        for (T t : data) {
            Field nameField = t.getClass().getDeclaredField("name");
            // setAccessible 实体中的属性是用private定义的,需要设置setAccessible 为true,才可以访问到对象
            nameField.setAccessible(true);
            // 获取属性值
            String name = (String) nameField.get(t);

            Field weightField = t.getClass().getDeclaredField("weight");
            // setAccessible 实体中的属性是用private定义的,需要设置setAccessible 为true,才可以访问到对象
            weightField.setAccessible(true);
            // 获取属性值
            Integer weight = (Integer) weightField.get(t);

            for (int ipCount = 0; ipCount < weight; ipCount++) {
                ips.add(t);
            }
        }
        return ips;
    }

    public T weightRobin(List<T> data) throws NoSuchFieldException, IllegalAccessException {
        List<T> list = this.getDataByWeight(data);
        if (index.get() >= list.size()) {
            index = new AtomicInteger(0);
        }
        T t = list.get(index.get());
        index.getAndIncrement();
        return t;
    }

}


import lombok.*;

/**
 * @author :juiwi
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DbConfig {

    private String name;

    private int weight;
}

加权随机法

加权随机法(Weighted Random Selection)是一种随机选择方法,它允许每个选项有不同的概率被选中,其中每个选项的概率与其所对应的权重成正比。这种随机选择的过程可以用于多种场合,比如在游戏中角色技能发动的概率分配、广告展示的频率分配、推荐系统的物品推荐等。

优点

  1. 灵活性:加权随机法可以根据实际情况灵活地调整各个选项被选中的概率,有助于实现个性化和定制化的服务。
  2. 公平性:在考虑个体特征或重要程度差异时,可以通过权重合理分配资源或机会,更符合实际需求。
  3. 高效性:在预先计算好累计权重的情况下,可以在常数时间内完成随机选择,效率较高。

缺点

  1. 权重设定主观性:权重的选择往往依赖于主观判断或历史数据分析,若权重设置不合理,可能导致最终结果偏离预期目标。
  2. 忽视动态变化:如果权重是固定的,当选项的实际重要性或可用性发生变化时,需要重新调整权重才能保证选择的有效性。
  3. 复杂度增加:在大规模数据集上,特别是当选项数目巨大且权重分布复杂时,维护和更新权重列表会增加一定的系统复杂性。
public void randomWeight() throws NoSuchFieldException, IllegalAccessException {
    RandomWeight<DbConfig> randomWeightRobin =new RandomWeight<DbConfig>();
    List<DbConfig> dbConfigList= new ArrayList<>();
    dbConfigList.add(new DbConfig("192.168.1.1", 1));
    dbConfigList.add(new DbConfig("192.168.1.2", 2));
    dbConfigList.add(new DbConfig("192.168.1.3", 4));
    for (int i =0;i< 10 ;i++){
        DbConfig server = randomWeightRobin.randomWeightRobin(dbConfigList);
        System.out.println(server);
    }
}


import java.lang.reflect.Field;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ThreadLocalRandom;

public class RandomWeight<T> {

    public <T> List<T> getDataByWeight(List<T> data) throws NoSuchFieldException, IllegalAccessException {
        List<T> ips = new CopyOnWriteArrayList<T>();
        for (T t : data) {
            Field nameField = t.getClass().getDeclaredField("name");
            // setAccessible 实体中的属性是用private定义的,需要设置setAccessible 为true,才可以访问到对象
            nameField.setAccessible(true);
            // 获取属性值
            String name = (String) nameField.get(t);

            Field weightField = t.getClass().getDeclaredField("weight");
            // setAccessible 实体中的属性是用private定义的,需要设置setAccessible 为true,才可以访问到对象
            weightField.setAccessible(true);
            // 获取属性值
            Integer weight = (Integer) weightField.get(t);
            // 根据权重不同,放入list 中的数量等同于权重,轮询出的的次数等同于权重
            for (int ipCount = 0; ipCount < weight; ipCount++) {
                ips.add(t);
            }
        }

        return ips;
    }

    public <T> T randomWeightRobin(List<T> data) throws NoSuchFieldException, IllegalAccessException {
        List<T> ips = this.getDataByWeight(data);
        //        //循环随机数
        //        Random random=new Random();
        //        int index =random.nextInt();
        int index = ThreadLocalRandom.current().nextInt(ips.size());
        T t = ips.get(index);
        return t;
    }
}

随机法

负载均衡中的随机法是一种简单的分配策略,它适用于将网络请求或其他负载均匀地分散到一组服务器上的场景。随机法的基本思想是,每当有新的请求到达时,负载均衡器根据一组服务器列表随机选择一个服务器来处理请求。选择哪个服务器是基于纯粹的随机概率,每个服务器被选中的概率理论上是相等的。

优点:

  1. 实现简单:随机算法实现起来较为直观和简洁,不需要额外的信息收集和复杂计算。
  2. 在长时间运行下,理论上可以达到平均意义上的负载均衡:由于随机性,随着请求次数的增加,每个服务器处理的请求数量趋于平衡。

缺点:

  1. 微观上的负载不均衡:在短期内,由于随机性,可能出现某些服务器连续被选中而暂时负载过高,其他服务器却闲置的情况。
  2. 不考虑服务器当前状态:随机法并未根据服务器的实时负载状况进行选择,因此无法有效处理服务器之间性能差异或瞬时负载不均的问题。
public void random() {
    Random<DbConfig> randomdRobin = new Random<DbConfig>();
    List<DbConfig> dbConfigList = new ArrayList<>();
    dbConfigList.add(new DbConfig("192.168.1.1", 1));
    dbConfigList.add(new DbConfig("192.168.1.2", 2));
    dbConfigList.add(new DbConfig("192.168.1.3", 4));
    for (int i = 0; i < 10; i++) {
        DbConfig dbConfig = randomdRobin.randomRobin(dbConfigList);
        System.out.println(dbConfig);
    }
}

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

public class Random<T> {

    public <T> T randomRobin(List<T> data) {
        int index = ThreadLocalRandom.current().nextInt(data.size());
        T t = data.get(index);
        return t;

    }
}

IP_Hash 法

负载均衡中的IP_Hash(也称为ip_hash)算法是一种特殊的负载均衡策略,它主要用于保持客户端与服务器之间的会话亲和性(Session Affinity),确保来自相同客户端IP地址的请求总是被转发到同一台后端服务器上处理。

工作原理: 当负载均衡器(如Nginx、HAProxy等)接收到一个客户端请求时,它首先提取客户端的IP地址,然后使用某种哈希函数对该IP地址进行计算,得到一个哈希值。接着,将这个哈希值与后端服务器池中的服务器数量进行取模运算,得出一个索引,指向后端服务器列表中的一个具体服务器。这样一来,相同IP地址的请求将始终被映射到同一台服务器上,从而维持了会话状态的一致性,这对于那些需要维持用户会话状态的应用程序非常重要,比如Web应用中需要保持用户登录状态或购物车信息的情况。

特点:

  • 会话保持:ip_hash算法可以有效保持客户端会话在同一服务器上处理,避免了会话状态在多服务器间共享的问题,减少了对分布式会话存储的需求。
  • 适用场景:特别适用于那些不支持分布式会话管理的应用,或者是由于性能、安全性或其他原因不适合在集群环境中共享会话的应用。
  • 局限性
  • 如果某台服务器宕机,原来被映射到该服务器的客户端IP将不能再被正常处理,除非有备用服务器机制或重新计算哈希映射。
  • 客户端IP地址改变(如用户切换网络环境或经过代理服务器)会导致请求被转发到不同的服务器,影响会话连续性。
  • 在大型集群中,由于哈希碰撞,可能存在少量IP被映射到同一服务器的风险,造成负载不均衡。
public void ipHash() {
    IpHash<DbConfig> ipHash =new IpHash<DbConfig>();
    List<DbConfig> dbConfigList= new ArrayList<>();
    dbConfigList.add(new DbConfig("192.168.1.1", 1));
    dbConfigList.add(new DbConfig("192.168.1.2", 2));
    dbConfigList.add(new DbConfig("192.168.1.3", 4));
    DbConfig dbConfig = ipHash.ipHashRobin(dbConfigList, "192.168.90.2");
    System.out.println(dbConfig.toString());
}


import java.util.List;

/**
 * @author juiwi
 */
public class IpHash<T> {

    /**
     * @param data
     * @param hashData
     * @param <T>
     * @return
     */
    public <T> T ipHashRobin(List<T> data, String hashData) {
        //        int hashCode = hashData.hashCode();
        //        int listSize = data.size();
        //        int index = hashCode % listSize;
        int index = hashData.hashCode() % data.size();
        T t = data.get(index);
        return t;
    }
}

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇