Java实现5种负载均衡算法

Java实现5种负载均衡算法

1. 轮询算法
import com.google.common.collect.Lists;

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

/**
 * 轮询算法
 * 轮询算法按顺序把每个新的连接请求分配给下一个服务器,最终把所有请求平分给所有的服务器。
 * 优点:绝对公平
 * 缺点:无法根据服务器性能去分配,无法合理利用服务器资源。
 * @author: 
 * @date: 2022-11-10 17:53
 */
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 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);
        }
    }
}
2. 加权轮询法
import com.collmall.shortlink.entity.DbConfig;
import org.springframework.util.CollectionUtils;

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

/**
 * 加权轮询法
 * 该算法中,每个机器接受的连接数量是按权重比例分配的。这是对普通轮询算法的改进,
 * 比如你可以设定:第三台机器的处理能力是第一台机器的两倍,那么负载均衡器会把两倍的连接数量分配给第3台机器,轮询可以将请求顺序按照权重分配到后端。
 * @author 
 * @date 2022年11月11日14:46:25
 */
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;
    }
  
    public static void main(String[] args) 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);
        }
    }
}
3. 加权随机法
import com.collmall.shortlink.entity.DbConfig;

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

/**
 * 加权随机法
 * 获取带有权重的随机数字,随机这种东西,不能看绝对,只能看相对,
 * 我们不用index 控制下标进行轮询,只用random 进行随机取ip,即实现算法。
 * @author 
 * @date 2022年11月14日11:37:20
 */
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;
    }

    public static void main(String[] args) 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);
        }

    }
}
4. 随机法
import com.collmall.shortlink.entity.DbConfig;

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

/**
 * 随机法
 * 负载均衡方法随机的把负载分配到各个可用的服务器上,通过随机数生成算法选取一个服务器,
 * 这种实现算法最简单,随之调用次数增大,这种算法可以达到每台服务器的请求量接近于平均。
 * @author 
 * @date  2022年11月14日13:46:24
 */
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;
 
    }
 
    public static void main(String[] args) {
        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);
        }
    }
}
5. IP_Hash 法
import com.collmall.shortlink.entity.DbConfig;

import java.util.ArrayList;
import java.util.List;

/**
 * IP_Hash算法
 * hash(ip)%N算法,通过一种散列算法把客户端来源IP根据散列取模算法将请求分配到不同的服务器上
 *
 * 优点:保证了相同客户端IP地址将会被哈希到同一台后端服务器,直到后端服务器列表变更。根据此特性可以在服务消费者与服务提供者之间建立有状态的session会话
 *
 * 缺点: 如果服务器进行了下线操作,源IP路由的服务器IP就会变成另外一台,如果服务器没有做session 共享话,会造成session丢失。
 * @author 
 * @date 2022年11月14日14:06:41
 */
public class IpHash<T> {


    /**
     *
     * @param data
     * @param hashData
     * @param 
     * @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;
 
    }
 
    public static void main(String[] args) {
        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.88.2");
        System.out.println(dbConfig.toString());
    }
}
6. 附录 DbConfig
public class DbConfig  {
    //id
    private Long id;
    //数据库名称
    private String name;
    //负载策略:1轮询算法 ,2 加权轮询法,3 加权随机法,4 随机法,5 IP_Hash算法
    private Integer loadPolicy;
    //权重: 只有 2 加权轮询法,3 加权随机法 才会用到
    private Integer weight;
    //是否删除:0 未删除,1是已删除
    private Integer isDeleted;
    //创建时间
    private Date cT;
    //更新时间
    private Date uT;


    public DbConfig(String name, Integer weight) {
        this.name = name;
        this.weight = weight;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getLoadPolicy() {
        return loadPolicy;
    }

    public void setLoadPolicy(Integer loadPolicy) {
        this.loadPolicy = loadPolicy;
    }

    public Integer getWeight() {
        return weight;
    }

    public void setWeight(Integer weight) {
        this.weight = weight;
    }

    public Integer getIsDeleted() {
        return isDeleted;
    }

    public void setIsDeleted(Integer isDeleted) {
        this.isDeleted = isDeleted;
    }

    public Date getCT() {
        return cT;
    }

    public void setCT(Date cT) {
        this.cT = cT;
    }

    public Date getUT() {
        return uT;
    }

    public void setUT(Date uT) {
        this.uT = uT;
    }

    /**
     * 获取主键值
     *
     * @return 主键值
     */
    @Override
    protected Serializable pkVal() {
        return this.id;
    }

    @Override
    public String toString() {
        return "DbConfig{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", loadPolicy=" + loadPolicy +
                ", weight=" + weight +
                ", isDeleted=" + isDeleted +
                ", cT=" + cT +
                ", uT=" + uT +
                '}';
    }
}

参考:

Java实现5种负载均衡算法(小结)_java_脚本之家 (jb51.net)

你可能感兴趣的:(java,java,算法,负载均衡)