2012-11-26 7 views
19

Sur un nouveau projet avec beaucoup de trafic, nous réfléchissons à la façon de structurer notre application Symfony2 pour profiter des caches et être prêts à être plus agressifs dans le futur. J'aimerais connaître votre opinion.Comment structurer une application Symfony2 avec ESI?

Supposons qu'un utilisateur demande à une page une liste de lieux. Cette page a:

- list 
    - common data (title, author, description) 
    - user data (the user likes the list + other data) 
- first 20 places 
    - common data (title, photo of each place) 
    - user data (the rates of the user for those places) 

Le code HTML pourrait ressembler à:

<html>... 
<body> 
    <header> 
    ... 
    <!-- Embed the top user menu --> 
    <esi:include src="http://example.com/profile/menu" /> 
    ... 
    </header> 

    <content> 
    ... 
    common data of the list 
    ... 
    <!-- Embed the common data of the first 20 places, the same for everyone --> 
    <esi:include src="http://example.com/lists/17/places" /> 
    ... 
    <!-- Embed the user data of the list (used in JS) --> 
    <esi:include src="http://example.com/lists/17/user" /> 
    ... 
    <!-- Embed the user data of the list of places (used in JS) --> 
    <esi:include src="http://example.com/lists/17/places/user" /> 
    ... 
    </content> 
</body>  
</html> 

Le code HTML sera mis en cache sur la passerelle (Symfony ou vernis). La liste des lieux sera également mise en cache la plupart du temps sur la passerelle. Les demandes de données d'utilisateur seront celles qui sont appelées et ne seront pas mises en cache (pas au moins initialement).

Questions:

  1. Comment pensez-vous de cette structure?
  2. Si l'utilisateur est anonyme, puis-je éviter de créer les esi-includes pour les données de l'utilisateur? Aussi, si j'ai un cookie pour l'utilisateur anon? Comment?
  3. Est-ce que l'esi-include pour le menu utilisateur a du sens?
  4. Ou devrions-nous oublier ESI et aller toujours à travers le contrôleur (en cache la vue rendue des données communes par exemple)?
  5. Devrions-nous déplacer les 2 demandes ESI qui demandent que les données utilisateur soient des appels AJAX, au lieu d'attendre sur le serveur?
  6. Est-ce une bonne approche à l'échelle si nous devons le faire rapidement? Quel serait le meilleur?

merci beaucoup!

Répondre

4

Nous avons utilisé Varnish sur un site pour la mise en cache de pages entières et j'utilise Symfony2 depuis quelques années, mais gardez à l'esprit que je n'ai pas utilisé Varnish + Symfony2 + ESI sur n'importe quel environnement de production.

  1. Je pense que l'idée de base est OK. Si le menu est le même dans de nombreuses pages et que la liste des emplacements est la même sur de nombreuses pages, vous obtenez du contenu commun mis en cache par Varnish ou le cache inverse de Symfony. Comme Varnish conserve généralement le cache en mémoire, vous obtenez votre contenu plus rapidement et vous n'avez pas besoin d'appeler le rendu et le code d'interrogation DB à chaque requête. La partie la plus difficile est de mettre ces requêtes ESI en cache si l'utilisateur est connecté. Comme je le sais, dans la configuration par défaut de Varnish, les requêtes avec Cookie ne sont jamais mises en cache. Si vous avez tendance à transmettre des cookies aux demandes ESI, ces réponses ESI ne seront pas partagées entre les utilisateurs.

    Vous pouvez essayer d'établir des règles à partir de l'URL, mais si vous utilisez des aides par défaut Twig Symfony, les URL générées sont/_internal/..., il peut donc être difficile de distinguer les utilisateurs publics et privés.

    Vous pouvez également configurer pour toujours ignorer les cookies si Cache-Control: public est passé. Cela se fait par défaut dans Symfony:

    if ($this->isPrivateRequest($request) && !$response->headers->hasCacheControlDirective('public')) { 
        $response->setPrivate(true); 
    } 
    

    Comme vous le voyez à partir du code, si vous avez public directive, la réponse ne sera jamais privé.

    Je n'ai pas trouvé comment Varnish traite cette directive - si je comprends bien, il ne met pas en cache les requêtes qui ont un cookie par défaut. Donc, je pense que vous devez modifier la configuration pour y parvenir.

  2. Si la page principale doit également être mise en cache, je ne vois pas comment vous pouvez ignorer les inclusions.

    Je suppose que JS est requis pour vos utilisateurs enregistrés (pas les robots de recherche), donc je suggère d'utiliser Javascript pour différer le chargement des données de l'utilisateur.

    Le code Javascript peut regarder si l'utilisateur a le cookie session-id etc. et fait la demande pour obtenir les données seulement dans ce cas. Cela peut également être une bonne idée de définir un autre cookie, comme _loggedin pour éviter que le code Javascript n'obtienne l'identifiant de la session.

    Non connecté les utilisateurs peuvent aussi avoir certaines données dans les cookies, comme _likedPost:1,2,132. Javascript peut obtenir ce cookie et faire quelques corrections HTML sans même faire la demande supplémentaire. Comme nous l'avons fait avec ces cookies: nous avons séparé les cookies JS uniquement des cookies d'application. Nous avons fait cela par un modèle, comme _\w pour les cookies JS. Ensuite, nous avons modifié la configuration de Varnish pour diviser l'en-tête Cookie et supprimer ces cookies JS uniquement. Ensuite, s'il n'y a plus d'autre cookie, la réponse est partagée avec tout le monde. Application (Symfony) ne reçoit pas ces cookies, car ils sont dépouillés.

  3. Je pense que c'est le cas si c'est la même chose dans chaque page.

  4. Je pense que ESI est bon car Varnish peut contenir du cache en mémoire. Il se peut donc qu'il ne fasse même pas de requêtes sur votre disque dur pour le contenu. Comme le cache de votre contrôleur peut aussi être en mémoire, je pense que Varnish chercherait le cache plus rapidement que le framework Symfony avec tout le routage, le code PHP, l'initialisation des services, etc.

  5. Cela dépend, mais je pense qu'il pourrait être une meilleure approche. Gardez à l'esprit que les caches vivent différentes vies. Par exemple, si votre liste de lieux est mise en cache pendant 2 heures, à la fin de cette période, les lieux peuvent avoir changé - certains nouveaux éléments sont nouveaux dans la liste et certains d'entre eux sont manquants. Votre liste à l'utilisateur est toujours l'ancienne (en cache), mais vous fournissez les données de l'utilisateur sur la nouvelle liste - certaines données ne sont pas nécessaires, d'autres sont manquantes.

    Il serait peut-être préférable d'obtenir des endroits chargés en javascript, par exemple en recherchant un attribut HTML tel que data-list-item-id, puis d'effectuer une requête ajax demandant des données sur ces éléments. Dans ce cas, vos données utilisateur seront synchronisées avec la liste en cache actuelle et vous pouvez faire une requête ajax pour les deux listes au lieu de 2.

  6. Si l'invalidation du cache (requêtes PURGE) n'est pas utilisée, tout le cache HTTP est en effet bon mettre à l'échelle. Vous pouvez mettre l'application à l'échelle sur plusieurs serveurs et configurer Varnish pour les appeler de façon aléatoire, selon une règle ou simplement en utilisant l'un d'entre eux comme sécurité intégrée. Si la bande passante est encore trop grande, vous pouvez toujours modifier les délais d'expiration du cache et d'autres configurations.

+0

merci beaucoup Barius, Nous faisons les demandes de données utilisateur en ajax, au lieu de ESI. Donc je suis d'accord avec toi. Voyons comment ça se passe. La partie clé et amusante sera d'éviter d'utiliser PURGE. C'est l'objectif de pouvoir évoluer. – fesja

+0

Partagez comment ça se passe après l'avoir essayé –

Questions connexes