Gestion des caches avec Nginx et PHP-FPM

Fibre_optique

Les plus curieux d’entre vous auront peut-être remarqué que le blog de Guillaume est propulsé par un WordPress, hébergé sur un serveur HTTP Apache 2. Je me suis récemment mis en tête d’apprendre à utiliser Nginx et d’en découvrir les subtilités afin de migrer tous mes services vers cette plateforme.

Les raisons ?

  1. Apprendre à utiliser Nginx ;
  2. Améliorer les performances du site et des autres services auto-hébergés ;
  3. Alléger la charge serveur car le blog de Guillaume commence à attirer du monde 🙂 Près de 13 000 visites le mois dernier ! Et j’ai de nouveaux projets qui vont arriver…

Je profite donc de mes découvertes pour les noter ici afin de vous en faire profiter. Et aujourd’hui, on va s’attaquer aux différents niveaux de cache que nous allons pouvoir configurer entre Nginx, PHP-FPM et nos clients. En avant donc !

Premier niveau de cache : le cache opcode (PHP)

PHP étant un langage interprété, chaque script est chargé, analysé puis pré-compilé lorsqu’il est appelé. La version pré-compilée d’un script s’appelle de l’opcode et il est possible de mettre en cache cet opcode afin d’alléger le processus de pré-compilation. Comme l’opcode est en cache, PHP n’a plus besoin de charger, d’analyser et de pré-compiler vos scripts, ce qui permet un gain de temps et de performance évident.

Il existe des projets permettant de gérer le cache opcode comme eAccelerator ou APC, mais PHP dispose depuis sa version 5.5 d’un cache opcode natif, appelé opCache, activé par défaut et très facilement paramétrable.

Quelques configuration de opCache

Les paramètres par défaut d’opCache peuvent ne pas être adaptés à votre machine. Par exemple la taille du cache est limitée à 64Mo ce qui est plutôt léger par rapport à mon espace disque… Pour modifier la configuration je vous conseille de créer ou d’éditer le fichier /etc/php5/fpm/conf.d/05-opcache.ini. Voici quelques pistes mais n’hésitez pas à aller faire un tour sur la documentation officielle.

; configuration for php ZendOpcache module
; priority=05
zend_extension=opcache.so
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 4000
opcache.revalidate_freq = 10
opcache.fast_shutdown=1

Visualiser le cache opCache

Il existe par ailleurs des scripts une page permettant de visualiser facilement l’état du cache opCache. Je pense par exemple à opcache-status qui n’est autre qu’un fichier PHP à placer où vous voulez. Accédez-y et si tout va bien il devrait vous afficher quelque chose de similaire à cela :

opcache

Sinon vous avez aussi OpCacheGUI, ou encore opcache-gui, eux aussi assez jolis.

Deuxième niveau de cache : le cache Fast-CGI

Nous avions vu précédemment comment Nginx travaille de concert avec PHP-FPM pour exécuter vos plus beaux scripts PHP. Lorsqu’une requête PHP est adressée à Nginx, il transfère celle-ci à PHP via le protocole Fast-CGI, PHP interprète le code, l’exécute et renvoie à Nginx (toujours via Fast-CGI) du code HTML.

Or Nginx est aussi capable de mettre en place un cache Fast-CGI qui contiendra le code HTML renvoyé ici par PHP. Nginx n’aura même plus besoin de faire travailler PHP pour délivrer du contenu, et il n’est plus à démontrer que Nginx est le meilleur des serveurs web lorsqu’il s’agit de délivrer du contenu statique ! Notez que ce cache fonctionne avec PHP-FPM mais aussi tous les autres programmes appelés par Fast-CGI. Que ça soit du perl, du python ou encore du ruby !

Définition du cache Fast-CGI

Pour mettre en place ce cache, rendez-vous dans /etc/nginx/nginx.conf :

http {
     [...]
 
     fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=nginxcache:10m inactive=1h max_size=1g;
 
     [...]
}
L’idée ici c’est de déclarer une zone de cache intitulée « nginxcache » avec une table d’index de 10Mo (1Mo ~ 8000 clés). Ce cache se situera dans /var/cache/nginx avec une taille maximum de 1Go. levels correspond au niveau de hiérarchie du cache et si du contenu mis en cache n’est pas accédé au bout de inactive, il est supprimé.
Le dossier /var/cache/nginx doit être créé par vos soins et Nginx doit en être propriétaire (chown -R www-data: /var/cache/nginx) et avoir les droits d’écriture (chmod -R 775 /var/cache/nginx) !

Utilisation du cache dans vos server blocks

Maintenant que notre zone est prête, reste plus qu’à l’utiliser ! Si vous avez déjà configuré Nginx pour qu’il fonctionne avec PHP-FPM, cet extrait devrait vous être familier :

location  ~ \.php$ {
      [...]
 
      fastcgi_cache nginxcache;
      fastcgi_cache_key $host$request_uri;
      fastcgi_cache_valid any 1h;
      fastcgi_cache_use_stale off;
}

Et voilà la travail ! Rechargez Nginx et accédez à vos sites. Une arborescence devrait apparaître dans /var/cache/nginx :

sudo tree /var/cache/nginx
/var/cache/nginx
├── 5
│   └── 70
├── 7
│   ├── 66
│   └── 70
├── 9
│   ├── d1
│   └── fe
├── c
│   ├── 84
│   │   └── 82838d0c43365d76e6c7ae5dab67b84c
│   └── fd
└── tmp

Pour aller plus loin et si vous en avez les moyens, vous pouvez tout à fait stocker le cache Fast-CGI dans un ramdisk et là… C’est la fête…

Mise en cache des session SSL

Les opérations de chiffrement et de déchiffrement lors d’une session SSL peuvent s’avérer très lourdes en calcul si vous utilisez du chiffrement de haut niveau. Par ailleurs, c’est l’ouverture d’une session SSL, ou poignée de main SSL, qui est la plus coûteuse et il est possible de mettre en place un cache SSL afin de ne pas supprimer systématiquement les sessions pour les réutiliser.

Nginx va stocker les sessions dans un cache réutilisable par tous ses processus. Il se configure avec la directive ssl_session_cache de la manière suivante :

http {
        [...]
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;
        [...]
}
Un cache de 1Mo (1m) peut stocker jusqu’à 4000 sessions !

Cache final : le cache utilisateur

Ce cache est un peu spécial puisqu’il est stocké dans le navigateur de vos visiteurs. Ici attention à ce que vous faites car impossible de le réinitialiser… Là encore c’est très simple à configurer. Définissez pour quels types de fichiers vous souhaitez activer le cache et spécifiez la durée de cache :

server {
        [...]
        location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
                expires 14d;
        }
        [...]
}
La configuration peut aller plus loin car vous pouvez utiliser tout un tas d’échelles de temps : ms, m, s, h, d, W, Y…. Allez faire un tour sur la documentation pour plus d’informations !

Avec tous ces niveaux de cache, couplés à la rapidité de Nginx, le temps de réponse de vos services web devrait drastiquement diminuer, ainsi que la consommation de bande passante et de CPU. Nous avons optimisé toute la chaîne HTTP de la requête jusqu’à la réponse chez l’utilisateur final. Moi qui découvre Nginx je me rend compte que ses possibilités sont vraiment immenses. Je crois que je n’ai pas fini de vous en parler !

Oh et n’oubliez pas :

Désactivez TOUS les caches en environnement de développement !

😉


Source et références :

Cet article vous a plu ? Partagez-le sur les réseaux sociaux !

Twitter Facebook Google Plus email