多种负载均衡算法及其Java代码实现

首先给大家介绍下什么是负载均衡(来自百科)

负载均衡 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展 网络设备和 服务器的带宽、增加 吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。

负载均衡,英文名称为Load Balance,其意思就是分摊到多个操作单元上进行执行,例如Web 服务器、 FTP服务器、 企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。

本文讲述的是”将外部发送来的请求均匀分配到对称结构中的某一台服务器上”的各种算法,并以Java代码演示每种算法的具体实现,OK,下面进入正题,在进入正题前,先写一个类来模拟Ip列表:

import java.util.HashMap;

/**  * @author ashang.peng@aliyun.com  * @date 二月 07, 2017  */

public class IpMap   {
    // 待路由的Ip列表,Key代表Ip,Value代表该Ip的权重
    public static HashMap<String, Integer> serverWeightMap =
            new HashMap<String, Integer>();

    static
    {
        serverWeightMap.put("192.168.1.100", 1);
        serverWeightMap.put("192.168.1.101", 1);
        // 权重为4
        serverWeightMap.put("192.168.1.102", 4);
        serverWeightMap.put("192.168.1.103", 1);
        serverWeightMap.put("192.168.1.104", 1);
        // 权重为3
        serverWeightMap.put("192.168.1.105", 3);
        serverWeightMap.put("192.168.1.106", 1);
        // 权重为2
        serverWeightMap.put("192.168.1.107", 2);
        serverWeightMap.put("192.168.1.108", 1);
        serverWeightMap.put("192.168.1.109", 1);
        serverWeightMap.put("192.168.1.110", 1);
    }
}

轮询(Round Robin)法

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

其代码实现大致如下:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**  * @author ashang.peng@aliyun.com  * @date 二月 07, 2017  */

class RoundRobin   {
    private static Integer pos = 0;

    public static String getServer()
    {
        // 重建一个Map,避免服务器的上下线导致的并发问题
        Map<String, Integer> serverMap =
                new HashMap<String, Integer>();
        serverMap.putAll(IpMap.serverWeightMap);

        // 取得Ip地址List
        Set<String> keySet = serverMap.keySet();
        ArrayList<String> keyList = new ArrayList<String>();
        keyList.addAll(keySet);

        String server = null;
        synchronized (pos)
        {
            if (pos > keySet.size())
                pos = 0;
            server = keyList.get(pos);
            pos ++;
        }

        return server;
    }
}

由于serverWeightMap中的地址列表是动态的,随时可能有机器上线、下线或者宕机,因此为了避免可能出现的并发问题,方法内部要新建局部变量serverMap,现将serverMap中的内容复制到线程本地,以避免被多个线程修改。这样可能会引入新的问题,复制以后serverWeightMap的修改无法反映给serverMap,也就是说这一轮选择服务器的过程中,新增服务器或者下线服务器,负载均衡算法将无法获知。新增无所谓,如果有服务器下线或者宕机,那么可能会访问到不存在的地址。因此,服务调用端需要有相应的容错处理,比如重新发起一次server选择并调用。

对于当前轮询的位置变量pos,为了保证服务器选择的顺序性,需要在操作时对其加锁,使得同一时刻只能有一个线程可以修改pos的值,否则当pos变量被并发修改,则无法保证服务器选择的顺序性,甚至有可能导致keyList数组越界。

轮询法的优点在于:试图做到请求转移的绝对均衡。

轮询法的缺点在于:为了做到请求转移的绝对均衡,必须付出相当大的代价,因为为了保证pos变量修改的互斥性,需要引入重量级的悲观锁synchronized,这将会导致该段轮询代码的并发吞吐量发生明显的下降。

随机(Random)法

通过系统的随机算法,根据后端服务器的列表大小值来随机选取其中的一台服务器进行访问。由概率统计理论可以得知,随着客户端调用服务端的次数增多,

其实际效果越来越接近于平均分配调用量到后端的每一台服务器,也就是轮询的结果。

随机法的代码实现大致如下:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**  * @author ashang.peng@aliyun.com  * @date 二月 07, 2017  */

 class Random   {
    public static String getServer()
    {
        // 重建一个Map,避免服务器的上下线导致的并发问题
        Map<String, Integer> serverMap =
                new HashMap<String, Integer>();
        serverMap.putAll(IpMap.serverWeightMap);

        // 取得Ip地址List
        Set<String> keySet = serverMap.keySet();
        ArrayList<String> keyList = new ArrayList<String>();
        keyList.addAll(keySet);

        java.util.Random random = new java.util.Random();
        int randomPos = random.nextInt(keyList.size());

        return keyList.get(randomPos);
    }
}

整体代码思路和轮询法一致,先重建serverMap,再获取到server列表。在选取server的时候,通过Random的nextInt方法取0~keyList.size()区间的一个随机值,从而从服务器列表中随机获取到一台服务器地址进行返回。基于概率统计的理论,吞吐量越大,随机算法的效果越接近于轮询算法的效果。

源地址哈希(Hash)法

源地址哈希的思想是根据获取客户端的IP地址,通过哈希函数计算得到的一个数值,用该数值对服务器列表的大小进行取模运算,得到的结果便是客服端要访问服务器的序号。采用源地址哈希法进行负载均衡,同一IP地址的客户端,当后端服务器列表不变时,它每次都会映射到同一台后端服务器进行访问。

源地址哈希算法的代码实现大致如下:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**  * @author ashang.peng@aliyun.com  * @date 二月 07, 2017  */

 class Hash      {
    public static String getServer()
    {
        // 重建一个Map,避免服务器的上下线导致的并发问题
        Map<String, Integer> serverMap =
                new HashMap<String, Integer>();
        serverMap.putAll(IpMap.serverWeightMap);

        // 取得Ip地址List
        Set<String> keySet = serverMap.keySet();
        ArrayList<String> keyList = new ArrayList<String>();
        keyList.addAll(keySet);

        // 在Web应用中可通过HttpServlet的getRemoteIp方法获取
        String remoteIp = "127.0.0.1";
        int hashCode = remoteIp.hashCode();
        int serverListSize = keyList.size();
        int serverPos = hashCode % serverListSize;

        return keyList.get(serverPos);
    }
}

前两部分和轮询法、随机法一样就不说了,差别在于路由选择部分。通过客户端的ip也就是remoteIp,取得它的Hash值,对服务器列表的大小取模,结果便是选用的服务器在服务器列表中的索引值。

源地址哈希法的优点在于:保证了相同客户端IP地址将会被哈希到同一台后端服务器,直到后端服务器列表变更。根据此特性可以在服务消费者与服务提供者之间建立有状态的session会话。

源地址哈希算法的缺点在于:除非集群中服务器的非常稳定,基本不会上下线,否则一旦有服务器上线、下线,那么通过源地址哈希算法路由到的服务器是服务器上线、下线前路由到的服务器的概率非常低,如果是session则取不到session,如果是缓存则可能引发”雪崩”。如果这么解释不适合明白,可以看我之前的一篇文章MemCache超详细解读,一致性Hash算法部分。

加权轮询(Weight Round Robin)法

不同的后端服务器可能机器的配置和当前系统的负载并不相同,因此它们的抗压能力也不相同。给配置高、负载低的机器配置更高的权重,让其处理更多的请;而配置低、负载高的机器,给其分配较低的权重,降低其系统负载,加权轮询能很好地处理这一问题,并将请求顺序且按照权重分配到后端。加权轮询法的代码实现大致如下:

import java.util.*;

/**  * @author ashang.peng@aliyun.com  * @date 二月 07, 2017  */
class WeightRoundRobin   {
    private static Integer pos;

    public static String getServer()
    {
        // 重建一个Map,避免服务器的上下线导致的并发问题
        Map<String, Integer> serverMap =
                new HashMap<String, Integer>();
        serverMap.putAll(IpMap.serverWeightMap);

        // 取得Ip地址List
        Set<String> keySet = serverMap.keySet();
        Iterator<String> iterator = keySet.iterator();

        List<String> serverList = new ArrayList<String>();
        while (iterator.hasNext())
        {
            String server = iterator.next();
            int weight = serverMap.get(server);
            for (int i = 0; i < weight; i++)
                serverList.add(server);
        }

        String server = null;
        synchronized (pos)
        {
            if (pos > keySet.size())
                pos = 0;
            server = serverList.get(pos);
            pos ++;
        }

        return server;
    }
}

与轮询法类似,只是在获取服务器地址之前增加了一段权重计算的代码,根据权重的大小,将地址重复地增加到服务器地址列表中,权重越大,该服务器每轮所获得的请求数量越多。

加权随机(Weight Random)法

与加权轮询法一样,加权随机法也根据后端机器的配置,系统的负载分配不同的权重。不同的是,它是按照权重随机请求后端服务器,而非顺序。

import java.util.*;

/**  * @author ashang.peng@aliyun.com  * @date 二月 07, 2017  */

 class WeightRandom   {
    public static String getServer()
    {
        // 重建一个Map,避免服务器的上下线导致的并发问题
        Map<String, Integer> serverMap =
                new HashMap<String, Integer>();
        serverMap.putAll(IpMap.serverWeightMap);

        // 取得Ip地址List
        Set<String> keySet = serverMap.keySet();
        Iterator<String> iterator = keySet.iterator();

        List<String> serverList = new ArrayList<String>();
        while (iterator.hasNext())
        {
            String server = iterator.next();
            int weight = serverMap.get(server);
            for (int i = 0; i < weight; i++)
                serverList.add(server);
        }

        java.util.Random random = new java.util.Random();
        int randomPos = random.nextInt(serverList.size());

        return serverList.get(randomPos);
    }
}

这段代码相当于是随机法和加权轮询法的结合,比较好理解,就不解释了。

最小连接数(Least Connections)法

最小连接数算法比较灵活和智能,由于后端服务器的配置不尽相同,对于请求的处理有快有慢,它是根据后端服务器当前的连接情况,动态地选取其中当前

积压连接数最少的一台服务器来处理当前的请求,尽可能地提高后端服务的利用效率,将负责合理地分流到每一台服务器。

前面几种方法费尽心思来实现服务消费者请求次数分配的均衡,当然这么做是没错的,可以为后端的多台服务器平均分配工作量,最大程度地提高服务器的利用率,但是实际情况是否真的如此?实际情况中,请求次数的均衡真的能代表负载的均衡吗?这是一个值得思考的问题。

上面的问题,再换一个角度来说就是:以后端服务器的视角来观察系统的负载,而非请求发起方来观察。最小连接数法便属于此类。

最小连接数算法比较灵活和智能,由于后端服务器的配置不尽相同,对于请求的处理有快有慢,它正是根据后端服务器当前的连接情况,动态地选取其中当前积压连接数最少的一台服务器来处理当前请求,尽可能地提高后端服务器的利用效率,将负载合理地分流到每一台机器。由于最小连接数设计服务器连接数的汇总和感知,设计与实现较为繁琐,此处就不说它的实现了。

来源:51CTO

时间: 2025-01-21 18:00:16

多种负载均衡算法及其Java代码实现的相关文章

多种负载均衡算法及其 Java 代码实现

首先给大家介绍下什么是负载均衡(来自百科) 负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展 网络设备和 服务器的带宽.增加 吞吐量.加强网络数据处理能力.提高网络的灵活性和可用性. 负载均衡,英文名称为Load Balance,其意思就是分摊到多个操作单元上进行执行,例如Web 服务器. FTP服务器. 企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务. 本文讲述的是"将外部发送来的请求均匀分配到对称结构中的某一台服务器上"的各种算法,并以Java代码

【转载】对一致性Hash算法,Java代码实现的深入研究

原文地址:http://www.cnblogs.com/xrq730/p/5186728.html   一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读一文中"一致性Hash算法"部分,对于为什么要使用一致性Hash算法.一致性Hash算法的算法原理做了详细的解读. 算法的具体原理这里再次贴上: 先构造一个长度为232的整数环(这个环被称为一致性Hash环),根据节点名称的Hash值(其分布为[0, 232-1])将服务器节点放置

求计算OTN网络负载均衡问题的JAVA程序

问题描述 求计算OTN网络负载均衡问题的JAVA程序 JAVA新手一只,最近想搭OTN的台子计算网络均衡问题,想找个程序好好学学,求高手帮忙,万分感谢~ 解决方案 http://www.cnki.com.cn/Article/CJFDTotal-KJTB201308039.htm 解决方案二: 谢谢 不过有没有现成的程序?我想看看该怎么写

Nginx几种负载均衡算法及配置实例

Nginx负载均衡(工作在七层"应用层")功能主要是通过upstream模块实现,Nginx负载均衡默认对后端服务器有健康检测的能力,仅限于端口检测,在后端服务器比较少的情况下负载均衡能力表现突出. Nginx的几种负载均衡算法: 1.轮询(默认):每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某台服务器宕机,则自动剔除故障机器,使用户访问不受影响. 2.weight:指定轮询权重,weight值越大,分配到的几率就越高,主要用于后端每台服务器性能不均衡的情况. 3.ip_ha

云计算环境下的负载均衡算法的研究与设计

云计算环境下的负载均衡算法的研究与设计 北京邮电大学  冯秀玲 本文研究了云计算及集群的负载均衡机制和算法,提出了云计算环境下的集群负载均衡问题,并且基于两种不同的云计算场景:私有云和公有云,分别设计了两种不同的算法,对集中式和分布式的负载均衡算法进行了相应的改进,本文的主要内容包括: 第一,分析对比现有集中式算法的性能优劣,着重对典型的算法. 第二,研究分析现有的分布式负载均衡算法,并针对文献中随机游走算法的低效和不足问题进行了改进,改进后的分组随机游走算法属于分布式的,适合使用在公有云环境中

云存储系统中动态负载均衡算法研究

云存储系统中动态负载均衡算法研究 田浪军 陈卫卫 陈卫东 李涛 针对分布式哈希表(DHT)云存储系统中的存储负载不均问题,提出一种基于节点动态前移(NDF)的负载均衡算法.通过过载节点动态前移,缩小节点存储分区,进而降低节点的存储负载.同时,过载节点向第3个后继节点复制相关数据,保证系统中数据的副本数量稳定.在NDF算法执行过程中,只需过载节点与第3个后继节点进行简单协调,多个过载节点可以并发地进行负载转移,适合在大规模集群中部署. 云存储系统中动态负载均衡算法研究

java c# sign-签名算法,java代码转为 C#

问题描述 签名算法,java代码转为 C# 请帮忙把如下的java签名算法转换为c#的,牛人伸手啊!! 具体代码如下: public static String genSignature(String sk, String stringToSign) { String signature = ""; try { String encodedSign = URLEncoder.encode(stringToSign, ENCODING); try { Mac mac = Mac.getI

Weblogic的HttpClusterServlet如何配置负载均衡算法

问题描述 如题,按照各种教程贴部署了HttpClusterServlet,并且经过测试发现其默认情况下基本上把请求平均分配到各个节点.希望通过例如按权重分配的算法来分配,请问各位大神,这是否能够用HttpClusterServlet做到,该如何操作?求赐教 解决方案 解决方案二:WeightBasedReplicaHandler.javaRichReplicaList.javaprotectedRemoteReferencechooseReplica(RemoteReferenceremoter

基于第四层交换技术的负载均衡

摘 要 本文介绍了第四层交换技术的概念,技术原理以及如何使用第四层交换技术实现远程教育系统中的应用服务器负载均衡. 1 引言 当今世界已经步入信息时代,随着社会的迅速发展以及人们对网络应用需求的不断提高,对网络速度及带宽的要求不断上升.正是在这样的发展形势下,许多高速交换的新技术不断涌现.第二层交换实现局域网内主机间的快速信息交流,第三层交换可以说是交换技术与路由技术的完美结合,而下文要详细介绍的第四层交换技术则可以为网络应用资源提供最优分配,实现应用服务的负载均衡. 2 第四层交换技术 2.1