ENbext.dev
DocumentationExploitation

Traduction automatique depuis l’anglais. Consulter l’original.

Sur cette page

Mise à l'échelle

Une seule instance bext gère seule un trafic important. Lorsque vous avez besoin de plus de capacité, évoluez horizontalement en exécutant plusieurs instances derrière un équilibreur de charge avec Redis pour la coordination entre instances.

Configuration#

toml
# bext.config.toml
[server]
listen = "0.0.0.0:3061"
workers = 0                      # 0 = auto (one per CPU core)

[redis]
url = "redis://redis.internal:6379/0"
pool_size = 16                   # connection pool size per instance

[scaling]
health_path = "/__bext/health"   # health check endpoint
graceful_shutdown_timeout_secs = 30
session_affinity = "none"        # none | cookie | ip_hash
session_cookie_name = "BEXT_SID" # cookie name when session_affinity = "cookie"

[rate_limit]
enabled = true
requests_per_minute = 600
distributed = true               # share counters across instances via Redis

Synchronisation du cache Redis L2#

Lorsque plusieurs instances bext servent la même application, chacune dispose de son propre cache L1 en mémoire (DashMap). Sans coordination, l'invalidation du cache sur une instance laisse du contenu obsolète sur les autres.

Activez Redis comme couche de cache L2 pour résoudre ce problème :

toml
[redis]
url = "redis://redis.internal:6379/0"

[cache.isr]
max_entries = 10_000
default_ttl_ms = 60_000
default_swr_ms = 3_600_000
l2_enabled = true                # write-through to Redis
l2_ttl_ms = 300_000              # Redis entries live longer than L1

Flux de cache avec L2 activé :

  1. L1 HIT – Servir à partir d'un DashMap en mémoire (sous-milliseconde)
  2. L1 MISS, L2 HIT -- Récupérer de Redis, promouvoir en L1, servir
  3. L1 MISS, L2 MISS -- Rendu SSR, écriture sur L1 et L2, diffusion
  4. Invalidation -- Purge de L1 et L2 ; d'autres instances voient l'échec L2 lors de la prochaine demande et effectuent un nouveau rendu

Les résultats de la revalidation ISR sont écrits dans L2, de sorte que les autres instances récupèrent du nouveau contenu sans effectuer de nouveau rendu.

Limitation du débit distribué#

Avec distributed = true, les compteurs de limite de débit sont stockés dans Redis à l'aide de compteurs à fenêtre coulissante. Toutes les instances partagent le même budget par adresse IP client :

toml
[rate_limit]
enabled = true
requests_per_minute = 600
distributed = true

Sans Redis, chaque instance suit ses propres compteurs, ce qui signifie qu'un client pourrait répondre aux requêtes N * 600/minute sur N instances.

Séances collantes#

Si votre application stocke l'état de la session en mémoire (non recommandé pour les déploiements à grande échelle), activez l'affinité de session :

toml
[scaling]
session_affinity = "cookie"       # route same user to same instance
session_cookie_name = "BEXT_SID"

Avec l'affinité cookie, bext définit un cookie sur la première réponse contenant un identifiant d'instance. L'équilibreur de charge utilise ce cookie pour le routage. Avec ip_hash, le routage est déterminé par l'adresse IP du client.

Pour la plupart des applications, les instances sans état + Redis sont préférées aux sessions persistantes.

Configuration de l'équilibreur de charge#

nginx comme équilibreur de charge#

nginx
upstream bext_cluster {
    least_conn;
    server 10.0.1.10:3061;
    server 10.0.1.11:3061;
    server 10.0.1.12:3061;
}

server {
    listen 443 ssl http2;
    server_name app.example.com;

    location / {
        proxy_pass http://bext_cluster;
        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_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

HAProxy#

haproxy
frontend web
    bind *:443 ssl crt /etc/ssl/app.pem
    default_backend bext_servers

backend bext_servers
    balance leastconn
    option httpchk GET /__bext/health
    http-check expect status 200

    server bext1 10.0.1.10:3061 check inter 5s fall 3 rise 2
    server bext2 10.0.1.11:3061 check inter 5s fall 3 rise 2
    server bext3 10.0.1.12:3061 check inter 5s fall 3 rise 2

Équilibreurs de charge cloud (AWS ALB / GCP LB)#

Pointez le groupe cible ou le service backend sur le port 3061 sur chaque instance. Définissez la vérification de l'état sur GET /__bext/health avec l'état attendu 200. Activez HTTP/2 entre le LB et le bext pour de meilleures performances.

Point de terminaison du bilan de santé#

GET /__bext/health renvoie 200 lorsqu'il est sain, 503 lorsqu'il est dégradé. Les équilibreurs de charge doivent l'utiliser pour les sondes d'intégrité du backend :

bash
curl -s http://localhost:3061/__bext/health | jq .
json
{
  "status": "healthy",
  "uptime_secs": 172800,
  "checks": {
    "render_pool": "ok",
    "isr_cache": "ok",
    "redis": "ok"
  }
}

Réglage du nombre de travailleurs#

Le paramètre workers contrôle le nombre de threads du système d'exploitation qui gèrent les connexions entrantes (via les threads de travail Actix). La valeur par défaut est une par cœur de processeur.

toml
[server]
workers = 0    # auto = num_cpus

Lignes directrices :

  • Charges de travail liées au processeur (SSR lourd, transformations d'image) : conserver à num_cpus ou légèrement en dessous pour laisser de la marge pour les tâches du système d'exploitation.
  • Charges de travail liées aux E/S (principalement fichiers statiques, proxy) : peuvent aller jusqu'à 2 * num_cpus car les threads passent du temps à attendre les E/S.
  • Charges de travail mixtes : respectez la valeur par défaut. Le pool V8 possède son propre nombre de nœuds de calcul ( [render].workers ) distinct des nœuds de calcul du serveur.

Arrêt progressif#

Lorsque bext reçoit SIGTERM ou SIGQUIT, il cesse d'accepter de nouvelles connexions et draine les demandes en vol jusqu'à graceful_shutdown_timeout_secs :

toml
[scaling]
graceful_shutdown_timeout_secs = 30

Pendant la vidange :

  • Les nouvelles connexions TCP sont refusées (l'équilibreur de charge achemine vers des instances saines)
  • Les requêtes HTTP en cours se terminent normalement
  • Les connexions WebSocket et SSE reçoivent une trame proche
  • Après le délai d'attente, les connexions restantes sont interrompues de force

Cela s'intègre parfaitement aux mises à jour progressives Kubernetes, aux redémarrages de systemd et au flux sans temps d'arrêt bext upgrade.

Conseil

Pour la plupart des applications, les instances sans état avec Redis sont préférables aux sessions persistantes. L'état de session en mémoire empêche une répartition uniforme de la charge et complique les redémarrages progressifs : préférez stocker les données de session dans Redis ou dans un autre magasin partagé.

En rapport#

Modifier cette page ↗Besoin d’aide ? ↗
Rechercher dans la documentation

Saisissez un sujet, une commande ou une question.