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

Как настраивал балансировщик

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

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

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

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

Как настраивал балансировщик

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

Уровни балансировки

  1. L4 (Transport Layer) — балансировка на уровне TCP/UDP
  2. L7 (Application Layer) — балансировка на уровне HTTP/HTTPS
  3. Client-side — балансировка на клиенте (microservices)

1. Nginx как L7 Load Balancer

Наиболее популярный выбор для веб-приложений:

http {
    # Определение upstream группы серверов
    upstream backend_servers {
        # Round-robin (по умолчанию)
        server backend1.example.com:8080;
        server backend2.example.com:8080;
        server backend3.example.com:8080;
    }
    
    server {
        listen 80;
        server_name api.example.com;
        
        location / {
            proxy_pass http://backend_servers;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            
            # Timeout конфигурация
            proxy_connect_timeout 5s;
            proxy_send_timeout 10s;
            proxy_read_timeout 10s;
        }
    }
}

2. Стратегии распределения нагрузки

Round-Robin (по кругу):

upstream backend {
    # Запросы циклически распределяются
    server backend1:8080;
    server backend2:8080;
    server backend3:8080;
}

Weighted Round-Robin (взвешенный):

upstream backend {
    # backend1 получает 3 запроса на каждый запрос к backend2
    server backend1:8080 weight=3;
    server backend2:8080 weight=1;
}

Least Connections (минимум соединений):

upstream backend {
    least_conn;  # Запрос идёт на сервер с наименьшим числом активных соединений
    server backend1:8080;
    server backend2:8080;
    server backend3:8080;
}

IP Hash (по IP клиента):

upstream backend {
    ip_hash;  # Один клиент всегда попадает на один сервер (sticky session)
    server backend1:8080;
    server backend2:8080;
    server backend3:8080;
}

Hash (по кастомному ключу):

upstream backend {
    hash $request_uri consistent;  # Запросы к одному URI идут на один сервер
    server backend1:8080;
    server backend2:8080;
}

3. Health Checks

Проверка доступности серверов:

http {
    upstream backend {
        server backend1:8080 max_fails=3 fail_timeout=30s;
        server backend2:8080 max_fails=3 fail_timeout=30s;
        server backend3:8080 max_fails=3 fail_timeout=30s;
    }
    
    # Активная проверка здоровья (Nginx Plus только)
    upstream backend_with_health {
        zone backend 64k;
        server backend1:8080;
        server backend2:8080;
        server backend3:8080;
    }
}

4. Spring Cloud LoadBalancer (Client-side)

Для микросервисов в Java:

@Configuration
public class LoadBalancerConfig {
    // Spring Boot автоматически регистрирует в Eureka/Consul
}

@Service
public class UserServiceClient {
    private final RestTemplate restTemplate;
    
    public UserServiceClient(RestTemplateBuilder builder) {
        // LoadBalancerClient автоматически балансирует
        this.restTemplate = builder.build();
    }
    
    public User getUser(Long id) {
        // Запрос с автоматической балансировкой
        return restTemplate.getForObject(
            "http://user-service/users/" + id,
            User.class
        );
    }
}

5. Ribbon (Legacy Load Balancer)

Для старых версий Spring Cloud:

@Configuration
public class RibbonConfig {
    @Bean
    public IRule ribbonRule() {
        // Стратегии: RoundRobinRule, WeightedResponseTimeRule, etc.
        return new RoundRobinRule();
    }
}

@Service
public class ApiClient {
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

6. Feign с Load Balancer

Декларативный клиент с автоматической балансировкой:

@FeignClient(name = "user-service")
public interface UserServiceFeignClient {
    @GetMapping("/users/{id}")
    User getUser(@PathVariable Long id);
}

@Service
public class UserService {
    @Autowired
    private UserServiceFeignClient client;
    
    public User getUser(Long id) {
        // Запрос автоматически балансируется
        return client.getUser(id);
    }
}

7. AWS Load Balancer (ALB/NLB)

Для облачных развёртываний:

# CloudFormation / Terraform
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  ApplicationLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: my-alb
      Subnets:
        - subnet-12345678
        - subnet-87654321
      SecurityGroups:
        - sg-12345678
      Scheme: internet-facing
      Type: application
  
  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: backend-targets
      Port: 8080
      Protocol: HTTP
      VpcId: vpc-12345678
      TargetType: instance
      HealthCheckProtocol: HTTP
      HealthCheckPath: /health
      HealthCheckIntervalSeconds: 30
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 2
      UnhealthyThresholdCount: 2

8. HAProxy (High Availability)

Для высоконадёжных систем:

global
    maxconn 4096
    log 127.0.0.1 local0

defaults
    log global
    mode http
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms

frontend web_frontend
    bind *:80
    default_backend backend_servers

backend backend_servers
    balance roundrobin
    option httpchk GET /health HTTP/1.1\r\nHost:\ api.example.com
    
    server backend1 192.168.1.100:8080 check inter 2s fall 3
    server backend2 192.168.1.101:8080 check inter 2s fall 3
    server backend3 192.168.1.102:8080 check inter 2s fall 3
    
    # Sticky session для сохранения сессии
    cookie SERVERID insert indirect nocache

9. Kubernetes Service (для контейнеризации)

Автоматическая балансировка в K8s:

apiVersion: v1
kind: Service
metadata:
  name: api-service
spec:
  selector:
    app: api-backend
  type: LoadBalancer
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
      name: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-backend
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api-backend
  template:
    metadata:
      labels:
        app: api-backend
    spec:
      containers:
      - name: api
        image: my-api:latest
        ports:
        - containerPort: 8080
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10

10. Практический пример: Spring Boot приложение за Nginx

application.properties:

server.port=8080
server.servlet.context-path=/api

# Актуальный IP клиента при работе за балансировщиком
server.tomcat.remote-ip-header=X-Forwarded-For
server.tomcat.protocol-header=X-Forwarded-Proto

nginx.conf:

upstream java_backend {
    keepalive 32;
    server localhost:8080 max_fails=3 fail_timeout=30s;
    server localhost:8081 max_fails=3 fail_timeout=30s;
    server localhost:8082 max_fails=3 fail_timeout=30s;
}

server {
    listen 80;
    server_name api.example.com;
    
    location /health {
        access_log off;
        proxy_pass http://java_backend;
    }
    
    location / {
        proxy_pass http://java_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_redirect off;
    }
}

Best Practices

  1. Выбор стратегии:

    • Round-Robin — если нагрузка равномерная
    • Least Connections — если разные запросы имеют разное время выполнения
    • IP Hash — для sticky sessions (но лучше использовать distributed cache)
  2. Health Checks обязательны:

@RestController
public class HealthController {
    @GetMapping("/health")
    public ResponseEntity<?> health() {
        return ResponseEntity.ok(Map.of("status", "UP"));
    }
}
  1. Graceful Shutdown:
@Configuration
public class ShutdownConfig {
    @Bean
    public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
        return new TomcatServletWebServerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                final int shutdownWaitTime = 30;
                context.setUnloadDelay(shutdownWaitTime * 1000);
            }
        };
    }
}
  1. Мониторинг:
    • Метрики: количество активных соединений, время отклика, процент ошибок
    • Алерты на отказ сервера, деградацию performance

Итоги

  • Nginx — лучший выбор для L7 балансировки
  • Health Checks — критичны для надёжности
  • Выбор стратегии зависит от типа нагрузки
  • Client-side LB (Spring Cloud) — для микросервисов
  • Kubernetes Service — встроенная балансировка в K8s
  • Всегда тестируй failover и graceful shutdown
Как настраивал балансировщик | PrepBro