Comment optimiser les performances applicatives avec AWS Elasticache
Au sein d’une application, les appels à la base de données peuvent représenter un coût (temporel) important. Avec le service Elasticache, AWS propose des solutions afin de rationaliser et optimiser vos accès aux bases de données, et ainsi doper les performances de vos applications.
Présentation du service AWS Elasticache
AWS Elasticache est un service managé de datastore en stockage mémoire (“fully-managed in-memory datastore”) .
Le stockage en mémoire implique 2 caractéristiques essentielles :
- Elasticache est rapide, puisque l’on parle d’accès mémoire et non d’accès disque
- L’espace de stockage est limité par la taille de la mémoire
Au même titre que la plupart des services relatifs aux bases de données, Elasticache est un service principalement régional.
AWS propose avec Elasticache deux modes de compatibilité présentant des caractéristiques bien distinctes : Memcached et Redis.
Elasticache/Memcached propose un support de l’hyperthreading pour des performances élevées, mais en revanche il ne propose que des types de données simples (cache objet) et beaucoup moins de fonctionnalités. Ce service ne peut être déployé que dans une seule zone de disponibilité (AZ).
L’autre choix proposé par Elasticache est Redis, qui est bien plus riche en fonctionnalités : support du multi-AZ et de types de données plus complexes, chiffrement, sauvegardes, etc. Il propose également le sharding de données.
Le service Elasticache/Redis dispose également de multiples certifications telles que PCIDSS (données de paiement) et HIPAA (données de santé). En revanche, il offre des performances un peu moindres qu’Elasticache car il ne supporte pas l’hyperthreading.
Présentation d’un scénario
Prenons le cas d’une application web type CMS, destinée à recevoir un trafic important.
Considérons que le trafic de cette application est de type régional (national/continental) et qu’une typologie mono-région a été retenue.
Pour des raisons de sécurité, notre cahier des charges impose un chiffrement des données sur l’ensemble du périmètre applicatif.
Choix d’architecture
Principes généraux
De par le cahier des charges établi, notre choix se portera vers Redis afin de bénéficier des fonctionnalités de chiffrement d’Elasticache.
- Une “instanciation” Elasticache peut comporter de 1 à 15 nodes.
- Chacun de ces nodes peut avoir de 0 à 5 replicas.
- On peut donc compter un maximum de 90 instances.
Si l’on choisit d’avoir plusieurs nodes, nous entrons dans le mode de fonctionnement “cluster” (selon la dénomination Elasticache) avec sharding des données.
Dans notre exemple, pour des raisons de simplicité nous resterons sur un cas d’utilisation “cluster mode: disabled” (selon la terminologie Elasticache) ou plus communément “sans sharding”. Nous ne disposerons donc que d’un seul node, et d’un certain nombre de réplicas.
Comme sur les services type Aurora, la réplication est asynchrone : un replica peut donc présenter un retard par rapport au master.
Les replicas peuvent être répartis sur plusieurs zones de disponibilité (AZ), mais le service Elasticache ne propose en revanche pas d’autoscaling.
Une fonctionnalité intéressante d’Elasticache est qu’il permet un failover automatique en cas de défaillance d’un node. Et cette option est activée par défaut !
Un failover peut cependant entraîner une indisponibilité pouvant durer jusqu’à 3 à 6 minutes, et cela même si le failover automatique en contexte multi-AZ est activé.
Le paramétrage d’Elasticache se fait à travers des Parameter Groups, à la façon de ce que l’on trouve au sein du produit RDS.
Parmi les paramètres les plus importants pour Redis, il sera nécessaire de s’intéresser à :
maxmemory | C’est une donnée de configuration statique, imposée par AWS, vous indiquant la quantité maximale de mémoire utilisable pour stocker des objets en cache. Cette valeur varie, en fonction du type d’instance retenu |
reserved-memory-percent | C’est le pourcentage de mémoire utilisé par Elasticache pour son fonctionnement. Cette partie de la mémoire n’est pas utilisable pour stocker de la donnée en cache |
maxmemory-policy | Cette variable permet de configurer le comportement de Redis quand la mémoire arrive à saturation |
Elasticache et la sécurité
Comme la plupart des services AWS, Elasticache peut être protégé par Security Groups.
Le service supporte également le chiffrement at-rest et in-transit.
L’activation du chiffrement in-transit permet aussi l’activation des mécanismes d’authentification de Redis (REDIS AUTH).
Elasticache/Redis propose (comme pour Aurora) plusieurs endpoints:
- Le “primary endpoint” qui pointe vers le master de l’instanciation redis
- Le “reader endpoint” qui est un loadbalancer permettant de répartir le trafic sur l’ensemble des replicas (à l’exception du master)
Notez que si chaque noeud dispose de son propre endpoint, il est fortement déconseillé de s’en servir : vous devez vous appuyer sur les endpoints de l’instanciation Redis.
Elasticache/Redis et le scaling
Elasticache permet le scaling horizontal et vertical.
Dans le cadre d’un scaling vertical, l’opération est réalisée avec un downtime “minimal”. Notez qu’au sein d’une instanciation Elasticache/Redis, l’ensemble des nodes doit être du même type.
Le scaling horizontal est également possible. Ce dernier consiste à ajouter et supprimer des nœuds au sein de votre instanciation. Bien sûr, vous devez disposer d’au moins un replica pour pouvoir faire du Multi-AZ et bénéficier du failover automatique
Utilisation d’un service de cache
Elasticache propose deux stratégies pour ajouter des objets dans le datastore:
Lazy-Loading
Dans cette typologie d’utilisation, quand l’application a besoin de récupérer une donnée, elle interroge d’abord le cache. Si l’objet est disponible, Elasticache retourne directement la donnée.
Si elle ne l’est pas, l’application interroge la base de données puis va inscrire le résultat dans le datastore d’Elasticache.
C’est donc une approche réactive, qui permet d’avoir un datastore plus petit puisque seuls les objets requêtés sont stockés.
L’inconvénient de cette méthode est qu’il y a une “pénalité” de performance puisqu’il y a plus de risques que l’objet ne soit pas en cache et qu’il faille interroger la base de données.
Un autre problème posé par cette approche est que les objets stockés dans le datastore peuvent avoir un certain âge.
Il est donc nécessaire de positionner un TTL pertinent afin d’éviter de servir à l’application des données périmées.
Write-Through
Le fonctionnement en mode write-through est un peu différent, puisque à chaque écriture en base de données, l’application va également écrire dans le datastore d’Elasticache.
On est ici dans une approche proactive, et on a la garantie que les données stockées dans le datastore sont toujours à jour.
La contrepartie est que la taille du datastore sera plus importante, et qu’il est probable qu’une partie des données stockée dans le datastore ne soit jamais accédée.
On peut réduire l’impact de ce problème en positionnant là encore un TTL adapté, permettant de supprimer les objets inutilisés et de réduire la taille du datastore.
Suppression d’objets du datastore
Un objet peut être supprimé du datastore à l’une des conditions suivantes:
Le TTL de l’objet expire | L’objet peut alors être reclaimed par Redis. Le TTL d’un objet est généralement défini au moment où l’objet est déposé dans le datastore |
Le datastore est plein | Redis procède donc à une éviction, conformément à la policy configurée. La recopie d’une documentation technique n’ayant que peu d’intérêts, vous pouvez retrouver le spectre des possibilités proposées par Redis dans leur documentation. Notez que la policy par défaut sur Elasticache est volatile-lru, ce qui signifie que Redis supprimera les fichiers “les moins récemment utilisés” ET disposant d’un champ TTL renseigné. |
Un ordre de suppression est passé à Redis | On peut supprimer manuellement un objet à l’aide de la CLI mise à disposition par l’éditeur Redis, ou encore à travers l’API Redis (utilisée par exemple via une librairie au sein de votre application) |
Un dernier mot sur le TTL …
Avec Redis, il n’y a pas de “TTL par défaut” qui serait appliqué à un objet déposé dans le datastore.
Les applications doivent donc définir explicitement le TTL quand elles déposent un objet.
Il est cependant possible de définir (ou modifier) a posteriori le TTL à l’aide de commandes Redis telles que EXPIRE ou EXPIREAT.
La commande TTL de Redis permet de connaître le TTL actuel d’un objet.
La commande PERSIST permet quant à elle de supprimer le TTL sur un objet du datastore.
Gestion & opérations du service
L’une des particularités du service Elasticache est qu’il ne propose pas de logs. Vous n’en trouverez donc pas dans Cloudwatch.
En revanche, AWS publie bon nombre de métriques dans Cloudwatch Metrics.
Ces métriques concernent à la fois l’instance (“host-level metrics”) mais aussi l’application Redis elle-même.
Vous pourrez donc trouver bon nombre d’indicateurs techniques tels que:
- Le nombre d’items actuellement stockés dans le datastore
- Le nombre d’évictions réalisées par Redis
- Le nombre d’objets reclaimed (TTL expiré) supprimés par Redis
- Le nombre de commandes GET/SET éxécutées par Redis, ainsi que leur latence
- Etc.
Evolution du nombre d’objets stockés dans le datastore Elasticache
A 15h45, on observe une importante suppression d’objets « reclaimed » (courbe orange) : la moitié des objets ont été supprimés, car leur TTL a expiré
Mesure de l’efficacité d’Elasticache (« cache hit rate »)
Pour plus de détails, vous pouvez consulter les documentations AWS suivantes :
Enfin, AWS propose avec Elasticache son système d’events, vous permettant de mettre en place des notifications ou d’autres traitement sur des événements tels que:
- Failover
- Scaling
- Reboot de node
- Remplacement de node
- etc.
Retour sur notre scénario: éléments de performance
Suite à la mise en place d’Elasticache/Redis chez l’un de nos clients, nous avons pu constater les éléments de performance suivants:
- Entre 50% et 70% des requêtes sont servies par Elasticache plutôt que par la base de données
- Le temps de réponse d’Elasticache est entre 5 et 10 fois plus rapide que celui du SGBD relationnel utilisé
Considérations financières
Si l’on prend le cas d’une instance de type r5.large dans la région eu-west-1 :
Instance | Cout horaireOn demand | Cout mensuelOn demand | Economie | Cout mensuelRéservation 1 an | Economie | |
Elasticache | cache.m5.large | 0.241$ | 173.52$/mois | – | 119.72$/mois | – |
RDS/MySQL | db.r5.large | 0.265$ | 190.80$/mois | 9% | 127.97$/mois | 7% |
RDS/MSSQL standard mono-AZ | db.r5.large | 1.025$ | 738$/mois | 76% | 707.078$/mois | 83% |
RDS/Oracle | db.r5.large | 0,536$ | 385,92$/mois | 48% | 254,697$/mois | 53% |
Aurora | db.r5.large | 0,32$ | 230.40$/mois | 25% | 153.30$/mois | 22% |
On le voit, une instance Elasticache est environ 10% moins chère qu’une instance RDS/MySQL, 25% moins chère qu’une instance Aurora.
L’écart se creuse avec les SGBD sous licence, puisque dans un contexte Mono-AZ et mono-instance, Elasticache se révèle environ 50% moins cher qu’Oracle et 75% moins cher que MS SQL Server.
Le service Elasticache est donc un service performant et peu cher.
Bien sûr la comparaison n’est pas si simple, puisque Elasticache n’est pas capable de remplacer votre SGBD relationnel.
Cependant, pour un coût relativement modique, il peut permettre de soulager et downsizer vos instances de base de données, et donc réaliser de substantielles économies …
Aller plus loin avec Elasticache
Il est possible d’utiliser d’autres fonctionnalités de Redis, telles que la sauvegarde (“append on file”). Nous ne l’avons pas abordé dans cet article, car cela est peu pertinent dans le use-case présenté.
Si vous n’avez pas d’exigences en termes de chiffrement et que vous avez besoin de plus de performance, il est également possible d’opter pour Elasticache/Memcache plutôt que pour Redis.
D’autres patterns d’utilisation de Redis sont possibles pour des besoins plus importants, par exemple en utilisant le “cluster mode” proposé par Elasticache, vous permettant de bénéficier entre autres des fonctionnalités de sharding.
Il est également possible d’utiliser Elasticache pour d’autres utilisations que du cache d’objets dans un contexte web. Il est par exemple possible d’utiliser les Sorted Sets de Redis, afin de stocker, maintenir et mettre à disposition un classement (par exemple pour un jeu en ligne) avec beaucoup de simplicité et de rapidité.
Autre exemple : les fonctionnalités de Redis sur les données géospatiales peuvent être utilisées pour simplifier le tracking d’une flotte de véhicules, ou encore dans un contexte IOT ou dans le cadre d’un moteur de recommandations…
Pour en savoir plus sur les cas d’usage les plus courants