NBS System est le premier hébergeur Magento Entreprise en France ; nos administrateurs système ont donc l’occasion d’explorer cette solution dans les moindres détails, dans de nombreuses configurations.

L’un d’entre eux, Julien Khamis, a ainsi découvert fin de semaine dernière un bug dans les plateformes Magento utilisant Redis et plusieurs services Apache.

 

Contexte et symptômes :

Magento logoLors d’un vidage de cache Magento, et dans une plateforme utilisant Redis pour le stockage du cache, nous constatons une forte montée en charge des serveurs frontaux. Cette charge est liée à des processus Apache, qui consomment principalement du temps CPU.

Il est à noter que les plateformes ne possédant qu’un seul service Apache ne sont pas impactées par ce bug.

Cause principale :

Lors d’un vidage de son cache, Magento dépose un verrou (LOCK) indiquant qu’il est normal que le cache ne soit pas accessible car il a été vidé, et que la re-génération de ce dernier est déjà prise en charge.

En général, comme par exemple sur les plateformes utilisant Memcache, ce verrou est déposé sur MySQL. Cette action est peu coûteuse, elle est instantanée et elle est surtout indépendante de toute base de données. Le verrou est donc instantanément pris en compte par tous les processus Apache cherchant à exécuter une requête ; ces derniers vont donc simplement attendre la recréation du cache, puis serviront aux internautes les pages demandées avec le nouveau cache.

La création d’un verrou sur Redis

Quand une plateforme utilise Redis pour stocker son cache, le processus est différent. Après le vidage du cache, durant la première requête envoyée à un serveur frontal exigeant un accès au cache, le processus Apache servant cette requête va effectuer les actions suivantes :

  1. Demander à Redis si le cache existe. Dans notre cas, il n’existe pas, on passe donc à l’étape 2.
  2. Demander à Redis si un verrou existe. Puisqu’on parle ici de la première requête après le vidage de cache, le verrou n’existe pas encore ; on passe à l’étape 3.
  3. Ordonner à Redis de créer un verrou.
  4. En parallèle, commencer à recréer le cache. Pour cela, le processus Apache va parcourir tous les fichiers .xml du répertoire de configuration Magento (app/etc/). En effet, cela va lui permettre de générer la clé de configuration nécessaire à l’affichage de chaque page, et de les concaténer en un fichier dans le cache Magento.
  5. Une fois le cache recréé, insérer le cache dans Redis, et enfin…
  6. Demander à Redis de supprimer le verrou.

redis (2)Le problème ici vient de la caractéristique de Redis d’être un service « mono-threadé », c’est-à-dire qu’il n’est capable de ne traiter qu’une seule action à la fois. Les requêtes qui lui sont adressées sont donc empilées dans une file de traitement.

Ainsi, entre l’étape 1 et l’étape 3, un certain temps s’est écoulé ; assez de temps pour que de nombreux clients envoient des requêtes exigeant l’existence du cache (imaginons, pour l’exemple, que ce nombre soit 3). Les processus Apache traitant ces requêtes suivent la même ligne de conduite que celui de la première requête : demande de l’existence du cache, puis demande de l’existence d’un verrou.

Le problème est là : la requête de création du premier verrou n’a toujours pas été exécutée par Redis, elle est toujours dans la file d’attente. Une boucle de requêtes a été créée dans Redis. En se limitant à trois requêtes, on peut imaginer une file comme celle-ci :

- Cache 1 ?

- Cache 2 ?

- Verrou 1 ?

- Cache 3 ?

- Verrou 2 ?

- Créer verrou 1.

- Verrou 3 ?

- Créer verrou 2.

Suivons la requête 2 : sa demande concernant l’existence du verrou a été effectuée avant la création du premier verrou. Ainsi, même si ce dernier a été créé, le processus Apache va tout de même demander à Redis la création d’un verrou, qui va remplacer le premier.

Ce n’est qu’à partir de la requête 3 que la réponse de Redis à la question « verrou ? » sera « oui » : pour toutes les requêtes effectuée après cela, les processus Apache se mettront simplement en attente du cache final. Cela aussi consomme du temps CPU.

C’est l’une des causes de la montée en charge des serveurs. D’une part, les nombreux processus Apache (un par requête) doivent attendre la réponse de Redis avant d’effectuer une autre action, et ce temps de réponse dépend du nombre de requêtes à traiter avant d’arriver à celle qu’ils ont effectuée. D’autre part, les requêtes n’ayant pas à créer de verrou sont en attente du cache. Cette attente (io wait) consomme du temps CPU.

La recréation du cache

magento-redisLa deuxième grande cause de la montée en charge importante des serveurs est liée à la recréation du cache en elle-même. En effet, quand un processus Apache a réussi à créer un verrou sur Redis, il commence, en parallèle, à générer le nouveau cache. Pour cela, comme indiqué plus haut dans l’article, il parcourt les fichiers .xml du répertoire de configuration Magento. Or, ces fichiers ne sont accessibles que par un processus à la fois. En plus des ressources nécessaires à la lecture de ces fichiers, le grand nombre de processus n’y ayant pas encore accès sont en attente, ce qui, on le rappelle, consomme des ressources. Tous les processus Apache de la boucle décrite précédemment essayant de lire les .xml en parallèle ou presque, la montée en charge est particulièrement forte.

Et ce n’est pas encore fini…

Une fois qu’un processus Apache a récupéré les informations des fichiers .xml, et donc recréé le cache, il va l’insérer dans Redis, et lui demander de supprimer le verrou. Il pourra ensuite répondre à la requête initiale du client, et le processus s’arrêtera.

Mais cela n’arrêtera pas l’exécution des milliers d’autres processus en cours faisant exactement la même chose… Tous les processus ayant posé un verrou sur Redis inséreront également dans Redis le cache qu’ils auront recréé, et lui demanderont de supprimer le verrou. Et là encore, ces requêtes seront mises en file d’attente, comme par exemple de la manière suivante :

- Insertion cache 1

- Insertion cache 2

- Retirer verrou 1

- Retirer verrou 2

Cela signifie que même si un processus a réussi à insérer son cache dans Redis, il ne va pas pour autant s’arrêter et libérer ses ressources immédiatement, puisque Redis aura d’autre requêtes à traiter avant de retirer son verrou et donc, de « libérer » le processus.

Cerise sur le gâteau, tous les processus ayant reçu « oui » à leur question sur l’existence d’un verrou vont également envoyer des requêtes régulières à Redis, pour lui demander de leur fournir le cache. Des étapes en plus dans la file de traitement…

Conséquences

Il peut parfois se passer des heures avant que tous les processus Apache ne se terminent. Bien entendu, le cache étant inaccessible depuis son vidage jusqu’au retrait du dernier verrou, le site concerné est, durant tout ce temps, indisponible…

Contournement

Afin de mettre un terme à cette boucle de re-création de cache, l’administrateur système, en accord avec le client, aura la possibilité d’arrêter manuellement les services Apache des serveurs frontaux, excepté un. Cela limitera le nombre de processus Apache tournant en parallèle, et Redis arrivera donc beaucoup plus vite au traitement de la dernière requête de retrait de verrou, celle qui marque la disponibilité du cache ! La charge retombera et les services pourront être relancés.

Correctif

Le seul correctif possible à ce jour est de placer le verrou en dehors de Redis, comme c’est le cas avec Memcache. Il peut être déplacé en base de données, ou bien à tout autre endroit accessible par tous les frontaux au même instant, comme par exemple sur le share media. Le verrou sera alors visible par tous les processus Apache, ce qui permet d’éviter le lancement d’une boucle de recréation de cache.

Cette modification peut-être effectuée par le développeur du site (par exemple l’agence de développement), et n’aura a priori aucun impact négatif sur le site. Un partenaire, connaissant bien Magento, a mis en place ce correctif pour un client en moins d’une journée et le site n’a subi aucun ralentissement suite à cette manipulation.

Pour plus de détails à ce sujet, n’hésitez pas à nous contacter.

Source technique : Julien Khamis

Lucie Saunois
Lucie Saunois
Passionnée d'informatique, en particulier de sécurité, depuis qu'elle a rejoint l'OT Group en 2015, Lucie se spécialise dans la vulgarisation technique pour permettre à tous d'appréhender ces sujets parfois complexes.