负载均衡(干货版)

news/2024/7/10 3:07:02 标签: 负载均衡, java, 服务器
java">private static Map<String, Integer> serviceWeightMap = new HashMap<String, Integer>();
static {
    serviceWeightMap.put("192.168.1.100", 1);
    serviceWeightMap.put("192.168.1.101", 1);		 // 权重为4
    serviceWeightMap.put("192.168.1.102", 4);
    serviceWeightMap.put("192.168.1.103", 1);
    serviceWeightMap.put("192.168.1.104", 1);        // 权重为3
    serviceWeightMap.put("192.168.1.105", 3);
    serviceWeightMap.put("192.168.1.106", 1);        // 权重为2
    serviceWeightMap.put("192.168.1.107", 2);
    serviceWeightMap.put("192.168.1.108", 1);
    serviceWeightMap.put("192.168.1.109", 1);
    serviceWeightMap.put("192.168.1.110", 1);
}

一、轮询法(Round Robin)

对所有的服务器节点全部按顺序来,将请求按照顺序轮流地分配到各个服务器上,所以适合用于服务器硬件条件基本都相同的情况

java">private static Integer pos = 0;
 
public static String testRoundRobin() {   
    // 重新创建一个map,避免出现由于服务器上线和下线导致的并发问题
    Map<String, Integer> serverMap = new HashMap<String, Integer>();
    serverMap.putAll(serviceWeightMap);
     
    // 取得 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;
}

由于 serviceWeightMap 中的地址列表是动态的,随时可能由机器上线、下线或者宕机,因此,为了避免可能出现的并发问题,比如数组越界,通过在方法内新建局部变量 serverMap, 先将域变量拷贝到线程本地,避免被其他线程修改。这样可能会引入新的问题,当被拷贝之后,serviceWeightMap 的修改将无法被 serverMap 感知,也就是说, 在这一轮的选择服务器中,新增服务器或者下线服务器负载均衡算法中将无法获知。新增比较好处理,而当服务器下线或者宕机时,服务消费者将有可能访问不到不存在的地址。 因此,在服务消费者服务端需要考虑该问题,并且进行相应的容错处理,比如重新发起一次调用

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

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

二、加权轮询法(Weight Robin)

那么加权轮询算法无疑就是对各个服务器有了"高低贵贱之分",没办法,服务器的吃力水平不同,只能让那些强悍的机器优先并多处理一些请求,比较弱的机器就让它稍稍压力小一点

java">public 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;
    }
}

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

三、随机法(Random)

随机算法也是一种使用场景比较多的负载均衡算法,这种算法基本思想也是很简单的,随机生成一个数字(或者随机挑一个IP地址)出来,然后挑到谁就是谁,当然, 如果随机数是等概况生成的,那时间长了,基本上跟轮询算法没有什么区别,区别最主要的还是在顺序上,随机算法没有那么严格的顺序

java">public 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);
    }
}

四、加权随机法(Weight Random)

加权随机算法是在随机算法的基础上加了加权的条件,随机法时间长了,基本上跟一般轮询算法就没啥区别了,刚才也说到了,如果服务器的配置都差不多, 可以分配差不多的任务,但是如果服务器吃力能力差异比较大,那水平高的和水平低的服务器都给那么多任务,对于高配置的服务器来说就是有点浪费了, 对于低配置的服务器来说就有点吃不消,所以在这种配置差异性比较大的情况下,加权的工作还是必要的

java">public 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)

那个服务器的连接数少,就分配给哪个服务器新的请求,合情合理,这种算法的缺点就是,当一个比较弱的服务器和一个比较彪悍的服务器,本来就是前者连接的要少, 后者要大,如果非要谁的少新请求分配给谁的话,那就是弱服务器的连接要等于强服务器的连接,无疑这样会让弱服务器吃不消,或者造成强服务器的浪费, 所以这里还可以使用加权的方法解决这样的问题------加权最小连接法

六、源地址哈希法(Hash)

源地址哈希法可以把客户端的 IP 地址拿出来,然后计算出 IP 地址的 hash 值,根据 hash 值映射到服务器

java">public 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地址将会被哈希到同一台后端服务器,直到后端服务器列表变更。根据此特性可以在服务消费者与服务提供者之间建立有状态的 session 会话

源地址哈希算法的缺点在于:除非集群中服务器的非常稳定,基本不会上下线,否则一旦有服务器上线、下线,那么通过源地址哈希算法路由到的服务器服务器上线、下线前路由到的服务器的概率非常低,如果是 session 则取不到 session,如果是缓存则可能引发 “雪崩”


http://www.niftyadmin.cn/n/18350.html

相关文章

GitLab创建新分支并同步其它分支的内容(IDEA)

拉取项目到本地 选择对应项目并复制clone地址 打开IDEA&#xff0c;选择File–》New–》Project from Version Control 在弹出的对话框中粘贴刚才复制的地址 完成后项目就被拉取到本地对应目录中了 创建新分支 这里以master分支为例&#xff0c;其它分支同理 首先在GitL…

计网理论模拟

一. 单选题&#xff08;共10 题&#xff0c;20.0分&#xff09; 1. (单选题,2.0分)网络协议主要由 3 个基本要素组成&#xff0c;即&#xff08; &#xff09; A. 层次、语义和同步B. 语法、原语和同步C. 语法、语义和同步D. 语法、语义和功能 正确答案: C 2. (单选题,2.0分…

J-004 Jetson电路设计之HDMI设计--NANO XAVIER NX

HDMI电路设计1 简介2 框图介绍3 原理图介绍1 简介 NANO & XAVIER NX提供一路HDMI接口&#xff0c;DP接口与HDMI是兼容的&#xff0c;可用于扩展一路HDMI。其中引脚说明: PIN名称描述方向类型63HDMI_DP_TXDN0DisplayPort 1 Lane 0 or HDMI Lane 2输出HDMI/DP65HDMI_DP_TXD…

蓝牙HID基础知识

蓝牙HID基础知识 一&#xff1a;定义 HID是Human Interface Device的缩写&#xff0c;由其名称可以了解HID设备是直接与人交互的设备&#xff0c;例如键盘、鼠标与游戏手柄等。 蓝牙HID 是属于蓝牙协议里面的一个profile, 不管在蓝牙2.0 2.1 3.0还是4.0&#xff0c;5.0的蓝牙中…

目标检测论文解读复现【NO.21】基于改进YOLOv7的小目标检测

前言 此前出了目标改进算法专栏&#xff0c;但是对于应用于什么场景&#xff0c;需要什么改进方法对应与自己的应用场景有效果&#xff0c;并且多少改进点能发什么水平的文章&#xff0c;为解决大家的困惑&#xff0c;此系列文章旨在给大家解读最新目标检测算法论文&#xff0…

基于FPGA的PWM发生器设计

目录 引言 设计说明 设计特点 设计思路 设计源码 整数除法模块

智能遥测终端机——微功耗设计的物联网网关

一、产品概述 智能遥测终端机是一款采用微功耗设计的物联网网关&#xff0c;采用内置电池组供电&#xff0c;支持对模拟量、开关量、RS485传感器采集并通过NB-IoT或4G通讯方式传输数据。智能遥测终端机支持参数远程升级、远程配置、蓝牙配置等&#xff0c;智能遥测终端机集成高…

基于Java毕业设计校园讲座管理源码+系统+mysql+lw文档+部署软件

基于Java毕业设计校园讲座管理源码系统mysqllw文档部署软件 基于Java毕业设计校园讲座管理源码系统mysqllw文档部署软件本源码技术栈&#xff1a; 项目架构&#xff1a;B/S架构 开发语言&#xff1a;Java语言 开发软件&#xff1a;idea eclipse 前端技术&#xff1a;Layui、…