Tu vois la feature « Scheduled Autoscaling » de Laravel Cloud, tu souris. Normal. Newsletter à 10h, lancement à 18h, soldes le vendredi… tu veux de la capacité avant le pic, pas après. Sauf que c’est exactement le genre de confort qui peut te donner une fausse sensation de sécurité. Tu peux te retrouver avec 2× plus de CPU… et exactement la même panne, juste plus chère.
Je te propose un angle vraiment prod : ce que l’autoscaling planifié résout (et ce qu’il ne résout pas), puis un protocole de test k6 qui ressemble à un trafic réel, les métriques que je regarde en priorité, les pièges bêtes de planning (fuseau, chevauchement), et le plan de repli que je veux voir avant le jour J.
Autoscaling planifié sur Laravel Cloud : ce que ça fait vraiment (et ce que ça ne fera jamais)
L’autoscaling « planifié » sur Laravel Cloud, l’idée est simple : tu définis des fenêtres où ton app doit monter en capacité, avec des bornes min/max, et la plateforme ajuste les ressources dans cette plage. C’est utile parce que l’autoscaling réactif a un défaut connu : il réagit après que la métrique a bougé. Pendant ce temps, tes utilisateurs, eux, attendent déjà.
Mais il faut être clair sur la promesse. Planifier le scaling ne corrige pas une requête SQL lente, ne supprime pas un N+1, ne débloque pas une table qui lock, ne rend pas Redis magique, et ne rend pas tes jobs moins gourmands. Ça te donne juste de l’air côté compute pour absorber un volume. Si ton goulot d’étranglement est ailleurs, tu vas surtout faire tourner plus de workers… qui vont frapper plus fort sur la même base.
Sponsorisé par Le Scribouillard
Besoin de contenu optimisé SEO ?
Utilisez la meilleure plateforme française de création de contenu assistée par IA ! Et générez des articles pour moins de 1€ !
Le piège classique : tu scales le web… et tu saturés la base (ou les queues)
Le scénario que j’ai vu trop de fois : le pic arrive, l’autoscaling planifié fait son boulot, tu as plus d’instances, plus de PHP workers, plus de concurrence… et soudain la DB part en fumée. CPU qui grimpe, connexions qui explosent, locks, temps de réponse qui s’allongent, et effet boule de neige parce que les timeouts créent encore plus de retries.
Même combat côté queues. Si ton pic génère des jobs (envoi d’emails, génération de PDF, sync externe, webhooks), augmenter les web nodes sans réfléchir au throughput des workers et à la capacité de la DB, c’est un moyen très efficace de transformer un retard « acceptable » en backlog ingérable.
Donc oui, planifier le scaling est une bonne idée. Mais uniquement si tu sais déjà où est ton bottleneck quand tout va vite.
Préparer un test crédible : si ton staging ne ressemble pas à la prod, ça ne vaut rien
Avant de lancer k6, je pose une règle un peu sèche : si ton environnement de test n’a pas une DB avec des volumes réalistes, des index identiques, un cache qui se comporte pareil et des workers configurés comme en prod, tu vas tester du vent. Tu peux quand même faire un test, mais il faut l’assumer : ce sera un test de « forme » (valider le protocole), pas un test de « vérité ».
Dans l’article Laravel sur k6, on voit bien un truc important : dès que tu montes fort en charge, la latence devient irrégulière et tu observes des effets de jitter, surtout pendant les phases d’ajustement de capacité. C’est exactement ça qu’il faut capturer. Pas juste un score « RPS max » sur 30 secondes, mais la dynamique pendant l’événement de scaling.
Concrètement, je veux que la base soit peuplée, que les caches soient dans un état proche du réel (ni totalement froid, ni artificiellement chaud), et que les endpoints testés soient ceux qui vont souffrir le jour J. Pas « / » et « /health ».
Mon protocole k6 pour valider un scaling schedule (ramp-up, hold, ramp-down)
Un test utile, c’est un test qui ressemble à une montée de trafic, pas un mur. Je préfère un ramp-up progressif, un plateau suffisamment long pour laisser la plateforme scaler, puis une redescente. Ça te donne trois infos : à quel moment ça casse, ce qui se passe pendant le scale-out, et si ton système se « remet bien » après.
Je cible toujours quelques parcours critiques. Exemple typique d’une app Laravel : page produit, recherche/filtre, ajout au panier, login, checkout, endpoints API consommés par le front, et une action qui déclenche un job (email, export, webhook). L’idée n’est pas de tout couvrir. L’idée, c’est de frapper ce qui coûte vraiment.
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '2m', target: 200 }, // montée
{ duration: '8m', target: 200 }, // plateau (laisse le temps au scaling)
{ duration: '2m', target: 0 }, // redescente
],
thresholds: {
http_req_failed: ['rate<0.01'],
http_req_duration: ['p(95)<600'],
},
};
const BASE_URL = __ENV.BASE_URL;
export default function () {
const headers = { 'User-Agent': 'k6-laravel-cloud-schedule-test' };
const resHome = http.get(`${BASE_URL}/`, { headers });
check(resHome, { 'home 200': (r) => r.status === 200 });
// Endpoint “cher” typique : recherche
const resSearch = http.get(`${BASE_URL}/search?q=chaussures`, { headers });
check(resSearch, { 'search 200': (r) => r.status === 200 });
// Endpoint qui déclenche souvent du boulot côté backend
const resCart = http.post(`${BASE_URL}/cart/add`, JSON.stringify({ sku: 'SKU-123', qty: 1 }), {
headers: { ...headers, 'Content-Type': 'application/json' },
});
check(resCart, { 'cart add ok': (r) => r.status === 200 || r.status === 204 });
sleep(1);
}Deux détails qui changent tout. D’abord, je fais tourner ce test pendant la fenêtre où le scaling planifié est censé se produire, avec une marge avant et après. Ensuite, je compare deux runs : une fois avec le schedule (pré-scaling), une fois sans (autoscaling « normal »). Si les deux courbes se ressemblent trop, c’est qu’il y a un autre problème que la capacité brute.
# Exemple simple : lance le test sur la fenêtre du schedule
BASE_URL="https://staging.example.com" k6 run loadtest.js
# Si tu collectes des métriques (Prometheus/Influx/Cloud dashboards),
# garde la même fenêtre de temps et annote le moment où le scaling est censé démarrer.Lire les résultats : p95, erreurs, et surtout le « trou » pendant le scale-out
Le piège, c’est de se contenter du débit moyen. Moi je veux la latence p95 (voire p99 si tu as du trafic), le taux d’erreur, et une vision minute par minute. Le moment intéressant, c’est souvent le « trou » pendant la transition. Tu peux avoir un système qui tient 200 VU sur le papier, mais qui prend 30 à 90 secondes de latence dégradée au moment où la plateforme ajoute de la capacité. Et c’est exactement le moment où ton pic arrive.
Si tu vois une montée des 429/503, ou des timeouts côté client pendant le scale-out, tu as un sujet. Ça peut être un démarrage trop lent (cold start, cache froid), un pool de connexions DB qui sature, ou un downstream (DB, Redis, API externe) qui n’encaisse pas la montée de concurrence.
Ce que j’aime bien, c’est de poser un objectif de service simple avant de « juger » le test. Exemple : « p95 < 600 ms et moins de 1% d’erreurs sur le plateau ». Sans ça, tu vas toujours trouver une façon de te convaincre que « ça passe ».
Les métriques qui te disent où ça bloque : DB, Redis, queues, PHP-FPM
Quand ça commence à souffrir, le dashboard qui te sauve n’est pas celui du CPU de l’instance web. C’est celui qui te dit quel composant sature. Côté base, je regarde en priorité le CPU, les temps de requêtes, le nombre de connexions, et les signes de contention (locks, waits). Sur MySQL comme sur PostgreSQL, une hausse brutale de la concurrence peut transformer une lenteur marginale en embouteillage complet.
Côté Redis, je veux voir la mémoire, les evictions, et les latences si tu les as. Un cache qui évince trop, c’est un cache qui ne sert plus à grand-chose pendant un pic. Et si tu utilises Redis pour les sessions, tu as aussi un risque de latence « transverse » : toute l’app ralentit d’un coup.
Côté queues, la métrique terrain, c’est la profondeur de file et l’âge du job le plus vieux. Si tu scalés le web et que ton backlog part en diagonale, tu as un incident qui se décale dans le temps. Tu vas « survivre » au pic, puis exploser 20 minutes plus tard quand les jobs critiques (paiement, facturation, notifications) n’ont pas suivi.
Enfin, pense au temps de démarrage réel des nouveaux workers PHP. Même si Laravel Cloud ajoute de la capacité, il y a un délai. Le scale-out n’est pas instantané. Ce délai doit être intégré dans ton schedule, sinon tu arrives pile à l’heure… mais en retard.
Les pièges bêtes du scheduling : fuseau horaire, chevauchements, limites
Le premier piège, c’est le fuseau horaire. Tu planifies « 10h », mais tu ne sais pas si c’est 10h UTC, 10h Europe/Paris, ou 10h dans le fuseau du compte. Ajoute un changement d’heure et tu as un pic qui tombe en dehors de ta fenêtre. Ça paraît idiot, mais c’est le genre de truc qui arrive une fois, et qui coûte cher.
Le deuxième piège, c’est le chevauchement ou l’empilement de règles. Tu ajustes un schedule pour un événement ponctuel, tu oublies de le retirer, et le mois d’après tu as une montée de capacité inutile tous les jours. Ou pire, deux schedules se contredisent et tu ne comprends plus quel plafond est appliqué.
Troisième piège : des bornes min/max mal posées. Si ton max est trop bas, ton schedule te donne une illusion de « planification », mais tu plafonnes avant le volume attendu. Si ton min est trop haut, tu vas payer une capacité inutile pendant toute la fenêtre, et tu ne l’apprendras qu’en regardant la facture. Dans les deux cas, il faut un test et une observation de métriques, pas une croyance.
Le plan B qui évite le downtime : rollback, mode dégradé, décisions à l’avance
Le jour du pic, tu n’as pas envie d’improviser. Je veux toujours un plan de rollback ultra simple : désactiver/ajuster le schedule, remonter une config de cache, couper une feature coûteuse via feature flag. Et surtout, je veux savoir qui décide, et en combien de minutes. Le « on verra » ne tient pas quand tu as 2 000 personnes en train de refresh une page.
Le mode dégradé, c’est ce qui sépare souvent un incident « gérable » d’un incident « catastrophique ». Si ton service peut passer en lecture seule pendant 10 minutes, si tu peux mettre certaines écritures en file d’attente, si tu peux réduire la surface (désactiver recherche avancée, exports, pages admin lourdes), tu gagnes du temps. Tu ne rends pas l’app parfaite. Tu la rends vivante.
Et je le dis franchement : si ton app ne supporte pas le trafic attendu même avec plus de compute, le bon move n’est pas « augmenter encore ». Le bon move, c’est de couper ce qui brûle, de stabiliser, puis d’aller corriger le vrai bottleneck (requêtes, index, cache, jobs, dépendances externes). Sinon tu vas juste déplacer le point de rupture.
Mon avis : le scaling planifié, c’est une ceinture… pas un airbag
Je suis pour le scheduled autoscaling. C’est une feature qui colle à la réalité des pics prévisibles, et sur Laravel Cloud c’est exactement le genre de confort qui peut faire gagner des heures de stress. Mais c’est une ceinture, pas un airbag. Ça t’aide quand tout va à peu près bien. Ça ne te sauve pas d’un système qui s’effondre dès que la DB est sous pression.
Le bon usage, c’est simple : tu planifies, tu testes avec k6 sur une fenêtre réaliste, tu regardes p95 et erreurs, tu identifies le bottleneck, tu poses des limites raisonnables, et tu as un mode dégradé prêt. Le jour où tu fais ça sérieusement, l’autoscaling devient une mécanique. Et c’est exactement ce qu’on veut en prod.