7 usages du Load Balancer: explication détaillée avec exemples
1. Vue d’ensemble
Quand on parle de Load Balancer (LB), beaucoup pensent simplement : « il répartit les requêtes sur plusieurs serveurs ». En réalité, le LB fait bien plus que ça — de la réduction de charge SSL, à la conservation des sessions utilisateur, en passant par la protection contre les DDoS et le monitoring de la santé des backends.
Cet article couvre 7 usages principaux du Load Balancer, chacun avec des exemples de configuration ou de code concrets (nginx, Spring Boot, Kubernetes) pour que tu comprennes bien comment il fonctionne dans un système réel. Après lecture, tu sauras quand activer telle ou telle fonctionnalité sur le LB et tu éviteras quelques erreurs de configuration courantes.
2. Distribution du trafic
C’est la fonction la plus basique : le LB reçoit une requête du client et la transmet à l’un des plusieurs serveurs backend selon un algorithme — round robin, least connections, weighted round robin…
upstream order_service {
server 10.0.1.11:8080;
server 10.0.1.12:8080;
server 10.0.1.13:8080;
}
server {
listen 80;
location /orders/ {
proxy_pass http://order_service;
}
}
upstream déclare 3 instances du OrderService. Par défaut, nginx utilise round robin — la requête 1 va vers .11, la requête 2 vers .12, la requête 3 vers .13, puis revient à .11. Si une instance traite des requêtes plus lourdes, tu peux basculer vers least_conn; pour que nginx privilégie le serveur avec le moins de connexions ouvertes.
Note : Round robin ne tient pas compte de la santé du serveur. Si les instances ont des capacités différentes (par exemple une machine avec plus de ressources), utilise
weight:server 10.0.1.11:8080 weight=3; server 10.0.1.12:8080 weight=1;
3. Terminaison SSL
Au lieu de laisser chaque backend déchiffrer lui-même TLS (coûteux en CPU), tu confies cela au LB. Le LB garde le certificat, déchiffre HTTPS en HTTP pur, puis le transfère au réseau interne.
server {
listen 443 ssl;
server_name api.nonladev.com;
ssl_certificate /etc/nginx/certs/nonladev.crt;
ssl_certificate_key /etc/nginx/certs/nonladev.key;
location / {
proxy_pass http://order_service; # HTTP pur, sans TLS
proxy_set_header X-Forwarded-Proto https;
}
}
Grâce à cela, OrderService écrit en Spring Boot n’a pas besoin de configuration server.ssl.* du tout — il fonctionne juste en HTTP normal sur le port 8080. L’en-tête X-Forwarded-Proto aide le backend à savoir que la requête originale était HTTPS pour générer des URL de redirection correctes.
Note : Si le réseau interne entre le LB et le backend n’est pas de confiance (par exemple sur plusieurs sous-réseaux, cloud différents), ne fais pas juste la termination — effectue un « SSL bridging » : le LB déchiffre puis réchiffre avec un certificat interne avant de transférer.
4. Persistance de session
Quand le backend stocke la session en mémoire (session locale), la requête du même utilisateur doit toujours aller à la même instance, sinon l’utilisateur sera « déconnecté » aléatoirement.
upstream order_service {
ip_hash; # même IP client -> même serveur
server 10.0.1.11:8080;
server 10.0.1.12:8080;
}
ip_hash hache l’IP du client pour choisir de manière déterministe un serveur dans l’upstream. Une autre approche est la sticky session basée sur des cookies — le LB ajoute lui-même un cookie pour marquer l’instance, ce qui fonctionne même quand les clients sont derrière un NAT avec une IP commune.
Une solution plus robuste consiste à abandonner la sticky session et à externaliser la session avec Spring Session + Redis :
@Configuration
@EnableRedisHttpSession
public class SessionConfig {
}
spring.data.redis.host=redis.internal
spring.data.redis.port=6379
Avec cette configuration, la session est stockée dans Redis au lieu de la mémoire de chaque instance. Peu importe le serveur auquel va la requête, elle pourra lire la session — le LB peut utiliser un round robin normal, sans avoir besoin de ip_hash.
Note :
ip_hashpeut causer un déséquilibre de charge si plusieurs utilisateurs partagent le même NAT (par exemple un bureau d’entreprise) — tout leur trafic se concentre sur 1 serveur. Privilégie l’externalisation de la session quand le système grandit.
5. Haute disponibilité
Le LB vérifie continuellement les backends ; si une instance meurt, le LB l’enlève automatiquement de la liste de service et concentre le trafic sur les instances encore vivantes — tout cela se passe sans que le client le sache.
upstream order_service {
server 10.0.1.11:8080 max_fails=3 fail_timeout=30s;
server 10.0.1.12:8080 max_fails=3 fail_timeout=30s;
}
max_fails=3 signifie qu’après 3 requêtes consécutives échouées, nginx marque ce serveur comme « down » pendant 30 secondes (fail_timeout), et ne lui envoie plus de nouvelles requêtes. Après 30 secondes, nginx réessaie — si le serveur a récupéré, il est remis dans la rotation.
[14:02:01] 10.0.1.12 timeout -> nombre d'échecs 1
[14:02:05] 10.0.1.12 timeout -> nombre d'échecs 2
[14:02:09] 10.0.1.12 timeout -> nombre d'échecs 3 -> marqué DOWN pour 30s
[14:02:09] trafic réacheminé vers 10.0.1.11
[14:02:39] 10.0.1.12 réessayé -> sain -> de retour dans le pool
Grâce à ce mécanisme, un crash d’instance n’effondre pas tout le système — c’est la base même de la haute disponibilité au niveau réseau.
6. Scalabilité horizontale
Le LB est une condition préalable au scaling horizontal : tu ajoutes une nouvelle instance, le LB la reconnaît automatiquement et répartit la charge dessus, sans modifier le code du backend.
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 2
template:
spec:
containers:
- name: order-service
image: nonladev/order-service:1.4.0
ports:
- containerPort: 8080
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: order-service-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: order-service
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Ici, le Service Kubernetes (jouant le rôle de LB interne) équilibre automatiquement le trafic entre les pods order-service. Le HorizontalPodAutoscaler surveille le CPU — quand il dépasse 70%, Kubernetes crée des pods supplémentaires (max 10), et le LB ajoute immédiatement les nouveaux pods à la liste de service sans avoir besoin de redéployer ou redémarrer quoi que ce soit.
Note : Le scaling n’est efficace que si le backend est stateless (ou que la session a été externalisée comme dans la section 4). Sinon, les nouveaux pods ajoutés ne pourront pas accéder aux anciennes sessions des utilisateurs.
7. Atténuation des attaques DDoS
Positionné en première ligne, le LB est le lieu idéal pour bloquer le trafic anormal avant qu’il n’atteigne les backends — par rate limiting ou en distribuant le trafic plus largement.
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=20r/s;
server {
location /orders/ {
limit_req zone=api_limit burst=10 nodelay;
proxy_pass http://order_service;
}
}
limit_req_zone limite chaque IP à un maximum de 20 requêtes/seconde. burst=10 permet de dépasser temporairement jusqu’à 10 requêtes en queue, nodelay traite la rafale immédiatement au lieu de la ralentir. Au-delà de cette limite, nginx retourne 503 Service Temporarily Unavailable au lieu de laisser les requêtes s’accumuler sur le backend.
Si tu veux du rate limiting au niveau application (en complément, pas en remplacement du LB), utilise Bucket4j dans Spring Boot :
<dependency>
<groupId>com.bucket4j</groupId>
<artifactId>bucket4j-core</artifactId>
<version>8.10.1</version>
</dependency>
Bucket bucket = Bucket.builder()
.addLimit(Bandwidth.simple(20, Duration.ofSeconds(1)))
.build();
@GetMapping("/orders")
public ResponseEntity<?> getOrders() {
if (!bucket.tryConsume(1)) {
return ResponseEntity.status(429).body("Trop de requêtes");
}
return ResponseEntity.ok(orderService.findAll());
}
Note : Le rate limiting par IP peut être contourné avec des IP usurpées ou un botnet distribué. Avec des DDoS à grande échelle, tu dois combiner le LB avec une CDN/WAF en amont, le LB n’étant que la deuxième ligne de défense.
8. Monitoring de la santé des backends
Contrairement à la section 5 (réaction en cas d’échec de requête), le health monitoring permet au LB d’appeler activement un endpoint régulièrement pour vérifier si le serveur fonctionne encore — on appelle cela un active health check.
@RestController
public class HealthController {
@GetMapping("/health")
public ResponseEntity<String> health() {
boolean dbUp = checkDatabaseConnection();
if (!dbUp) {
return ResponseEntity.status(503).body("DB_DOWN");
}
return ResponseEntity.ok("OK");
}
private boolean checkDatabaseConnection() {
// vérifier le pool de connexions, retourne true/false
return true;
}
}
Avec Spring Boot Actuator, tu as déjà un endpoint similaire sans avoir à l’écrire :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
management.endpoints.web.exposure.include=health
management.endpoint.health.show-details=always
Le LB (ou Kubernetes) appelle /actuator/health toutes les quelques secondes :
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
periodSeconds: 5
failureThreshold: 3
Écris un test pour t’assurer que l’endpoint répond correctement quand la DB plante :
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class HealthControllerTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
void shouldReturn503WhenDatabaseDown() {
// simuler DB down via profil test ou mock bean
ResponseEntity<String> response =
restTemplate.getForEntity("/health", String.class);
assertThat(response.getStatusCode().value()).isIn(200, 503);
}
}
Ce test s’assure que l’endpoint /health retourne toujours un statut valide (200 ou 503) sans lever d’exception — car si le health check lui-même plante, le LB penserait à tort que le serveur est down et exclurait à tort une instance saine.
Note : L’endpoint de health check doit être léger et rapide (moins de quelques centaines de ms). S’il interroge beaucoup de tables ou appelle d’autres services, le health check lui-même devient la cause de timeouts et est injustement exclu par le LB.
9. Conclusion
Le Load Balancer n’est pas juste « un outil de répartition de charge » — il joue aussi un rôle dans la réduction de charge SSL, la conservation des sessions, la détection des défaillances, le support du scaling horizontal, et constitue la première ligne de défense contre les DDoS. Quand tu conçois ton système, tu dois clarifier quel usage tu as besoin parmi ces 7 pour choisir les bonnes fonctionnalités lors de la configuration du LB — nginx, HAProxy, AWS ALB ou Kubernetes Service supportent tous la plupart de ces cas d’usage, ils diffèrent juste dans leur déclaration.
Conseil final : ne concentre pas toute la responsabilité dans un seul LB. Combiner les active health checks, le rate limiting, et l’externalisation de session permettra à ton système de bien scaler et de gérer les défaillances beaucoup mieux qu’en se contentant simplement d’activer round robin.