← Назад к вопросам

Какие знаешь стратегии Load Balancing?

2.0 Middle🔥 141 комментариев
#Docker, Kubernetes и DevOps#REST API и микросервисы

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Стратегии Load Balancing

Load Balancing (балансировка нагрузки) - критический компонент при масштабировании приложений. Распределяет входящие запросы между несколькими серверами.

1. Round Robin (Циклическое распределение)

Самый простой способ - запросы распределяются по кругу:

Запрос 1 -> Сервер 1
Запрос 2 -> Сервер 2
Запрос 3 -> Сервер 3
Запрос 4 -> Сервер 1
Запрос 5 -> Сервер 2
...

Реализация в Spring Cloud:

@Configuration
public class LoadBalancerConfig {
    @Bean
    public RestTemplate restTemplate(
            @LoadBalanced RestTemplateBuilder builder) {
        return builder.build();  // Использует Round Robin
    }
}

@Service
public class UserService {
    @Autowired
    private RestTemplate restTemplate;
    
    public User getUser(String id) {
        // Автоматически распределяется между инстансами USER-SERVICE
        return restTemplate.getForObject(
            "http://USER-SERVICE/users/" + id,
            User.class
        );
    }
}

Характеристики:

  • Плюсы: простая, справедливая
  • Минусы: не учитывает нагрузку на серверы
  • Когда использовать: все серверы одинаковые

2. Weighted Round Robin (Взвешенное распределение)

Некоторым серверам даётся больший вес:

Сервер 1 (вес 3) -> получает 3 запроса из 6
Сервер 2 (вес 2) -> получает 2 запроса из 6
Сервер 3 (вес 1) -> получает 1 запрос из 6

Конфигурация в Nginx:

upstream backend {
    server server1.example.com weight=3;
    server server2.example.com weight=2;
    server server3.example.com weight=1;
}

server {
    location / {
        proxy_pass http://backend;
    }
}

Когда использовать: разные серверы имеют разную мощность

3. Least Connections (Наименьше соединений)

Запрос идёт к серверу с минимальным количеством активных соединений:

Сервер 1: 5 соединений
Сервер 2: 2 соединения <- Новый запрос
Сервер 3: 8 соединений

Реализация (Nginx):

upstream backend {
    least_conn;
    server server1.example.com;
    server server2.example.com;
    server server3.example.com;
}

Когда использовать: долгоживущие соединения (WebSocket)

4. IP Hash (Привязка по IP)

Запросы от одного IP всегда идут на один сервер:

IP 192.168.1.1 -> hash() -> Сервер 1 (всегда)
IP 192.168.1.2 -> hash() -> Сервер 2 (всегда)
IP 192.168.1.1 -> hash() -> Сервер 1 (одинаков)

Nginx конфигурация:

upstream backend {
    ip_hash;
    server server1.example.com;
    server server2.example.com;
    server server3.example.com;
}

Плюсы:

  • Каждый клиент попадает на один сервер
  • Полезно для сессионных данных

Минусы:

  • Неравномерная нагрузка
  • При добавлении/удалении сервера - переоценка

Когда использовать: sticky sessions без shared cache

5. Least Response Time (Минимальное время ответа)

Запрос идёт к серверу с наименьшим временем ответа:

Сервер 1: avg response time = 50ms
Сервер 2: avg response time = 100ms <- ЗАНЯТ
Сервер 3: avg response time = 30ms <- Новый запрос

Nginx (требует módulo):

upstream backend {
    least_time last_byte;
    server server1.example.com;
    server server2.example.com;
    server server3.example.com;
}

Когда использовать: неоднородные серверы с разными

6. Random (Случайное распределение)

Запрос случайно направляется на один из серверов:

private List<Server> servers = Arrays.asList(
    new Server("server1"),
    new Server("server2"),
    new Server("server3")
);

public Server selectServer() {
    Random random = new Random();
    return servers.get(random.nextInt(servers.size()));
}

Nginx:

upstream backend {
    random;
    server server1.example.com;
    server server2.example.com;
}

Плюсы: простая, хорошо распределяет при случайных запросах Минусы: не учитывает состояние сервера

7. Consistent Hashing (Согласованное хеширование)

Используется для распределённых систем:

Ключ "user:123" -> hash() -> позиция на кольце

Кольцо (hash space):
     Server1 (hash=10)
   /            \
Server3        Server2
 (hash=80)     (hash=40)

"user:123" -> hash=50 -> nearest clockwise = Server2

Плюсы:

  • При добавлении сервера - минимально перехешируется
  • Идеально для кэширования

Когда использовать: распределённое кеширование (Redis), sharding БД

8. Session Affinity / Sticky Sessions

Сессия привязывается к одному серверу:

Запрос 1 (no cookie) -> Server1 (присваивает cookie с ID)
Запрос 2 (cookie=server1) -> Server1 (заходит на тот же)
Запрос 3 (cookie=server1) -> Server1

Spring Session решение (Shared Session Storage):

@Configuration
public class SessionConfig {
    @Bean
    public LettuceConnectionFactory connectionFactory() {
        return new LettuceConnectionFactory();
    }
}

// Конфигурация
spring.session.store-type=redis

Nginx Sticky Session:

upstream backend {
    server server1.example.com;
    server server2.example.com;
    
    sticky cookie srv_id expires=1h domain=.example.com path=/ secure httponly;
}

Минусы: снижает масштабируемость, нужен общий storage

9. Resource Based (На основе ресурсов)

Клиент выбирает сервер на основе доступных ресурсов:

public class ResourceBasedLoadBalancer {
    public Server selectServer(List<Server> servers) {
        return servers.stream()
            .min(Comparator.comparing(server -> 
                calculateLoad(server.getCpuUsage(), 
                             server.getMemoryUsage(),
                             server.getDiskSpace())
            ))
            .orElse(servers.get(0));
    }
    
    private double calculateLoad(double cpu, double memory, double disk) {
        return (cpu * 0.5) + (memory * 0.3) + (disk * 0.2);
    }
}

Когда использовать: гетерогенные серверы с разным железом

10. Geographic Load Balancing (Географическое)

Запросы направляются на ближайший сервер (по geography):

Пользователь в Москве -> московский data center
Пользователь в NY -> NY data center
Пользователь в Tokyo -> Tokyo data center

Реализация с DNSmasq:

# GeoDNS маршрутизирует на основе IP geo-локации

В Java через CDN:

// CloudFlare, AWS CloudFront автоматически handles

11. Сравнение стратегий

╔════════════════════════╦═══════════════════╦════════════════╦═══════════════╗
║ Стратегия              ║ Сложность         ║ Справедливость ║ Лучше всего   ║
╠════════════════════════╬═══════════════════╬════════════════╬═══════════════╣
║ Round Robin            ║ Низкая            ║ Хорошая        ║ Стандартная   ║
║ Weighted RR            ║ Низкая            ║ Отличная       ║ Разные мощ    ║
║ Least Connections      ║ Средняя           ║ Отличная       ║ WebSocket     ║
║ IP Hash                ║ Низкая            ║ Плохая         ║ Sticky session║
║ Least Response Time    ║ Средняя           ║ Отличная       ║ Динамическая  ║
║ Consistent Hashing     ║ Высокая           ║ Отличная       ║ Шардирование  ║
║ Resource Based         ║ Высокая           ║ Отличная       ║ Гетерогенные  ║
╚════════════════════════╩═══════════════════╩════════════════╩═══════════════╝

12. Health Check (Проверка здоровья)

Любой балансировщик должен проверять доступность сервера:

@Service
public class HealthCheckService {
    @Scheduled(fixedDelay = 5000)
    public void checkServerHealth() {
        for (Server server : servers) {
            try {
                ResponseEntity<HealthStatus> response = 
                    restTemplate.getForEntity(
                        server.getHealthUrl(),
                        HealthStatus.class
                    );
                
                server.setHealthy(response.getStatusCode().is2xxSuccessful());
            } catch (Exception e) {
                server.setHealthy(false);
            }
        }
    }
}

Nginx health check:

upstream backend {
    server server1.example.com;
    server server2.example.com;
    
    check interval=3000 rise=2 fall=5 timeout=1000 type=http;
    check_http_send "GET /health HTTP/1.0\r\n\r\n";
    check_http_expect_alive http_2xx;
}

13. Общие рекомендации

  • Простые случаи: Round Robin
  • HTTP запросы: Least Connections
  • Сессионные данные: Shared Storage + Round Robin (не IP Hash)
  • Кэширование: Consistent Hashing
  • Микросервисы: Spring Cloud Load Balancer (интеграция с Service Discovery)
  • Production: обязательно health checks
  • Масштабирование: используй с автоскейлингом

14. Spring Cloud LoadBalancer Example

@Configuration
public class LoadBalancerConfiguration {
    @Bean
    public LoadBalancerClient loadBalancerClient(
            ServiceInstanceListSupplier supplier) {
        return new BlockingLoadBalancerClient(
            new RoundRobinLoadBalancer(
                supplier,
                "USER-SERVICE"
            )
        );
    }
}
Какие знаешь стратегии Load Balancing? | PrepBro