Table des matières :
- 100 000 produits : ce que ça veut dire pour PrestaShop (et ce que ça ne dit pas)
- CPU : fréquence, cœurs, et le vrai goulot PHP-FPM
- RAM : le vrai budget entre InnoDB, PHP, OPcache et caches
- Stockage : NVMe, IOPS, latence et découpage DB/médias
- Pile logicielle sur serveur dédié : ce qui change le dimensionnement (et ce qui ne le changera jamais)
- Mesurer pour dimensionner : sans métriques, vous achetez au hasard
- Configs matérielles types (2026) pour 100 000 produits, et les signaux pour sortir du mono-serveur
100 000 produits : ce que ça veut dire pour PrestaShop (et ce que ça ne dit pas)
Un « gros catalogue » PrestaShop ne se résume pas à ps_product avec 100 000 lignes. La charge réelle vient du produit dans plusieurs dimensions : langues (ps_product_lang), boutiques (ps_product_shop), prix spécifiques (ps_specific_price), stock (ps_stock_available), associations catégories (ps_category_product), et surtout déclinaisons (ps_product_attribute*) et caractéristiques (ps_feature_product). À 100 000 produits, on voit souvent 300 000 à 800 000 déclinaisons en B2C (tailles/couleurs), ce qui multiplie les jointures et la cardinalité des index. Sur PrestaShop 8.1/8.2 et PrestaShop 9 (Symfony 6.4), le core reste fortement MySQL-bound : le CPU nécessaire dépend déjà de votre schéma et de la qualité de vos index, pas uniquement du nombre de SKU.
Pour rendre ce « 100 000 » plus concret, voilà une manière simple de raisonner (ordres de grandeur) :
| Dimension | Table(s) typique(s) | Multiplicateur fréquent | Effet direct |
|---|---|---|---|
| Langues | ps_product_lang, ps_category_lang |
× 2 à × 6 | plus de rows, plus de jointures |
| Multi-boutiques | ps_*_shop |
× 2 à × n shops | filtres shop + index supplémentaires |
| Déclinaisons | ps_product_attribute, ps_product_attribute_combination |
× 3 à × 10 | explosions de lignes + tri/filtre plus coûteux |
| Caractéristiques | ps_feature_product |
× 5 à × 30 | facettes et filtres plus lourds |
| Prix spécifiques | ps_specific_price |
très variable | écritures + recalculs + jointures |
Conséquence : deux boutiques affichant « 100 000 produits » peuvent avoir des contraintes très différentes. Exemple typique : un catalogue mode avec 100 000 produits et 6 tailles × 4 couleurs (donc 24 combinaisons moyennes) ne se dimensionne pas comme un catalogue B2B où la majorité des produits n’a pas de déclinaison mais possède beaucoup de prix spécifiques par groupe/client.
Autre point que beaucoup sous-estiment : l’écriture. Les pages catalogue sont majoritairement en lecture, mais les jobs annexes (imports, réindexation, génération de déclinaisons, recalcul de prix, régénération d’images) introduisent des phases de débit d’écriture soutenu sur InnoDB. Si vous avez un pipeline d’import fréquent (ex. PIM/ERP) ou des mises à jour de stock en quasi temps réel, le dimensionnement doit viser la stabilité en charge mixte (lecture + écriture), pas un simple bench de page catégorie.
Enfin, « 100 000 produits » est muet sur le poste qui finit souvent par saturer un serveur dédié : les médias. 100 000 produits × 5 images × 3 formats (original + 2 tailles) = 1,5 million de fichiers, avant même WebP/AVIF, zooms, variations. Le coût négatif n’est pas seulement le stockage : côté FS (inodes), cache page du noyau, et temps de déploiement/sauvegarde. Si vous ne mettez pas les images derrière un CDN ou un object storage, prévoyez une marge disque et surtout une stratégie de dégradation (sinon un rsync ou une sauvegarde pleine peut faire tanguer votre latence SQL).
Mini-scenario (vécu en e-commerce) : un import de nuit régénère 200 000 miniatures et déclenche un pic d’I/O sur le même volume que MySQL. Le matin, le trafic démarre ; résultat, les fsync InnoDB deviennent erratiques, le checkout ralentit alors que « le CPU est à 35% ». Ce n’est pas un problème de cœurs : c’est un problème de compétition disque et de séparation des rôles (volumes, priorités, fenêtres de batch).
CPU : fréquence, cœurs, et le vrai goulot PHP-FPM
Sur un serveur dédié PrestaShop, le CPU sert à deux choses très différentes : exécuter du PHP (front-office/back-office, modules) et exécuter du SQL (optimiseur + exécution). Côté PHP, le traitement d’une requête est essentiellement mono-thread à l’échelle d’un worker. Dit autrement : ajouter des cœurs aide à augmenter la concurrence, mais la fréquence (perf single-core) conditionne le p95/p99 de chaque requête. À trafic identique, un CPU à faible fréquence « beaucoup de cœurs » peut donner un site qui encaisse, mais lent.
Pour dimensionner, partez d’une relation simple : concurrence ≈ RPS × latence (Little’s Law, à granularité grossière). Exemple réaliste : 40 RPS en moyenne sur des pages catégorie/produit, p95 à 350 ms à chaud → ~14 requêtes concurrentes. Avec un peu de marge (pics, back-office, webhooks), viser 25 à 35 workers PHP-FPM est cohérent, à condition que la base suive. Pour comprendre où se perd le temps entre Nginx/Apache, FPM et le script, référez-vous à l’analyse du flux d’exécution : PHP-FPM : comprendre le flux d’exécution avec Nginx et Apache.
Quelques points pratiques qui changent le dimensionnement CPU (sans tomber dans la théorie) :
- Pages “dynamiques” vs “cacheables” : si 70% de vos hits sont servis par Varnish/Nginx cache, la pression CPU/PHP est sans commune mesure.
- Modules : un module mal conçu peut ajouter 10–30 requêtes SQL par page (N+1), ce qui fait exploser le temps CPU SQL avant même de parler de cœurs.
- Back-office : souvent plus lourd qu’on ne le croit (grilles, exports, filtres). Ne dimensionnez pas uniquement sur le FO.
- Pics : soldes, newsletters, campagnes ads. Le CPU “moyen” n’a aucune valeur si le p99 s’écroule en pic.
Ne dimensionnez pas le CPU uniquement sur le front-office. Sur 100 000 produits, les batchs sont un état permanent : imports, réindexation, génération d’images, exports (flux marketplaces), tâches Symfony Messenger si vous en avez (PrestaShop 9 facilite l’usage de workers Symfony) : Symfony Messenger : configuration avancée, choix du transport et performances. Si vous mutualisez web+DB sur la même machine, ces batchs peuvent voler des cycles au SQL et dégrader le checkout. La mitigation est simple : slots horaires + nice/ionice + throttling (à la fois côté MySQL et côté workers).
Checklist rapide (CPU/FPM) à valider en pré-prod avant achat :
- votre p95/p99 FO (catégorie/produit/panier) à chaud ;
- la latence DB p95 et le
Threads_runningsous charge ; - la taille max d’un pic attendu (RPS ou sessions simultanées) ;
- le nombre de workers “utiles” avant que MySQL ne devienne le goulot (vous le voyez quand augmenter
pm.max_childrenaugmente les temps de réponse).
RAM : le vrai budget entre InnoDB, PHP, OPcache et caches
La RAM est le poste le plus mal dimensionné en PrestaShop, parce que les symptômes sont trompeurs : tant que ça swappe un peu, ça « marche »… puis les p99 explosent. Côté PHP, vous devez compter : (1) RSS moyen d’un worker en charge (mesurez-le, ne devinez pas), (2) OPcache, (3) marge pour les pointes (BO, modules lourds, PDF).
Si OPcache est trop petit, vous vous reprenez de la compilation et du churn mémoire à chaque déploiement… et parfois au quotidien si votre nombre de scripts dépasse la capacité.
Côté base, l’ordre de grandeur qui compte est le working set des index et des pages de données fréquemment lues. Sur un serveur dédié à MySQL, une règle pratique est 60 à 75% de RAM pour innodb_buffer_pool_size. Sur une machine web+DB, cette règle est dangereuse : vous devez d’abord figer le budget PHP-FPM, puis allouer le reste au buffer pool, sinon votre site se met à tuer des workers sous pression mémoire.
Un calcul rapide, à adapter à vos mesures (PrestaShop 8.2/9, PHP 8.2/8.3) :
- 30 workers FPM × 220 MB RSS ≈ 6,6 GB
- OPcache 512 MB + marge interned strings + JIT désactivé ≈ 0,7 GB
- Redis (sessions/cache) : 1 à 4 GB selon usage
- OS + page cache : 4 à 8 GB
Sur un serveur à 64 GB, il vous reste typiquement 40 à 50 GB pour InnoDB. Et si vous activez Varnish (cache HTTP) en RAM, il faut le budgéter aussi.
Deux conseils “anti-surprise” en prod :
- Zéro swap en charge (ou swap quasi nul). Un serveur qui commence à swapper pendant un pic devient imprévisible.
- Imports : ils font chuter le taux de hit InnoDB si le buffer pool est trop juste, et le FO prend la vague. Sur des catalogues 100 000+, c’est l’une des premières causes de “ça allait hier, c’est lent aujourd’hui”.
Pour les paramètres OPcache et la logique de sizing, gardez sous la main : PHP OPcache : paramètres recommandés pour optimiser les performances.
Stockage : NVMe, IOPS, latence et découpage DB/médias
Pour un gros catalogue, le stockage n’est pas « juste » de la capacité. Ce qui fait mal, c’est la latence (p95/p99) sur des lectures aléatoires d’index et des fsync sur les writes InnoDB. Une paire NVMe décente (datacenter, pas du consumer) écrase en pratique du SATA SSD en latence et en IOPS soutenus, et ça se voit immédiatement sur les pages avec tri, filtres, facettes, et sur les requêtes qui touchent des tables d’association volumineuses. Si vous hésitez encore sur NVMe vs SSD, l’article à garder en référence côté e-commerce est : Serveurs dédiés infogérés e-commerce : NVMe, Redis, Varnish et haute disponibilité.
Côté RAID, le choix classique sur un unique serveur est RAID1 (2 disques) pour la simplicité et la résilience. RAID10 a du sens si vous avez 4 NVMe et un workload write plus lourd (imports/stock/flux). À noter : si vous mettez DB + images + logs sur le même volume, vous vous fabriquez des collisions d’I/O. À 100 000 produits, séparer au minimum (1) volume DB, (2) volume médias, (3) volume backups/snapshots est souvent un meilleur gain que d’ajouter 2 cœurs.
Une grille de découpage simple (pragmatique) :
- DB (NVMe, priorité latence) : MySQL datadir + binlogs (si possible séparés selon votre politique).
- Médias (capacité + inodes) :
/img, uploads, caches d’images, éventuellement sur un volume distinct. - Logs & backups : éviter que des logs en rotation ou une sauvegarde complète n’impactent le disque DB.
La gestion du disque sur PrestaShop est aussi un sujet “hygiène” : tables de logs qui gonflent, tables de recherche, tables de stats modules. Sans nettoyage, vous dimensionnez pour de la dette technique. Si vous voulez un point d’entrée pragmatique (DB et fichiers), utilisez un outil de remise à plat et mesurez avant/après : MedCleanMyShop PrestaShop : nettoyage base de données et fichiers automatisé. Attention : nettoyer/archiver implique des risques fonctionnels (perte d’historique module), donc faites-le sur pré-prod avec sauvegarde et validation métier.
Pile logicielle sur serveur dédié : ce qui change le dimensionnement (et ce qui ne le changera jamais)
Le « dimensionnement matériel » se fait rarement sans choisir une pile cohérente. Sur Debian 12/13, la combinaison la plus stable en 2026 pour PrestaShop 8.2/9 reste : Nginx (ou Apache event MPM), PHP-FPM, MySQL/MariaDB, Redis. Le tuning OS (limits, sysctl, file descriptors, TCP backlog) ne compense pas un sous-dimensionnement, mais il évite des plafonds absurdes. Si vous partez de zéro, suivez la base d’installation et d’optimisation système, puis ajustez : Serveur dédié PrestaShop : installation et optimisation Debian pour gros catalogue.
Le point qui change vraiment le dimensionnement CPU/RAM, c’est la stratégie de cache :
- si vous laissez PrestaShop servir dynamiquement la plupart des pages (catégories, recherche, produit), le serveur doit absorber des bursts de PHP + SQL ;
- si vous activez un cache HTTP (Varnish ou cache Nginx) et que vous purgez proprement, votre charge web devient beaucoup plus « plate » et vous pouvez à la fois réduire les workers et stabiliser la base.
Côté applicatif, les optimisations core (cache Smarty, CCC, CDN) restent indispensables pour ne pas dépenser du CPU inutilement : PrestaShop : optimiser performance via cache Smarty, CCC et CDN et, pour le volet SEO/perf, SEO PrestaShop : checklist technique 2025 pour indexation et performance.
Point “GEO” utile (sans sur-promettre) : si votre clientèle est majoritairement en France/Benelux, héberger vos nœuds web et DB dans l’UE simplifie généralement la gouvernance (RGPD — Règlement (UE) 2016/679) et réduit la latence réseau moyenne. Ce n’est pas une règle absolue (un bon CDN peut servir vite partout), mais à échelle catalogue + checkout, quelques millisecondes répétées sur des dizaines d’allers-retours (TLS, requêtes API, back-office, webhooks) finissent par se voir dans les p95.
Ce qui ne disparaîtra pas, en revanche : la recherche et les facettes sont des aspirateurs à CPU/SQL si vous restez sur l’index natif MySQL. À 100 000 produits, le core peut tenir, mais ça se paye en latence (et en complexité de tuning SQL). La règle pragmatique : si la recherche interne est critique business, basculez sur un moteur dédié (Meilisearch/Elasticsearch/Algolia), et vous dimensionnerez autrement (moins de pression DB, plus de RAM pour l’index externe). Pour trancher : Moteur de recherche marketplace : Meilisearch, Elasticsearch ou Algolia et, pour comprendre le cœur de l’index natif, Index de recherche PrestaShop : fonctionnement, tables SQL et pondérations.
Mesurer pour dimensionner : sans métriques, vous achetez au hasard
Un dimensionnement matériel sérieux part d’objectifs observables : TTFB p95, p99 checkout, taux d’erreur, saturation CPU, contention MySQL. Ne vous contentez pas de « load average ». Sur PrestaShop, les signaux utiles sont : temps de réponse FPM, utilisation OPcache, Threads_running MySQL, Innodb_buffer_pool_reads (miss), latence disque, et surtout le p95 des requêtes SQL par endpoint (produit/catégorie/panier).
Pour mettre ça en place vite, Netdata est très efficace en diagnostic : Netdata : activer et configurer les collectors pour monitoring temps réel.
Si vous voulez sortir du “graphing” pour aller vers l’alerte et le capacity planning, passez à Prometheus + Alertmanager : Prometheus : configuration des alertes, métriques et requêtes PromQL. Le but n’est pas de collectionner des dashboards, mais de définir des seuils exploitables. Exemples de signaux actionnables (à adapter) :
phpfpm_listen_queuenon nul plus de 5 minutes ⇒ workers insuffisants ou DB en retard ;- p95 MySQL qui grimpe quand vous augmentez les workers FPM ⇒ goulot DB (index, contention, I/O) ;
- baisse brutale du hit rate buffer pool lors d’un import ⇒ buffer pool trop serré, requêtes “wide scans”, ou import qui pollue le cache.
Côté SQL, dimensionner sans slow query log revient à dimensionner pour compenser des requêtes foireuses. Le core PrestaShop n’est pas exempt de patterns discutables, et les modules sont souvent le vrai problème. Avant d’ajouter 64 GB de RAM, regardez vos requêtes lentes, vos index manquants, et vos N+1 : PrestaShop MySQL : analyser slow query log et optimiser index et Optimisation de code PrestaShop : diagnostiquer lenteurs et requêtes SQL. Un serveur « plus gros » ne répare pas un tri sans index sur une table d’association à plusieurs millions de lignes.
Pour éviter le piège “ça marche en moyenne”, définissez un mini-contrat de performance interne (SLO) :
- p95 pages catégorie/produit (à chaud) ;
- p95 ajout panier et étapes checkout ;
- taux d’erreur 5xx ;
- temps de traitement des imports (et leur impact sur le FO).
Sans ces repères, vous ne saurez pas si l’achat d’un CPU supérieur a réellement amélioré la capacité… ou juste masqué un problème SQL.
Configs matérielles types (2026) pour 100 000 produits, et les signaux pour sortir du mono-serveur
Sur un unique serveur dédié (web+DB), si vous voulez une base solide pour 100 000 produits avec trafic modéré et cache activé, un profil « propre » en 2026 ressemble à : 8 à 12 cœurs hautes fréquences, 64 GB RAM, 2× NVMe 1 TB en RAID1, réseau 1 Gbps, et une vraie politique de backups hors machine. C’est à la fois assez pour tenir des pics (si Varnish/CDN font le job) et assez confortable pour ne pas micro-manager chaque worker. Pour un trafic plus soutenu (recherche/facettes actives, imports fréquents, beaucoup de déclinaisons), passez à 16 cœurs et 128 GB, pas pour « faire joli » : pour absorber simultanément FPM + InnoDB buffer pool + Redis sans arbitrage agressif.
Repères concrets (profils) — à ajuster selon votre réalité (déclinaisons, langues, modules, cache) :
| Profil | Quand il convient | CPU | RAM | Stockage |
|---|---|---|---|---|
| “Catalogue 100k + cache HTTP efficace” | majorité des hits cacheables, peu de BO simultané | 8–12 cœurs HF | 64 GB | 2× NVMe RAID1 |
| “100k + facettes/recherche MySQL + imports fréquents” | DB très sollicitée, écritures régulières | 16 cœurs | 128 GB | 2–4× NVMe (RAID10 si writes) |
| “100k + moteur de recherche externe” | search offload (Meili/ES), DB plus stable | 12–16 cœurs | 64–128 GB | NVMe + RAM dédiée à l’index externe (sur autre nœud) |
Les signaux qui indiquent que vous devez arrêter de tout faire sur une seule box, même si elle est puissante :
Threads_runningMySQL décolle pendant le trafic (et ne redescend pas vite),- p95 SQL augmente quand vous montez les workers FPM (effet “plus de concurrence = plus de contention”),
- vos imports font baisser le taux de hit du buffer pool et dégradent le checkout,
- vous avez besoin d’un moteur de recherche externe qui mérite ses propres ressources,
- vos médias et backups perturbent la latence DB (I/O contention).
À ce stade, le meilleur ROI n’est plus « ajouter 32 GB », mais séparer DB et web, puis ajouter un nœud cache/recherche si nécessaire. Si vous basculez vers une architecture à plusieurs nœuds, prévoyez un vrai reverse-proxy/load balancer (health checks, sticky sessions si besoin) : HAProxy : configuration avancée ACL, health checks et sticky sessions.
Avant de signer pour un serveur dédié « dimensionné pour 100 000 produits », faites une checklist de validation orientée risques :
- mesurer le RSS moyen d’une requête FO/BO (en charge, pas à vide),
- fixer un budget de workers (et vérifier la file d’attente FPM),
- définir le buffer pool sans swap en charge,
- réserver du disque pour binlogs/backups/snapshots (et tester un restore),
- simuler une journée d’import + un pic de trafic (même avec un test k6/wrk en pré-prod),
- valider que la volumétrie médias (fichiers + inodes) ne vous enferme pas (CDN/object storage ou volume dédié).
Si vous n’avez pas de pré-prod, vous dimensionnez à l’aveugle : dans ce cas, prenez volontairement « trop » de RAM (64 GB a minima) et du NVMe, parce que ce sont les deux leviers qui rattrapent le mieux les erreurs de modélisation, sans vous enfermer dans une refonte immédiate.
