Сводка различных алгоритмов балансировки нагрузки

Балансировка нагрузки

Сводка различных алгоритмов балансировки нагрузки

случайный алгоритм

Сначала поместите сервер в массив или список, получите индекс в допустимом диапазоне массива с помощью случайного алгоритма JDK и получите доступ к соответствующему серверу в соответствии с этим случайным индексом. Из теории вероятности и статистики известно, что по мере того, как клиент обращается к серверу, фактический эффект становится все ближе и ближе к равномерному распределению запросов к каждому серверу в списке серверов.

Код:

 public String random(){
        String[] servers = {"server1", "server2", "server3"};
        // 将系统的当前时间作为种子获取一个随机器
        Random generator = new Random(System.currentTimeMillis());
        // 将服务器列表大小作为上界传入随机生成器
        int index = generator.nextInt(servers.length);
        return servers[index];
    }

Взвешенный случайный алгоритм

Если производительность обработки сервера высокая или низкая, в это время требуется взвешенный случайный алгоритм. Взвешенный случайный алгоритм также очень прост, в основном в двух формах:

Очень простой формой является увеличение количества серверов в списке серверов в соответствии с весом сервера. Например, вес сервера А равен 7, а вес сервера Б равен 3, то в список серверов добавляются 7 серверов А и 3 сервера Б. В это время, если выполняется случайный алгоритм, будет взвешенный эффект.

Код:

public String weightRandomA(){
        // 服务器列表
        String[] servers = {"serverA", "serverB"};
        // 权重
        int[] weights = {7, 3};
        
        List<String> weightServers = new ArrayList<>();
        // 根据权重大小往新的权重服务器列表里重复添加对应的服务器
        for (int i = 0; i < servers.length; i++) {
            for (int j = 0; j < weights[i]; j++) {
                weightServers.add(servers[i]);
            }
        }
        // 将系统的当前时间作为种子获取一个随机器
        Random generator = new Random(System.currentTimeMillis());
        // 将服务器列表大小作为上界传入随机生成器
        int index = generator.nextInt(weightServers.size());
        
        return weightServers.get(index);
    }

Однако и здесь есть проблема, то есть, если значение веса очень велико, список серверов весов будет слишком большим. Другая форма состоит в том, чтобы сложить все значения веса, а затем случайным образом извлечь серверы в соответствии с верхней границей случайного числа, основанного на общем значении веса. Например, вес сервера A равен 2, вес сервера B равен 3, а вес сервера C равен 5. Общее значение веса равно 10. Выберите случайное число из 10. Если случайное число находится в диапазоне от 0 до 2, выберите сервер A, если случайное число находится в диапазоне от 3 до 5, выберите сервер B, а если случайное число находится в диапазоне от 5 до 10, выберите сервер C.

Код:

  public String weightRandomB(){
        // 服务器列表
        String[] servers = {"serverA", "serverB","serverC"};
        // 权重
        int[] weights = {2, 3, 5};
        // 总权重
        int totalWeight = 0;
        
        // 计算总权重
        for (int weight : weights) {
            totalWeight += weight;
        }
        // 将系统的当前时间作为种子获取一个随机器
        Random generator = new Random(System.currentTimeMillis());
        // 将总权重作为上界传入随机生成器  获取一个临时随机权重值
        int randomWeight = generator.nextInt(totalWeight);
        // 服务器列表下标
        int index = 0;
        // 递减  随机权重值  如果小于0的话,代表落入对应区间。根据得到的下标寻找服务器。
        for (int i = 0; i < weights.length; i++) {
            randomWeight -= weights[i];
            if (randomWeight <= 0) {
                index = i;
                break;
            }
        }
        
        return servers[index];
    }

алгоритм опроса

Случайный алгоритм прост и выполним, но он недостаточно сбалансирован, в крайнем случае один сервер всегда будет получать запросы, а другой сервер никогда не будет получать запросы. Поэтому в настоящее время требуется алгоритм опроса. Это делается путем вызова серверов в списке серверов по порядку. Например, в списке серверов три сервера ABC и автоинкрементное число, после каждого автоинкремента берем остаток 3. Если 0, берем сервер А, если 1, берем сервер Б, и если это 2, берите сервер C.

Код:

public String roundRobin(){
        String[] servers = {"serverA", "serverB", "serverC"};
        // 用自增序列值 除 服务器列表的数量
        int currentIndex = serialNumber % servers.length;
        // 计算出此次服务器列表下标时,对自增序列+1
        //(当前使用类变量,实际开发可用Atomic原子变量)
        serialNumber++;
        return servers[currentIndex];
    }

Алгоритм обычного взвешенного кругового перебора

Если рассматривается производительность разных серверов, требуется взвешенный циклический алгоритм. Например, вес сервера A равен 5, вес сервера B равен 3, а вес сервера C равен 2. Добавляйте их в список серверов один за другим, в это время список серверов [A,A,A,A,A,B,B,B,C,C]. Алгоритм взвешенного циклического перебора может быть реализован путем поочередного опроса серверов в списке.

Код:

 public String weightRoundRobinA() {

        // 服务器列表
        String[] servers = {"serverA", "serverB","serverC"};
        // 权重
        int[] weights = {5, 3, 2};

        List<String> weightServers = new ArrayList<>();
        // 根据权重大小往新的权重服务器列表里重复添加对应的服务器
        for (int i = 0; i < servers.length; i++) {

            for (int j = 0; j < weights[i]; j++) {
                weightServers.add(servers[i]);
            }

        }

        // 用自增序列值 除 带权重服务器列表的数量
        int currentIndex = serialNumber % weightServers.size();
        // 计算出此次服务器列表下标时,对自增序列+1
        //(当前使用类变量,实际开发可用Atomic原子变量)
        serialNumber++;

        return weightServers.get(currentIndex);

    }

В этом алгоритме при большом значении веса список будет очень длинным, в это время можно брать и накапливать наибольший общий делитель всех значений веса, а когда он попадает в соответствующий интервал, соответствующий сервер могут быть приняты. Например, вес сервера A равен 10, вес сервера B равен 3, а вес сервера C равен 2. Возьмите общий делитель 2, используйте алгоритм только что и увеличивайте общий делитель 2 каждый раз, когда выполняется самоувеличивающаяся последовательность.

Гладкий взвешенный циклический алгоритм

Приведенный выше алгоритм взвешенного опроса приведет к постоянному вызову одного и того же сервера.В настоящее время распределение запросов очень неравномерно.Всегда необходимо непрерывно вызывать один и тот же сервер в соответствии со значением веса перед вызовом следующего сервера. В это время требуется плавный алгоритм взвешивания. Предположим, что вес конфигурации сервера A равен 7, вес конфигурации сервера B равен 2, а вес конфигурации сервера B равен 1. Общее значение веса равно 10. Планирование гладкого взвешенного циклического перебора выглядит следующим образом. Эффективный вес каждого сервера — это текущий вес, отличный от веса конфигурации, который рассчитывается на основе предыдущего раунда. В каждом раунде для выполнения запроса выбирается сервер с наибольшим весом. Выбранный узел, текущий эффективный вес минус значение общего веса. Эффективные веса всех серверов перед началом следующего раунда плюс их собственные настроенные веса.

  • Вес сервера А: 7
  • Вес сервера B: 2
  • Вес сервера C: 1
  • Общий вес: 10
  • Каждый сервер будет добавлять свой собственный вес конфигурации в каждом раунде.
Раунды сервер А сервер Б сервер С Текущий выбранный сервер (тот, у которого текущий максимальный вес)
первый раунд 7 2 1 A (текущий вес - общий вес = -3)
второй раунд 4 2 2 A (текущий вес - общий вес = -6)
третий раунд 1 6 3 B (текущий вес - общий вес = -4)
четвертый раунд 8 -2 4 A (текущий вес - общий вес = -2)
пятый раунд 5 0 5 A (текущий вес - общий вес = -5)
шестой раунд 2 2 6 C (текущий вес - общий вес = -4)
седьмой раунд 9 4 -3 A (текущий вес - общий вес = -1)
восьмой раунд 6 6 -2 A (текущий вес - общий вес = -4)
девятый раунд 3 8 -1 B (текущий вес - общий вес = -2)
десятый раунд 10 0 1 A (текущий вес - общий вес = 0)

Таким образом, не будет последовательных повторных обращений к одному и тому же серверу.

Код:

  public String smoothWeightRouncRobin() {

        // 服务器列表
        String[] servers = {"serverA", "serverB","serverC"};
        // 权重
        int[] weights = {7, 2, 1};
        // 总权重
        int totalWeight = 0;
        // 计算总权重
        for (int weight : weights) {
            totalWeight += weight;
        }

        int maxWeightIndex = 0;
        // currentWeights是一个类变量,保存三个服务器的当前权重
        // 寻找当前权重值最大的下标
        for (int i = 0; i < currentWeights.length; i++) {
            if (currentWeights[i] > currentWeights[maxWeightIndex]) {
                maxWeightIndex = i;
            }
        }

        // 当前权重最大者  要减去 总权重
        currentWeights[maxWeightIndex] = currentWeights[maxWeightIndex] - totalWeight;

        // 依次给每个服务器加上它的配置权重
        for (int i = 0; i < currentWeights.length; i++) {
            currentWeights[i] = currentWeights[i] + weights[i];
        }

        return servers[maxWeightIndex];

    }

хеш-алгоритм

IP-адрес или запрошенный URL-адрес можно использовать для хеширования, и запрос распространяется на соответствующий сервер.

Алгоритм минимальных соединений

Метод минимального количества подключений выполняет балансировку нагрузки в соответствии с текущим статусом подключения сервера.При поступлении запроса для обработки запроса будет выбран сервер с наименьшим количеством текущих подключений.

Перейдите на мой личный блог vc2x.com