2012-11-26 14 views
19

In un nuovo progetto con molto traffico, stiamo pensando a come strutturare la nostra app Symfony2 per sfruttare le cache e essere pronti ad essere più aggressivi in ​​futuro. Mi piacerebbe conoscere la tua opinione.Come strutturare un'app Symfony2 con ESI?

Diciamo che un utente richiede a una pagina un elenco di luoghi. Questa pagina:

- 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) 

Il codice HTML potrebbe essere come:

<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> 

Il codice HTML verrà memorizzato nella cache sul gateway (Symfony o vernice). L'elenco dei luoghi verrà memorizzato nella cache la maggior parte del tempo anche sul gateway. Le richieste di dati dell'utente saranno quelle che vengono chiamate e non memorizzate nella cache (non inizialmente almeno).

Domande:

  1. Come ti senti su questa struttura?
  2. Se l'utente è anonimo, è possibile evitare di eseguire esi-include per i dati utente? Anche se ho un cookie per l'utente anon? Come?
  3. L'esi-include per il menu utente ha senso?
  4. O dovremmo dimenticare ESI e passare sempre attraverso il controller (ad esempio la memorizzazione nella cache della visualizzazione renderizzata dei dati comuni)?
  5. Dovremmo spostare le 2 richieste ESI che richiedono che i dati dell'utente siano chiamate AJAX, invece di attendere sul server?
  6. È un buon approccio per ridimensionare se abbiamo bisogno di farlo in fretta? Cosa sarebbe meglio?

grazie mille!

risposta

4

Abbiamo usato Varnish su un sito per il caching di pagine intere e ho utilizzato Symfony2 per alcuni anni, ma tieni presente che non ho usato Varnish + Symfony2 + ESI in alcun ambiente di produzione.

  1. Penso che l'idea di base sia OK. Se il menu è lo stesso in molte pagine e l'elenco di luoghi è lo stesso su molte pagine, si ottiene il contenuto comune memorizzato nella cache di Varnish o Symfony. Poiché Varnish di solito tiene in memoria la cache, ottieni i tuoi contenuti più velocemente e non devi chiamare il rendering e il codice di interrogazione del DB a ogni richiesta.

    La parte difficile è rendere le richieste ESI memorizzate nella cache se l'utente è connesso. Come noto, nella configurazione di Varnish di default, le richieste con Cookie non vengono mai memorizzate nella cache. Se si tende a passare i cookie alle richieste ESI, tali risposte ESI non saranno condivise tra gli utenti.

    È possibile provare a creare alcune regole dall'URL, ma se si utilizzano gli helper predefiniti di Symfony twig, gli URL generati sono/_internal/..., quindi potrebbe essere difficile distinguere tra pubblico e privato.

    Inoltre, è possibile configurare di ignorare sempre i cookie se viene passato Cache-Control: public. Questo viene fatto per impostazione predefinita in Symfony:

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

    Come si vede dal codice, se avete public direttiva, la risposta non sarà mai privata.

    Non ho trovato il modo in cui Varnish elabora questa direttiva, poiché, a quanto ho capito, non memorizza nella cache alcuna richiesta che dispone di cookie per impostazione predefinita. Quindi penso che devi modificare la configurazione per realizzare questo.

  2. Se la pagina principale deve anche essere memorizzata nella cache, non vedo come è possibile saltare gli include.

    Suppongo che JS sia richiesto per gli utenti registrati (non per i robot di ricerca), quindi suggerirei di utilizzare Javascript per differenziare il caricamento dei dati utente.

    Il codice Javascript può apparire se l'utente ha un cookie session-id ecc. E fare richiesta per ottenere i dati solo in questo caso. Potrebbe anche essere una buona idea impostare un altro cookie, come _loggedin per evitare che il codice Javascript ottenga l'id della sessione.

    Gli utenti non registrati possono inoltre disporre di alcuni dati nei cookie, ad esempio _likedPost:1,2,132. Javascript può ottenere questo cookie e apportare alcune correzioni HTML senza nemmeno fare la richiesta aggiuntiva.

    Come abbiamo fatto con questi cookie: abbiamo separato i cookie solo JS dai cookie dell'applicazione. Lo abbiamo fatto secondo alcuni schemi, come _\w per i cookie JS. Quindi abbiamo modificato la configurazione di Varnish per dividere l'intestazione Cookie e rimuovere questi cookie solo JS. Quindi, se non è rimasto nessun altro cookie, la risposta è condivisa con tutti. Applicazione (Symfony) non ottiene quei cookie, in quanto sono spogliati.

  3. Penso che lo faccia se è lo stesso in ogni pagina.

  4. Penso che ESI sia buono come Varnish può contenere cache in memoria. Quindi potrebbe essere che non avrebbe nemmeno fatto query sul tuo disco rigido per il contenuto. Poiché la cache del controller potrebbe essere anche in memoria, penso che Varnish cercherebbe la cache più veloce di Symfony con tutto il routing, il codice PHP, l'inizializzazione dei servizi ecc.

  5. Dipende, ma penso che potrebbe essere un approccio migliore Tieni presente che le cache vivono vite diverse. Ad esempio, se l'elenco dei luoghi viene memorizzato nella cache per 2 ore, al termine di questo periodo i posti possono essere cambiati: alcuni nuovi elementi sono nuovi nell'elenco e alcuni di essi sono mancanti. La tua lista per l'utente è ancora vecchia (memorizzata nella cache), ma tu fornisci i dati dell'utente sul nuovo elenco - alcuni dei dati non sono necessari, alcuni di essi sono mancanti.

    Potrebbe essere un approccio migliore per ottenere posti caricati da javascript, ad esempio la ricerca di alcuni attributi HTML come data-list-item-id e quindi effettuare una richiesta Ajax query di dati su questi elementi. In questo caso i dati dell'utente verranno sincronizzati con l'attuale elenco memorizzato nella cache e sarà possibile effettuare 1 richiesta Ajax per entrambi gli elenchi anziché 2.

  6. Se l'invalidazione della cache (richieste PURGE) non viene utilizzata, tutta la sheme della cache HTTP è effettivamente buona scalare. È possibile ridimensionare l'applicazione su diversi server e configurare Varnish in modo che vengano chiamati in modo casuale, in base a una regola o semplicemente per usarne uno come fail-safe. Se la larghezza di banda è ancora troppo grande, puoi sempre modificare i timeout della cache e altre configurazioni.

+0

grazie un sacco Barius, Stiamo facendo le richieste di dati degli utenti in Ajax, invece che in ESI. Quindi sono d'accordo con te. Vediamo come va. La parte chiave e divertente sarà evitando l'uso di PURGE. È l'obiettivo essere in grado di scalare. – fesja

+0

Condividi come va dopo aver provato –