集群与负载均衡的算法与实现

前言:

     负载均衡是为了解决并发情况下,多个请求访问,把请求通过提前约定好的规则转发给各个server。其中有好几个种经典的算法。在用java代码编写这几种算法之前,先来了解一下负载均衡这个概念。

1.概念

    负载均衡,英文名称为Load Balance,指由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无须其他服务器的辅助。通过某种负载分担技术,将外部发送来的请求均匀分配到对称结构中的某一台服务器上,而接收到请求的服务器独立地回应客户的请求。负载均衡能够平均分配客户请求到服务器阵列,借此提供快速获取重要数据,解决大量并发访问服务问题,这种集群技术可以用最少的投资获得接近于大型主机的性能。

2.几种负载均衡算法简介

主要的负载均衡算法是图中这些,在代码实现之前,我们先简单回顾一下他们的概念。

轮询法:

   轮询算法按顺序把每个新的连接请求分配给下一个服务器,最终把所有请求平分给所有的服务器。既是每一次把来自用户的请求轮流分配给内部中的服务器,从1开始,直到N(内部服务器个数),然后重新开始循环。算法的优点是其简洁性,它无需记录当前所有连接的状态,所以它是一种无状态调度。

   优点:绝对公平

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

加权轮询法:

    该算法中,每个机器接受的连接数量是按权重比例分配的。这是对普通轮询算法的改进,比如你可以设定:第三台机器的处理能力是第一台机器的两倍,那么负载均衡器会把两倍的连接数量分配给第3台机器。加权轮询分为:简单的轮询、平滑的轮询。

     什么是平滑的轮询,就是把每个不同的服务,平均分布。在Nginx源码中,实现了一种叫做平滑的加权轮询(smooth weighted round-robin balancing)的算法,它生成的序列更加均匀。5个请求现在分散开来,不再是连续的。

随机法:

    负载均衡方法随机的把负载分配到各个可用的服务器上,通过随机数生成算法选取一个服务器。毕竟随机,,有效性受到了质疑。

加权随机法:

     获取带有权重的随机数字,随机这种东西,不能看绝对,只能看相对。

IP_Hash算法:

    hash(object)%N算法,通过一种散列算法把请求分配到不同的服务器上。

Source Hashing(源地址Hash)

源地址散列调度算法是一种静态映射算法,它通过一个散列(Hash)函数将一个源IP地址映射到一台服务器,若该服务器是可用的并且没有超负荷,将请求发送到该服务器,否则返回空。它采用的散列函数与目标地址散列调度算法的相同。它的算法流程与目标地址散列调度算法的基本相似,除了将请求的目标IP地址换成请求的源IP地址,所以这里不一个一个叙述。

Destination hashing(目标地址Hash)

目标地址散列调度算法也是针对目标IP地址的负载均衡,它是一种静态映射算法,通过一个散列(Hash)函数将一个目标IP地址映射到一台服务器。目标地址散列调度算法先根据请求的目标IP地址,作为散列键(Hash Key)从静态分配的散列表找出对应的服务器,若该服务器是可用的且未超载,将请求发送到该服务器,否则返回空。

Least-Connection(最少连接)

最少连接调度算法是把新的连接请求分配到当前连接数最小的服务器,最小连接调度是一种动态调度短算法,它通过服务器当前所活跃的连接数来估计服务器的负载均衡,调度器需要记录各个服务器已建立连接的数目,当一个请求被调度到某台服务器,其连接数加1,当连接中止或超时,其连接数减一,在系统实现时,我们也引入当服务器的权值为0时,表示该服务器不可用而不被调度。

3.Java代码实现负载均衡五种算法


  1)、轮训法

/**
 * Title:轮询
 * Description:
 *
 * @author Created by Julie
 * @version 1.0
 * @date on 15:49 2017/10/26
 */
package com.test.loadbalance;
 
 
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
 
 
public class TestRoundRobin {
 
 
 
    //    1.定义map, key-ip,value-weight
    static Map<String,Integer> ipMap=new HashMap<>();
    static {
        ipMap.put("192.168.13.1",1);
        ipMap.put("192.168.13.2",1);
        ipMap.put("192.168.13.3",1);
 
    }
 
//    Integer sum=0;
    Integer  pos = 0;
 
    public String RoundRobin(){
        Map<String,Integer> ipServerMap=new ConcurrentHashMap<>();
        ipServerMap.putAll(ipMap);
 
        //    2.取出来key,放到set中
        Set<String> ipset=ipServerMap.keySet();
 
        //    3.set放到list,要循环list取出
        ArrayList<String> iplist=new ArrayList<String>();
        iplist.addAll(ipset);
 
        String serverName=null;
 
        //    4.定义一个循环的值,如果大于set就从0开始
        synchronized(pos){
            if (pos>=ipset.size()){
                pos=0;
            }
            serverName=iplist.get(pos);
            //轮询+1
            pos ++;
        }
        return serverName;
 
    }
 
    public static void main(String[] args) {
        TestRoundRobin testRoundRobin=new TestRoundRobin();
        for (int i=0;i<10;i++){
            String serverIp=testRoundRobin.RoundRobin();
            System.out.println(serverIp);
        }
    }
 
}

  2)、加权轮询法

package com.test.loadbalance;
 
 
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
 
/**
 * Title:
 * Description:加权轮询
 *
 * @author Created by Julie
 * @version 1.0
 * @date on 18:05 2017/10/26
 */
public class TestWeightRobin {
    //    1.map, key-ip,value-weight
    static Map<String,Integer> ipMap=new HashMap<>();
    static {
        ipMap.put("192.168.13.1",1);
        ipMap.put("192.168.13.2",2);
        ipMap.put("192.168.13.3",4);
 
 
    }
    Integer pos=0;
    public String WeightRobin(){
        Map<String,Integer> ipServerMap=new ConcurrentHashMap<>();
        ipServerMap.putAll(ipMap);
 
        Set<String> ipSet=ipServerMap.keySet();
        Iterator<String> ipIterator=ipSet.iterator();
 
        //定义一个list放所有server
        ArrayList<String> ipArrayList=new ArrayList<String>();
 
        //循环set,根据set中的可以去得知map中的value,给list中添加对应数字的server数量
        while (ipIterator.hasNext()){
            String serverName=ipIterator.next();
            Integer weight=ipServerMap.get(serverName);
            for (int i = 0;i < weight ;i++){
                ipArrayList.add(serverName);
            }
        }
        String serverName=null;
        if (pos>=ipArrayList.size()){
            pos=0;
        }
        serverName=ipArrayList.get(pos);
        //轮询+1
        pos ++;
 
 
        return  serverName;
    }
 
    public static void main(String[] args) {
        TestWeightRobin testWeightRobin=new TestWeightRobin();
        for (int i =0;i<10;i++){
            String server=testWeightRobin.WeightRobin();
            System.out.println(server);
        }
 
 
    }
}

   3).随机法:

package com.test.loadbalance;
 
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
 
/**
 * Title:
 * Description:随机
 *
 * @author Created by Julie
 * @version 1.0
 * @date on 18:25 2017/10/26
 */
public class TestRandom {
    //    1.定义map, key-ip,value-weight
    static Map<String,Integer> ipMap=new HashMap<>();
    static {
        ipMap.put("192.168.13.1",1);
        ipMap.put("192.168.13.2",2);
        ipMap.put("192.168.13.3",4);
 
 
    }
    public String Random() {
        Map<String,Integer> ipServerMap=new ConcurrentHashMap<>();
        ipServerMap.putAll(ipMap);
 
        Set<String> ipSet=ipServerMap.keySet();
 
        //定义一个list放所有server
        ArrayList<String> ipArrayList=new ArrayList<String>();
        ipArrayList.addAll(ipSet);
 
        //循环随机数
        Random random=new Random();
        //随机数在list数量中取(1-list.size)
        int pos=random.nextInt(ipArrayList.size());
        String serverNameReturn= ipArrayList.get(pos);
        return  serverNameReturn;
    }
 
    public static void main(String[] args) {
        TestRandom testRandom=new TestRandom();
        for (int i =0;i<10;i++){
            String server=testRandom.Random();
            System.out.println(server);
        }
 
 
    }
}

  4)、加权随机:

package com.test.loadbalance;
 
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
 
/**
 * Title:
 * Description:加权随机
 *
 * @author Created by Julie
 * @version 1.0
 * @date on 18:42 2017/10/26
 */
public class TestRobinRandom {
 
    //    1.定义map, key-ip,value-weight
    static Map<String,Integer> ipMap=new HashMap<>();
    static {
        ipMap.put("192.168.13.1",1);
        ipMap.put("192.168.13.2",2);
        ipMap.put("192.168.13.3",4);
 
 
    }
    public String RobinRandom(){
        Map<String,Integer> ipServerMap=new ConcurrentHashMap<>();
        ipServerMap.putAll(ipMap);
 
        Set<String> ipSet=ipServerMap.keySet();
        Iterator<String> ipIterator=ipSet.iterator();
 
        //定义一个list放所有server
        ArrayList<String> ipArrayList=new ArrayList<String>();
 
        //循环set,根据set中的可以去得知map中的value,给list中添加对应数字的server数量
        while (ipIterator.hasNext()){
            String serverName=ipIterator.next();
            Integer weight=ipServerMap.get(serverName);
            for (int i=0;i<weight;i++){
                ipArrayList.add(serverName);
            }
        }
 
        //循环随机数
        Random random=new Random();
        //随机数在list数量中取(1-list.size)
        int pos=random.nextInt(ipArrayList.size());
        String serverNameReturn= ipArrayList.get(pos);
        return  serverNameReturn;
    }
 
    public static void main(String[] args) {
        TestRobinRandom testRobinRandom=new TestRobinRandom();
        for (int i =0;i<10;i++){
            String server=testRobinRandom.RobinRandom();
            System.out.println(server);
        }
 
 
    }
}

5)、IP_Hash算法:

package com.test.loadbalance;
 
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
 
/**
 * Title:
 * Description:
 *
 * @author Created by Julie
 * @version 1.0
 * @date on 18:35 2017/10/26
 */
public class ipHash {
    //    1.定义map, key-ip,value-weight
    static Map<String,Integer> ipMap=new HashMap<>();
    static {
        ipMap.put("192.168.13.1",1);
        ipMap.put("192.168.13.2",2);
        ipMap.put("192.168.13.3",4);
    }
    public String ipHash(String clientIP){
        Map<String,Integer> ipServerMap=new ConcurrentHashMap<>();
        ipServerMap.putAll(ipMap);
 
        //    2.取出来key,放到set中
        Set<String> ipset=ipServerMap.keySet();
 
        //    3.set放到list,要循环list取出
        ArrayList<String> iplist=new ArrayList<String>();
        iplist.addAll(ipset);
 
        //对ip的hashcode值取余数,每次都一样的
        int hashCode=clientIP.hashCode();
        int serverListsize=iplist.size();
        int pos=hashCode%serverListsize;
        return iplist.get(pos);
 
    }
 
    public static void main(String[] args) {
        ipHash iphash=new ipHash();
        String servername= iphash.ipHash("192.168.21.2");
        System.out.println(servername);
    }
 
}

转载:https://blog.csdn.net/zhou2s_101216/article/details/78358354 ,仅当笔记用,谢谢

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值