Сводка различных алгоритмов балансировки нагрузки
случайный алгоритм
Сначала поместите сервер в массив или список, получите индекс в допустимом диапазоне массива с помощью случайного алгоритма 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-адрес можно использовать для хеширования, и запрос распространяется на соответствующий сервер.
Алгоритм минимальных соединений
Метод минимального количества подключений выполняет балансировку нагрузки в соответствии с текущим статусом подключения сервера.При поступлении запроса для обработки запроса будет выбран сервер с наименьшим количеством текущих подключений.