Le mythe classique en e-commerce, c’est de croire qu’un “gros serveur” va effacer un WooCommerce lent. Spoiler : non. Si ton TTFB est à 2,5s sur une page produit (surtout variable), c’est rarement un problème de RAM. C’est presque toujours un problème de génération côté PHP/DB… et parfois un problème de charge auto-infligée parce que ton preload (WP Rocket ou autre) arrose le site en continu.
Le cas typique, vu mille fois : pages publiques censées être cachées, mais qui restent “lourdes” à générer. Les premiers hits sont lents, les suivants vont mieux… jusqu’à ce que le preload repasse et remette le feu. Et toi tu regardes ton CPU global à 20% et tu te demandes où part le temps. Il part dans une poignée de workers PHP qui moulinent des hooks WooCommerce, des règles de prix, des variations, des sessions, et des requêtes MySQL pas si sexy.
Un TTFB lent sur WooCommerce, ce n’est pas “le serveur”, c’est une requête PHP qui rame
Quand on parle de TTFB sur une page HTML, on parle du temps nécessaire pour produire le premier octet. Donc avant que le navigateur puisse faire grand-chose. Si tu vois 2–3 secondes, c’est que PHP (et souvent MySQL) est en train de bosser. Et surtout : une requête WooCommerce, c’est principalement single-request. Elle ne va pas “utiliser tes 32 cores” comme un job de rendu vidéo. Elle va prendre un worker PHP-FPM, exécuter du code, faire des allers-retours DB, attendre, recalculer des trucs, et terminer. Un seul flux principal, beaucoup d’attente, beaucoup de hooks.
Le plus piégeux avec WooCommerce, c’est que tu peux avoir une infra saine et quand même un temps de génération mauvais. Les produits variables, les plugins de pricing, les systèmes de stock, les filtres de thèmes, les builders, les hooks “qui semblent inoffensifs”… tout ça s’empile. Et c’est rarement un seul truc “cassé”. C’est une addition de petites décisions qui finissent en 2,5 secondes.
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€ !
Avant de toucher à WP Rocket : prouve que tu es lent en “origin”
Je commence toujours par vérifier un truc bête : est-ce que je mesure une page servie du cache, ou une page générée. Teste en local avec curl et regarde les headers (WP Rocket ajoute des indices), et mesure hors navigateur pour ne pas te faire piéger par un cache de navigateur ou un CDN.
Si la page est réellement cachée, le TTFB doit devenir très bas (ou au moins stable) sur les hits suivants. Si tu as un TTFB haut et stable, c’est que tu ne sors pas du cache. Et là, WP Rocket n’est pas “lent”. Il est juste contourné : cookies, query strings, cache private, variation par device, page considérée comme non cacheable, ou un plugin qui force des headers anti-cache.
WooCommerce est souvent CPU-bound… mais pas “CPU global” : PHP-FPM est le goulot
Le serveur peut afficher 20% de CPU, et pourtant ton site est à genoux. Parce que ce que tu satures, ce n’est pas “le CPU”, c’est le nombre de workers PHP-FPM disponibles. Si tu as 10 workers et que 10 requêtes longues arrivent (preload, bots, vrais utilisateurs), la 11e attend. Et cette attente se voit dans le TTFB.
Les réglages pm.max_children, pm.max_requests, la taille mémoire, et le mode dynamic vs ondemand changent vraiment la donne. Et sur WooCommerce, je préfère généralement un pool dédié (au moins séparé de l’admin) et des limites pensées pour absorber des pics sans faire exploser la RAM. Si tu laisses max_children trop bas, tu fais la queue. Si tu le mets trop haut, tu swaps et tu t’auto-sabotes.
; Exemple d'approche (à adapter, ce n'est pas une recette universelle)
; Le but : éviter la file d'attente, sans exploser la RAM
pm = dynamic
pm.max_children = 40
pm.start_servers = 10
pm.min_spare_servers = 10
pm.max_spare_servers = 20
pm.max_requests = 500
request_terminate_timeout = 60s
Ce que je cherche surtout : est-ce que des requêtes attendent des workers. Si oui, tu peux avoir le meilleur MySQL du monde, tu vas quand même “sentir” du 2–3s. Et c’est aussi pour ça que le preload peut devenir un problème : il consomme des workers avec des requêtes qui n’apportent rien à l’utilisateur en temps réel.
Le vrai diagnostic : profile une requête “page produit” comme un adulte
À ce stade, arrêter de deviner fait gagner des heures. Sur un WooCommerce qui a des variations, des règles et des plugins, tu n’as aucune chance en mode intuition. Il faut profiler une requête “lente”, en prod ou en préprod réaliste. New Relic APM (ou un équivalent) est parfait pour ça : tu vois le temps passé en PHP, le temps DB, les requêtes les plus chères, et souvent le plugin ou la fonction responsable.
Si tu n’as pas APM, tu peux aussi faire un profil Xdebug (plutôt en staging) ou utiliser un profiler type XHProf/Tideways selon ton stack. Le but est le même : sortir un top clair. Sur WooCommerce, les gros postes fréquents sont des requêtes sur wp_postmeta qui explosent, des boucles sur les variations, des fonctions qui recalculent des prix/stock à chaque affichage, et des hooks ajoutés par des plugins “marketing” qui font des appels externes.
MySQL : le TTFB se planque souvent dans une ou deux requêtes débiles
WooCommerce adore postmeta. Et postmeta adore ruiner ta journée si tu laisses une requête non indexable tourner sur des volumes sérieux. Active le slow query log (sur une fenêtre de diagnostic), ou utilise les traces APM, et regarde ce qui revient. Une seule requête à 600ms répétée 4 fois, et tu as déjà mangé ton budget. Une requête “petite” mais appelée 200 fois dans un template, même punition.
Si tu as beaucoup de trafic, un object cache persistant (Redis/Memcached) devient vite non négociable sur WooCommerce. Pas pour “accélérer le HTML caché” (qui s’en fiche), mais pour réduire la charge sur les pages non cachées et sur les endpoints qui restent dynamiques (panier, checkout, fragments…). Et si tu utilises Redis, vérifie que ce n’est pas “installé” mais inactif dans les faits, ou mal dimensionné avec un eviction policy agressif.
Action Scheduler : le bruit de fond qui flingue tes perfs sans que tu le voies
Action Scheduler (utilisé par WooCommerce et plein d’extensions) est un classique. Quand ça se passe bien, tu ne le remarques pas. Quand ça se passe mal, tu as des rafales de jobs, des tables qui gonflent, et des exécutions qui se déclenchent au pire moment. Le résultat est vicieux : ton site “marche”, mais le TTFB se dégrade par intermittence, et tu accuses le cache ou le thème.
Va voir l’état des actions planifiées, la taille des tables, le volume d’actions en échec, et surtout la concurrence. Selon ton hébergement, WP_CRON peut se déclencher à chaque visite et créer une contention. Sur des sites à trafic, je préfère généralement désactiver WP-Cron côté WordPress et piloter via cron système, justement pour éviter des exécutions surprises en plein pic.
WP Rocket preload : utile, mais ça peut créer une tempête de requêtes
Le preload a un but simple : réchauffer le cache avant les utilisateurs. Sauf qu’en WooCommerce, “réchauffer” peut vouloir dire lancer plein de générations coûteuses. Si ta génération d’une page produit prend déjà 2,5s, le preload va juste répéter ça, en parallèle, et monopoliser tes workers PHP. Et là tu obtiens un truc absurde : un cache plugin qui, au lieu d’aider, fabrique de la charge.
Le piège n’est pas le preload en soi. Le piège, c’est le preload sans limite, sans délai, et sans conscience de ton pool PHP. Un preload trop agressif, c’est littéralement un mini-DDoS depuis ton propre serveur. Ça se voit souvent quand le site “va bien” la nuit (quand le preload a fini), puis redevient lent quand une purge arrive, qu’un import tourne, ou que le sitemap change et que le bot de preload repart en tournée.
Ce que je fais en pratique quand je suspecte ça : je désactive temporairement le preload, je mesure le TTFB et la stabilité sous trafic réel, puis je le réactive en le bridant. Ajouter un délai entre URLs et réduire la concurrence est souvent suffisant. Et si tu dois choisir, je préfère un cache qui se remplit un peu plus lentement, plutôt qu’un preload qui rend le site instable.
Une règle simple : si la page n’est pas cacheable, le preload ne te sauvera pas
Sur WooCommerce, tu as des pages qui ne doivent pas être cachées (panier, checkout, compte) et des pages qui peuvent être cachées mais qui sont facilement “dé-cachées” par un détail. Le détail le plus fréquent, c’est un cookie. Si un plugin te pose un cookie sur tout le site (tracking, A/B test, personnalisation), WP Rocket peut décider de ne plus servir du cache pour cette visite. Résultat : tu crois être en mode cache, mais tu es en génération PHP pour une grosse partie des hits.
Ça vaut le coup d’être un peu brutal : si tu veux un TTFB bas sur les pages publiques, il faut des pages publiques vraiment publiques. Moins de personnalisation, moins de scripts qui “décident” au runtime, moins de cookies posés partout. Sinon tu te bats contre ton propre site.
Mon ordre de bataille quand j’ai un TTFB à 2,5s sur une fiche produit
Je commence par isoler le phénomène : est-ce que le TTFB est lent uniquement sur le premier hit (cache froid) ou aussi à chaud. Si c’est lent à chaud, c’est quasi certain que je ne sers pas du cache HTML, ou que je suis sur un endpoint non cacheable. Ensuite je vérifie la saturation PHP-FPM (file d’attente, workers occupés, temps moyen), parce que c’est souvent là que tout se joue quand un preload tourne.
Une fois que je sais si je suis cache-hit ou cache-miss, je profile. Pas “désactiver 12 plugins au hasard”. Je profile une URL lente, je lis les traces, je trouve la fonction ou la requête qui coûte. Parfois c’est un plugin de prix dynamique qui fait des recalculs inutiles. Parfois c’est une requête meta sans index. Parfois c’est un thème qui charge des variations comme un cochon. Dans tous les cas, ce n’est pas ton 32-core qui va résoudre une boucle PHP foireuse.
Et seulement après, je reviens au preload et je le rends civilisé. Le preload est un accélérateur… mais un accélérateur de ce que tu as déjà. Si ton origin est lent, il accélère surtout ton passage au mur.