PERFORMANCE SYMFONY & FRANKENPHP

Votre app Symfony, dix fois plus rapide.

Analyse des lenteurs avec Blackfire, chasse aux requêtes base de données redondantes, cache multi-niveaux, moteur FrankenPHP. Objectif : passer sous 100 ms de temps de réponse sur les pages critiques (en conditions de charge réelle), sans réécrire l'application.

§ 01 — Le problème

Le problème.

Sans expert
  • Pages à 3–5 secondes — +40 % de visiteurs qui quittent, -20 % de conversion, un référencement qui plafonne.
  • Requêtes redondantes invisibles — OK en développement avec 10 lignes, catastrophique en production avec 10 000.
  • Facture cloud qui explose — Ajouter des serveurs masque le problème et multiplie la facture.
  • Pic saisonnier imminent — Vous savez que l'infrastructure ne va pas tenir — mais personne ne sait où chercher.
  • Pas de mesure fiable — « On dirait que la base rame » — mais aucun outil de mesure en production.
Avec Vulcain
  • Mesure des lenteurs en production avec blackfire
  • Chasse systématique aux requêtes redondantes
  • Cache sur plusieurs niveaux (navigateur
  • Mémoire
  • Base)
  • Moteur frankenphp en mode persistant quand pertinent. chaque gain est mesuré avant/après
  • Procédure pic de charge livrée.
§ 02 — Ce qui est livré

Ce qui est livré.

§ 01

Analyse des lenteurs

Instrumentation en production, captures sur les pages les plus lentes et les plus appelées. Visualisation graphique du temps passé dans chaque partie du code.

  • Mesure en production
  • Top 20 des pages lentes
  • Vue graphique
  • Comparaisons avant / après
§ 02

Requêtes base de données

Détection des requêtes redondantes, jointures optimisées, projections ciblées, cache de deuxième niveau, pagination efficace.

  • Chasse aux redondances
  • Jointures optimisées
  • Projections ciblées
  • Cache base de données
§ 03

Cache applicatif

Cache mémoire rapide (Redis) pour les données métier, cache des calculs coûteux, stratégies d'invalidation fines.

  • Redis
  • Cache des calculs coûteux
  • Invalidation fine
  • Protection pics de charge
§ 04

Cache côté client

Varnish ou cache HTTP Symfony, blocs dynamiques dans du contenu cacheable, purge à la demande.

  • Varnish / HTTP
  • Blocs dynamiques
  • Purge à la demande
  • Stratégie de durée de vie
§ 05

FrankenPHP persistant

Passage à FrankenPHP quand pertinent : gain 3 à 10 × grâce au démarrage unique de l'application. Traitements lourds exécutés en arrière-plan (emails, exports).

  • FrankenPHP production
  • Mode persistant
  • Arrière-plan asynchrone
  • File d'attente Redis
§ 06

Vitesse perçue

Compression et regroupement des ressources, HTTP/2, préchargement, chargement différé, images optimisées. Scores Core Web Vitals verts pour un référencement solide.

  • Ressources optimisées
  • HTTP/2 + préchargement
  • Core Web Vitals
  • Images optimisées
src/Infrastructure/Stocks/StockSyncProcessor.php php
<?php
declare(strict_types=1);

namespace App\Infrastructure\Stocks;

// AVANT : 35 000 INSERT/UPDATE individuels, transactions longues qui
// verrouillaient la table pendant les heures ouvrées.
//
// APRÈS : pagination par lots de 500, un seul upsert SQL par lot,
// signature de payload pour ignorer les rows inchangées.
final class StockSyncProcessor
{
    public function __construct(
        private readonly \Doctrine\DBAL\Connection $db,
        private readonly StockSourceClient $client,
    ) {}

    public function syncBatch(string $promoterId, int $offset, int $limit = 500): SyncReport
    {
        $units = $this->client->fetchUnits($promoterId, $offset, $limit);
        if ($units === []) {
            return SyncReport::empty();
        }

        // INSERT ... ON CONFLICT DO UPDATE : un seul aller-retour SQL
        // pour 500 lignes. Idempotent grâce à la PK (programme, lot).
        $sql = <<<SQL
            INSERT INTO programme_units (programme_id, lot_id, status, price_cents, signature, synced_at)
            VALUES {$this->placeholders(count($units))}
            ON CONFLICT (programme_id, lot_id) DO UPDATE SET
                status      = EXCLUDED.status,
                price_cents = EXCLUDED.price_cents,
                signature   = EXCLUDED.signature,
                synced_at   = EXCLUDED.synced_at
            WHERE programme_units.signature IS DISTINCT FROM EXCLUDED.signature
            SQL;

        $written = $this->db->executeStatement($sql, $this->flatten($units));

        return SyncReport::of(processed: count($units), written: $written);
    }
}

Sync quotidienne des stocks : 35 000 lots traités par paquets de 500 via un upsert SQL atomique. Idempotent (relance sans doublons), exécution en arrière-plan via Symfony Messenger.

§ 04 — Tarifs & délais
§ 01

Audit de performance

5 jours · forfait

Mesure en production + rapport des points de blocage. Vous avez la carte des gains possibles avant de décider.

  • Mesure en production
  • Top 20 des pages lentes
  • Rapport 20 pages
  • Plan priorisé
  • Restitution 1 h
§ 02

Optimisation ciblée

2 à 4 semaines

Audit + mise en œuvre des gains rapides : requêtes redondantes, cache mémoire, index base de données. Objectif : temps de réponse divisé par 3 à 5.

  • Audit complet
  • Gains rapides livrés
  • Mesures avant / après
  • Supervision livrée
  • Procédure pic de charge
§ 03

Optimisation profonde

4 à 8 semaines

Refonte ciblée des zones critiques : FrankenPHP, cache côté client Varnish, reconstruction des pages à fort trafic. Objectif : temps de réponse sous 100 ms.

  • Tout de l'optimisation ciblée
  • FrankenPHP en production
  • Cache Varnish
  • Refonte des pages à fort trafic
  • 3 mois de supervision

Tarifs sur devis après cadrage · forfait ou régie selon le format

§ 05 — Cas client · CRM immobilier neuf · synchronisation de stocks

Doric

Synchronisation quotidienne des stocks de programmes immobiliers depuis plus de 100 promoteurs : 5 000 programmes, 35 000 lots mis à jour chaque jour. Pagination par lots, opérations Doctrine en masse, transactions courtes, idempotence par signature et file d'attente Redis. La sync passée d'aléatoire à silencieuse, sans bloquer le CRM en pleine journée.

  • Symfony 6
  • Sylius
  • Redis
  • Varnish
  • FrankenPHP
100+
promoteurs synchronisés
35 000
lots mis à jour / jour
5 000
programmes immo
§ 04 — Questions fréquentes

Questions sur la performance .

§ 01 FrankenPHP, c'est utilisable en production ?

Oui, depuis 2024. Plusieurs de mes clients tournent en FrankenPHP en production avec d'excellents résultats. Le gain vient du mode persistant : l'application PHP est démarrée une seule fois, puis traite les requêtes en mémoire. Gain typique : 3 à 10 ×.

§ 02 Ajouter un cache Redis, ça change quoi ?

Dépend du cas. Pour garder en mémoire des calculs métier coûteux : énorme gain. Pour des requêtes simples : gain modéré, car la base de données fait déjà du bon travail. On mesure avant / après.

§ 03 Et l'hébergement ?

Parfois, le vrai problème est l'hébergeur. Mutualisé OVH → Scaleway, Clever Cloud ou AWS : gain d'un facteur 3 sur la performance sans toucher au code. Je regarde toujours ce levier.

§ 04 Combien de temps pour voir des résultats ?

2 à 5 jours pour identifier les points de blocage, 1 à 2 semaines pour livrer les premiers gains. Un gain 2 à 5 × est souvent atteignable en 2 semaines sur une application non optimisée.

§ 05 Blackfire en production, c'est sans risque ?

Oui, c'est fait pour ça. Blackfire est conçu pour être branché en production : surcoût négligeable (moins de 2 % en charge), échantillonnage configurable, ciblage par route ou par utilisateur.

§ 06 Le cache, ça cache aussi les bugs ?

Oui, c'est le piège. Je ne mets jamais de cache sans stratégie d'invalidation claire, sans suivi du taux d'utilisation, sans tests. Un mauvais cache est pire que pas de cache du tout.

§ 06 — Voir aussi
§ 08 — Mettre la forge au travail

15 minutes pour savoir
si on peut forger ensemble.

Un appel, pas un formulaire de 12 champs. Vous m'expliquez votre besoin, je vous dis honnêtement si je suis la bonne personne, on repart avec une prochaine étape claire.

  • 01
    Compte-rendu écrit et estimation envoyés sous 24 h.
  • 02
    Aucun engagement. Aucune relance commerciale.
  • 03
    Si ce n'est pas pour moi, je vous oriente vers un confrère.
symfony