Aller au contenu

Leviers de coût ElastiCache — type de nœud, réservations et le patron Redis surdimensionné

La deuxième ligne la plus chère d'une facture SaaS AWS est souvent un Redis surdimensionné. Choisissez la bonne famille de nœuds, appliquez les réserved instances sur le régime stable, et redimensionnez le working set — trois leviers qui se composent.

Une revue FinOps sur une facture SaaS de taille moyenne montre un cache.r6g.4xlarge tournant avec BytesUsedForCache à 18 Go de moyenne sur un nœud avec 105 Go utilisables. L’équipe a choisi cette taille il y a deux ans « pour laisser de la marge » et n’y est jamais revenue. La même revue montre un second cluster sur cache.m6g.xlarge (13 Go) qui est constamment à 11 Go et évincit sous pression mémoire — la mauvaise famille entièrement. Après que les deux clusters sont redimensionnés et qu’une réservation d’un an est appliquée aux nœuds restants, les dépenses ElastiCache chutent d’environ la moitié. Rien n’a changé côté application. Le redimensionnement était dans les métriques tout ce temps.

Ce qui se passe

La tarification ElastiCache est par heure-nœud, par type d’instance. Trois familles de nœuds dominent l’usage pratique, et elles ciblent différentes charges.

cache.t4g.* est la famille burstable. Petite capacité de base, crédits CPU qui s’accumulent durant faible charge et brûlent durant les rafales. Convient pour dev, préproduction et charges de production très faibles (un petit SaaS qui fait peut-être 100 opérations cache/sec). Mauvais pour tout cluster où le working set pousse réellement le nœud — un t4g sous charge soutenue épuise ses crédits CPU et est silencieusement étranglé, ce qui apparaît comme des pics de latence que personne n’arrive à expliquer.

cache.m6g.* est la famille à usage général. CPU et mémoire équilibrés. Convient pour les clusters où la charge est surtout lourde en lecture ou modérément liée à la mémoire et où la pression CPU et mémoire suit ensemble. La plage m6g.large (6,38 Go) à m6g.16xlarge (217,55 Go) couvre la plupart des charges générales.

cache.r6g.* est la famille optimisée mémoire. Même CPU que m6g pour une taille équivalente, mais ~2× la mémoire. Convient pour les clusters liés à la mémoire — le working set est grand, le patron d’accès est surtout des recherches par ID, et vous n’avez pas besoin de pousser les commandes à la limite du CPU. r6g.large a 13,07 Go; r6g.xlarge a 26,32 Go; r6g.4xlarge a 105,81 Go.

Pour presque toute charge Redis production lourde en mémoire, r6g est le bon choix. L’erreur est d’utiliser m6g parce que « usage général » semble un défaut sûr, et de constater que le cluster cogne constamment le plafond mémoire pendant que le CPU est inactif. Choisir r6g plutôt que m6g de taille en dollars équivalente vous achète 2× la mémoire pour le même budget CPU.

L’autre levier est les réservations d’instances. La tarification ElastiCache à la demande est le défaut. Les réservations d’instances engagent un type de nœud pour 1 ou 3 ans et escomptent le taux d’environ 30–40 % (1 an, sans paiement initial) jusqu’à 60 % (3 ans, tout initial). L’économique :

  • Sans engagement → à la demande. Convient pour les clusters qui peuvent disparaître ou changer de type en quelques mois.
  • 1 an, sans paiement initial → escompte ~30 %. Convient pour les clusters de production en régime stable où vous êtes confiant dans le type et la taille du nœud mais pas certain pour dans 3 ans. Le seuil de rentabilité par rapport à la demande est d’environ 8 mois.
  • 1 an, paiement initial partiel → escompte légèrement meilleur. Même cas d’usage que sans-initial, coût en capital légèrement plus élevé.
  • 3 ans, tout initial → escompte ~60 %. Convient seulement pour des clusters très stables et de longue durée où vous êtes absolument confiant que le type de nœud ne changera pas. Le capital tout-initial est verrouillé pour 3 ans.

Pour un SaaS typique, le bon patron est 1 an sans paiement initial sur les nœuds en régime stable. Les réservations de 3 ans valent généralement le coup seulement pour un cluster production cœur que vous aurez absolument toujours besoin à cette échelle dans 36 mois.

Le patron appelé « la deuxième ligne la plus chère est un Redis surdimensionné » : après EC2, la ligne suivante la plus grosse sur plusieurs factures AWS SaaS est ElastiCache. Et neuf fois sur dix quand on audite, le cluster a été dimensionné pour un working set 3 à 5× plus gros qu’il ne l’est réellement. Le redimensionnement est un seul appel API. Les économies sont immédiates et récurrentes.

Comment vérifier

Trois mesures pilotent les décisions de coût.

Usage mémoire actuel par rapport à la capacité du nœud. Pour chaque cluster, sortez le BytesUsedForCache maximum sur les 30 derniers jours et comparez au maxmemory du nœud.

aws cloudwatch get-metric-statistics \
  --namespace AWS/ElastiCache \
  --metric-name BytesUsedForCache \
  --dimensions Name=CacheClusterId,Value=saas-prod-001 \
  --start-time $(date -u -v-30d +%Y-%m-%dT%H:%M:%S) \
  --end-time   $(date -u +%Y-%m-%dT%H:%M:%S) \
  --period 3600 \
  --statistics Maximum \
  --query 'Datapoints[].Maximum' \
  --output text | sort -n | tail -1

Un cache.r6g.4xlarge a 105,81 Go utilisables. Si le max sur 30 jours est de 18 Go, ce nœud est dimensionné pour ~17 % de la capacité. La bonne taille est quelque part entre r6g.large (13 Go — un peu serré) et r6g.xlarge (26 Go — confortable). Redimensionnez d’un cran vers le bas et remesurez.

La même mesure fait surface le problème inverse. Si le max sur 30 jours est constamment à 90 %+ de maxmemory, le cluster évincit. Vérifiez la métrique d’éviction pour confirmer :

aws cloudwatch get-metric-statistics \
  --namespace AWS/ElastiCache \
  --metric-name Evictions \
  --dimensions Name=CacheClusterId,Value=saas-prod-001 \
  --start-time $(date -u -v-7d +%Y-%m-%dT%H:%M:%S) \
  --end-time   $(date -u +%Y-%m-%dT%H:%M:%S) \
  --period 3600 \
  --statistics Sum \
  --query 'Datapoints[?Sum > `0`]' \
  --output text

Des évictions soutenues pointent vers un sous-dimensionnement. La cure est une taille au-dessus, dans la même famille.

Utilisation CPU sur chaque nœud. ElastiCache expose CPUUtilization et EngineCPUUtilization. La première est le CPU au niveau EC2; la seconde est le processus principal Redis mono-thread. Redis est largement mono-thread pour l’exécution des commandes, donc EngineCPUUtilization est la métrique la plus significative.

aws cloudwatch get-metric-statistics \
  --namespace AWS/ElastiCache \
  --metric-name EngineCPUUtilization \
  --dimensions Name=CacheClusterId,Value=saas-prod-001 \
  --start-time $(date -u -v-14d +%Y-%m-%dT%H:%M:%S) \
  --end-time   $(date -u +%Y-%m-%dT%H:%M:%S) \
  --period 60 \
  --extended-statistics p95 \
  --query 'Datapoints[].ExtendedStatistics.p95' \
  --output text | sort -n | tail -1

Si EngineCPUUtilization p95 est sous 30 % et que le cluster est dans la famille m6g, vous pouvez passer à r6g de la même classe de taille et gagner une marge mémoire pour le même dollar. Si p95 est au-dessus de 70 %, vous êtes limité CPU et devez mettre à l’échelle le CPU — généralement en allant à une plus grande taille, ou dans les cas extrêmes en fragmentant via le mode cluster.

Tarification actuelle vs engagée. Les recommandations de redimensionnement d’AWS Cost Explorer incluent des suggestions de réservations ElastiCache. Filtrez sur ElastiCache et regardez l’engagement recommandé.

aws ce get-reservation-purchase-recommendation \
  --service "AmazonElastiCache" \
  --term-in-years ONE_YEAR \
  --payment-option NO_UPFRONT \
  --query 'Recommendations[].RecommendationDetails[].[InstanceDetails.NodeType,EstimatedMonthlySavingsPercentage]' \
  --output table

Les recommandations sont basées sur l’usage réel des 14–30 derniers jours. Elles sont conservatrices — AWS ne recommande une réservation que quand l’usage est suffisamment élevé et constant pour clairement atteindre le seuil de rentabilité. Quand même, traitez-les comme des points de départ : confirmez que le type de nœud recommandé correspond à ce que vous voulez vraiment à long terme avant d’engager.

La correction

La séquence d’ajustement de coût qui fonctionne.

Étape 1 : correction de famille. Pour chaque cluster, décidez s’il est dans la bonne famille. La règle : EngineCPUUtilization p95 sous 50 % et pression mémoire présente → r6g. Marges CPU et mémoire toutes deux présentes → considérer m6g pour économiser sur la mémoire dont vous n’avez pas besoin. Dev/préproduction/trafic très faible → t4g si et seulement si vous avez mesuré que le bursting n’est pas soutenu.

Changer de famille exige une recréation du cluster (pas de changement de famille sur place). Le patron est :

aws elasticache create-replication-group \
  --replication-group-id saas-prod-v2 \
  --replication-group-description "Migration de famille" \
  --cache-node-type cache.r6g.xlarge \
  --num-cache-clusters 2 \
  --automatic-failover-enabled \
  --engine redis \
  --engine-version 7.1 \
  --cache-subnet-group-name saas-prod \
  --security-group-ids sg-0123456789abcdef0

Faites la bascule de l’application avec une brève fenêtre de réchauffement, vérifiez, supprimez l’ancien cluster.

Étape 2 : correction de taille. Dans la bonne famille, choisissez la taille où le max mémoire sur 30 jours atterrit à 50–70 % de l’utilisable. Cela laisse de la marge pour la croissance et le burst, sans payer pour des nœuds à moitié vides.

Les changements de taille dans une famille peuvent se faire sur place avec modify-replication-group :

aws elasticache modify-replication-group \
  --replication-group-id saas-prod \
  --cache-node-type cache.r6g.xlarge \
  --apply-immediately

Le modify déclenche un remplacement progressif des nœuds. Chaque nœud est remplacé un à la fois, avec un bref failover quand le primaire est remplacé. La séquence complète sur un cluster à 2 nœuds est 20–40 minutes.

Étape 3 : réservations sur le régime stable. Une fois que le cluster a été redimensionné et est stable depuis un mois, appliquez une réservation d’un an sans paiement initial. L’API de recommandation de Cost Explorer fait surface les candidats. Achetez la réservation correspondant au type et à la quantité réels de nœuds :

aws elasticache purchase-reserved-cache-nodes-offering \
  --reserved-cache-nodes-offering-id <offering-id> \
  --reserved-cache-node-id saas-prod-r6g-xlarge-1yr \
  --cache-node-count 2

L’ID d’offre correspond à un type de nœud et un terme spécifiques. Sortez l’offre correspondante avec describe-reserved-cache-nodes-offerings filtré par type de nœud, terme et type d’offre.

Un point subtil : les réservations sont par type de nœud et région, pas par cluster. Si vous avez deux clusters tous deux roulant cache.r6g.xlarge dans la même région, quatre réservations de ce type de nœud couvrent les nœuds des deux clusters — la réservation est au niveau du compte. Cela signifie que vous pouvez réorganiser des clusters sous des réservations existantes tant que le total par type de nœud correspond.

Étape 4 : audit du working set. Le nœud le moins cher est celui que vous ne faites pas tourner. Certains clusters sont dimensionnés pour des caches qui sont surtout des données rassises — clés mises sans TTL, anciennes entrées de session d’utilisateurs inactifs, réponses calculées que personne n’interroge plus. Mettre des TTL réalistes et activer une politique d’éviction rétrécit le working set.

Vérifiez la politique d’éviction dans le groupe de paramètres :

aws elasticache describe-cache-parameter-groups \
  --query 'CacheParameterGroups[].[CacheParameterGroupName]' \
  --output text

aws elasticache describe-cache-parameters \
  --cache-parameter-group-name saas-prod \
  --query 'Parameters[?ParameterName==`maxmemory-policy`]' \
  --output table

Pour un cache (pas un magasin de sessions), allkeys-lru est généralement le bon — quand la mémoire se remplit, évincit les clés les moins récemment utilisées. Pour un magasin de sessions, volatile-lru est le bon — n’évincit que les clés avec TTL, pour ne pas perdre l’état persistant. Le mauvais défaut (noeviction) fait que le cluster refuse les nouvelles écritures quand la mémoire se remplit — ce qui apparaît comme des erreurs applicatives, pas comme un manque silencieux dans le cache.

Les trois leviers — famille, taille et réservation — se composent. Un cluster passé de m6g.4xlarge à la demande à r6g.xlarge réservé 1 an peut faire chuter son coût de ligne de 60–70 % tout en augmentant la mémoire utilisable. Le travail tient dans un après-midi par cluster et est permanent.


Stack Harbor conçoit les topologies Redis dans le cadre du travail sur le palier cluster en Gestion AWS et de la couche Clusters HA. Si ElastiCache est votre deuxième plus grosse ligne AWS et que personne ne se souvient pourquoi elle a été dimensionnée ainsi, commencez par une consultation d’infrastructure.