Pour votre boutique Magento il est commun d'utiliser une base de données Memcached ou Redis. Elle va gérer le cache et/ou les sessions. Le plus souvent utilisées dans des architectures multi-serveurs, ces bases de données améliorent les performances. Elles facilitent également la scalabilité horizontale de votre applicatif.
Néanmoins, mal configurés, ces outils peuvent parfois avoir des effets inattendus sur votre applicatif.
Ayant récemment rencontré un dysfonctionnement de sessions utilisateurs pour l'une de nos boutiques Magento, j'exposerai, à travers cet article, un premier éclaircissement sur le fonctionnement interne de Memcached.
Memcached
Mais avant tout, qu'est-ce que Memcached ? Memcached est une base de données clé-valeur à stockage en mémoire. L'ensemble des données est stocké en mémoire. Ces données sont accessibles via des clés uniques.
Memcached a un système d’allocation mémoire particulier. Il n’utilise pas de simples "malloc()/free()" pour travailler, mais un système appelé "slabs allocator".
Organisation et démarrage
Dans Memcached, les données sont stockées dans des 'slab classes’. Chaque slab class contient des ‘pages'. Chaque page est remplie par des 'chunks’.
Au démarrage, une ‘page' est créée automatiquement pour chaque ‘slab’ et divisée en plusieurs ‘chunks’.
Slab
Un ‘slab’ est donc une collection de ‘pages’, divisée en ‘chunks’ de la même taille. Chaque ‘slab’ est référencé par la taille de ses ‘chunks’. ( Slab class 80KB, Slab class 100KB etc…).
Lorsque l’on stocke un objet, la taille de cet objet est déterminée puis comparée à la taille des ‘slab classes’ pour y être rangé. Ainsi, un objet avec une taille plus grande que 80KB mais moins que 100KB sera stocké dans la 'Slab class 100KB’.
Page
Un ‘slab class’ peut avoir une ou plusieurs pages. Par défaut, la taille maximale d’une page est de 1MB (configuration). Donc, selon la taille d’un ‘chunk’ d’une ‘slab class’, une page pourra contenir un certain nombre de ‘chunk’. Il y a potentiellement une perte place.
Exemple
Supposons les paramètres de configuration suivants :
Lorsque Memcached va démarrer, celui-ci va créer 3 ‘slab classes’. Je vais les nommer A, B et C avec chacun une ‘page’ de base. Ces ‘slab classes’ sont prêts à recevoir des objets, dans sa division en ‘chunks’.
Chaque fois qu’une page est pleine, une nouvelle page est créée pour le ‘slab class’. Chaque ‘chunk’ est utilisé, mais pas forcément plein.
Dans mon exemple schématique, chaque ‘slab classes’ ne peut contenir qu'une page.
Évictions
Prenons le scénario d’enregistrement suivant :
11 objets de 80KB
Les dix premiers vont être enregistrés dans la ‘slab class A(100KB)'. Arrivé au onzième, la ‘Page1’ du ‘slab class A(100KB)’ est pleine. Il est impossible de créer une nouvelle page.
En raison de sa taille, l'objet ne peut pas être stocké dans la ‘slab class B(300KB)’. Memcached va le faire dans cette même ‘slab class A(100KB)’. Il va devoir procéder à un petit ménage pour arriver à ses fins.
Memcached va alors appliquer la règle LRU (Least Recently Used). Il va enlever l’objet N°1 du ‘slab class A(100KB)’ pour libérer un slot de 100KB. Le onzième objet peut alors être stocké dans le ‘slab class A(100KB)’.
Ce mécanisme s'appelle l’Éviction.
Cas pratique Magento
Comme indiqué en préambule, nous avons rencontré un dysfonctionnement pour les sessions utilisateurs.
La très efficace interface phpMemcachedAdmin, nous a permis de remarquer que la division par défaut en ‘slab class’ n'était pas adaptée à la taille de nos sessions. La moitié d'entre elles étaient inutilisées, bien qu'une page leur avait été réservée.
Celles-ci étaient principalement stockées dans les dernières ‘slab class’ allouées par Memcached. Ces ‘slab class’ ne disposaient pas d'assez de ‘chunks’ pour satisfaire notre utilisation.
Pour corriger la situation, nous avons redéfini le paramètre ‘min chunk size’ (-n). Désormais, Memcached commence sa répartition à un niveau plus proche de la taille moyenne de nos sessions.