2009-12-18 9 views
21

J'ai écrit une application Google App Engine qui génère par programme un ensemble de code HTML qui est vraiment la même sortie pour chaque utilisateur qui se connecte à mon système, et je sais que cela va être inefficace lorsque le code passe en production. Donc, j'essaie de trouver la meilleure façon de mettre en cache les pages générées. L'option la plus probable consiste à générer les pages et à les écrire dans la base de données, puis à vérifier l'heure de l'opération de mise en place de la base de données pour une page donnée par rapport à la dernière mise à jour du code. Ensuite, si le code est plus récent que le dernier mis à la base de données (pour une demande HTML particulière), le nouveau HTML sera généré et servi, et mis en cache dans la base de données. Si le code est plus ancien que le dernier mis à la base de données, alors je vais juste obtenir le HTML directement à partir de la base de données et le servir (évitant ainsi tout le gaspillage de CPU pour générer le HTML). Je ne cherche pas seulement à minimiser les temps de chargement, mais à minimiser l'utilisation du processeur. Cependant, un problème que j'ai, c'est que je ne peux pas comprendre comment vérifier par programme quand la version du code téléchargé sur le moteur de l'application a été mis à jour.Google App Engine - Caching généré HTML

Je suis ouvert à toutes les suggestions sur cette approche, ou d'autres approches pour la mise en cache html généré. Notez que bien que memcache puisse aider dans cette situation, je crois que ce n'est pas la solution finale puisque je n'ai vraiment besoin de recréer le html que lorsque le code est mis à jour (par opposition à chaque fois que memcache expire).

+5

Mais ... c'est ce à quoi sert memcache! Sauf si la génération du HTML prend vraiment très, très longtemps, vous êtes en train de le surpasser. –

+0

En outre, il semble que le modèle memcache App Engine ne met en cache que les accès au magasin de données, pas la génération de code: à partir de: http://code.google.com/appengine/docs/python/memcache/usingmemcache.html - Memcache est généralement utilisé avec le modèle suivant: L'application reçoit une requête de l'utilisateur ou de l'application. L'application vérifie si les données nécessaires pour satisfaire cette requête sont dans memcache. Si les données sont dans memcache, l'application utilise ces données. Si les données ne sont pas dans memcache, l'application interroge le magasin de données et stocke les résultats dans memcache pour les demandes futures. –

+2

@Alexander - Vous pouvez mettre tout ce que vous voulez dans Memcache, ce qu'ils mentionnent est le cas d'utilisation typique. –

Répondre

6

Afin de vitesse:

  1. memcache
  2. HTML mis en cache dans le magasin de données
  3. pleine page génération

Votre solution de mise en cache doit en tenir compte. Essentiellement, je recommanderais probablement d'utiliser memcache de toute façon. Il sera plus rapide que d'accéder au magasin de données dans la plupart des cas et lorsque vous générez un gros bloc de HTML, l'un des principaux avantages de la mise en cache est que vous n'avez pas à subir la pénalité d'accès aux données le magasin. Si vous mettez en cache en utilisant le magasin de données, vous avez toujours la pénalité d'E/S. La différence entre régénérer tout et extraire du fichier html mis en cache dans le magasin de données est susceptible d'être assez faible, sauf si vous avez une page très complexe. Il est probablement préférable d'obtenir un tas de caches de mémoire cache très rapides sur memcache et de faire une régénération complète de temps en temps plutôt que de faire un appel au magasin de données à chaque fois. Rien ne vous empêche d'invalider le code HTML mis en cache dans memcache lors de la mise à jour, et si votre trafic est suffisamment élevé pour le justifier, vous pouvez toujours créer un système de mise en cache à plusieurs niveaux.

Cependant, ma principale préoccupation est qu'il s'agit d'une optimisation prématurée. Si vous n'avez pas encore le trafic, maintenez la mise en cache au minimum. App Engine fournit un ensemble d'outils d'analyse des performances très pratiques et vous devriez les utiliser pour identifier les goulots d'étranglement après avoir généré au moins quelques QPS de trafic.

Chaque fois que vous faites l'optimisation des performances, mesurez d'abord! Un grand nombre d'optimisations de performances s'avèrent être soit plus lentes que l'original, exactement les mêmes, soit ont des caractéristiques d'expérience utilisateur négatives (comme des données périmées). N'optimisez pas jusqu'à ce que vous soyez certain de devoir le faire.

+0

Hi Bob, Merci pour vos commentaires! Tiendra compte de vos suggestions! –

+0

définitivement benchmark memcached si vous voulez y mettre de grandes quantités de données. Sur le moteur de l'application, il pickles tout avec une mise en œuvre pur python pickle iiirc, cela * pourrait * finir par assez lent. – tosh

+0

Si l'objet qu'il insère est du HTML brut pré-rendu, cela ne devrait pas avoir d'importance. –

1

Ceci n'est pas une solution complète, mais pourrait offrir une option intéressante pour la mise en cache.

Google Appengine Frontend Caching vous permet de mettre en cache sans utiliser memcache.

1

juste servir une version statique de votre site

Il est en fait beaucoup plus facile que vous le pensez.

Si vous avez déjà un fichier contenant toutes les URL de votre site (ex urls.py), la moitié du travail est déjà effectuée.

est ici la structure:

+-/website 
+--/static 
+---/html 
+--/app/urls.py 
+--/app/routes.py 
+-/deploy.py 

/html est l'endroit où seront servis les fichiers statiques à partir. urls.py contient une liste de toutes les URL de votre site. routes.py (si vous avez déplacé les routes de main.py) devra être modifié afin que vous puissiez voir la version générée dynamiquement localement mais servir la version statique en production. deploy.py est votre générateur de site statique à guichet unique.

La configuration de votre module d'URL dépend de votre configuration. Personnellement, je l'utilise comme un guichet unique pour récupérer toutes les métadonnées d'une page, mais YMMV.

Exemple:

main = [ 
    { 'uri':'about-us', 'url':'/', 'template':'about-us.html', 'title':'About Us' } 
] 

Avec toutes les urls du site dans un format structuré, il rend l'exploration de votre propre site simple comme bonjour.

La configuration de la route est un peu plus compliquée. Je n'entrerai pas dans les détails parce qu'il y a trop de façons différentes d'y arriver. L'élément important est le code requis pour détecter si vous exécutez sur un serveur de développement ou de production.

Ici, il est:

# Detect whether this the 'Development' server 
DEV = os.environ['SERVER_SOFTWARE'].startswith('Dev') 

Je préfère mettre cela en main.py et l'exposer dans le monde parce que je l'utilise pour activer/désactiver d'autres choses comme l'exploitation forestière, mais, encore une fois, YMMV.

dernier, vous avez besoin du robot d'exploration/compilateur:

import os 
import sys 
import urllib2 
from app.urls import main 

port = '8080' 
local_folder = os.getcwd() + os.sep + 'static' + os.sep + 'html' + os.sep 
print 'Outputting to: ' + local_folder 

print '\nCompiling:' 
for page in main: 
    http = urllib2.urlopen('http://localhost:' + port + page['url']) 
    file_name = page['template'] 
    path = local_folder + file_name 
    local_file = open(path, 'w') 
    local_file.write(http.read()) 
    local_file.close() 
    print ' - ' + file_name + ' compiled successfully...' 

C'est vraiment des choses rudimentaires. J'ai été stupéfait de la facilité avec laquelle je l'ai créé. C'est littéralement l'équivalent de l'ouverture page par page de votre site dans le navigateur, l'enregistrement au format html et la copie de ce fichier dans le dossier/static/html. La meilleure partie est, le dossier/html fonctionne comme n'importe quel autre dossier statique de sorte qu'il sera automatiquement mis en cache et l'expiration du cache sera le même que tous les autres fichiers statiques.

Remarque: Ceci gère un site où les pages sont toutes diffusées à partir du niveau du dossier racine. Si vous avez besoin d'une imbrication plus poussée des dossiers, il vous faudra une légère modification pour y remédier.

+0

Bonjour Evan. Bien qu'utile, votre réponse rend des hypothèses potentiellement incorrectes sur l'environnement d'Alex. S'il construit un système de gestion de contenu où les administrateurs peuvent éditer le contenu, indépendamment de l'application, alors l'utilisation de fichiers statiques ne va évidemment pas résoudre ce problème. Pensez à éviter les réponses qui ne répondent pas réellement à la question. Certains membres de la communauté les rejetteront. Si vous savez comment mettre en cache du HTML généré, je vous encourage à élaborer. Pourtant, je pense que ce sont des informations utiles, en particulier les étapes pour convertir le code HTML généré en HTML statique via la source du navigateur. – jmort253

+0

@ jmort253 En fait, il est tout à fait possible d'éditer le contenu et de l'afficher dynamiquement sur le serveur de développement. Idéalement, pousser le contenu vers le serveur de production implique un cycle de compilation/déploiement en un clic. Les routes dynamiques (c.-à-d., Installations d'édition/administration) et les fichiers de site dynamiques sont disponibles sur le serveur de développement tandis que le serveur de production pointe vers la version statique (ie static/html) du site. Côté production, tout reste statique donc tout est automatiquement mis en cache. –

+0

(suite) Cela peut ne pas être une approche standard/traditionnelle mais cela fonctionne. Je l'utilise actuellement pour 2 sites où le serveur de développement est GAE et la production est Apache (c'est-à-dire en utilisant des routes regex pour définir la bonne structure de fichier). La même chose peut être faite pour une configuration de production/développement GAE tout-en-un et les numéros de version resteront synchronisés si le compilateur est configuré pour se déclencher en tant que hook de déploiement GAE. Voir https://developers.google.com/appengine/articles/hooks. La meilleure façon de minimiser les cycles CPU est de ne jamais lancer de code dynamique en production ... –

1

fil vieux, mais je vais commenter toute façon que la technologie a progressé un peu ... Une autre idée qui peut ou non être approproate pour vous est de générer le code HTML et le stocker sur Google Cloud Storage. Ensuite, accédez au code HTML via un lien CDN que le stockage en nuage vous fournit. Inutile de vérifier memcache ou d'attendre que datastore se réveille sur les nouvelles demandes. J'ai commencé à stocker tous mes contenus JavaScript, CSS et autres contenus statiques (images, téléchargements, etc.) comme celui-ci pour mes applications Appengine et cela fonctionne bien pour moi.

+1

Pour ajouter à cela, l'entrée/sortie entre les services cloud dans la même région est gratuite: https://cloud.google.com/storage/pricing. Donc, tant que vous ne permettez pas à l'utilisateur d'y accéder directement, vous ne payez que pour le stockage. Cela peut être préférable si vous ne voulez pas gaspiller votre bande passante memcache sur vos ressources statiques. –