Combien de RCU et WCU DynamoDB réserver pour maximiser notre réduction de couts AWS, face à une charge qui varie en permanence ?

8 décembre 2022aws, dynamodb, finops
 Cet article a été rédigé il y a plusieurs années et peut ne plus être tout à fait à jour…

Je suis Principal Engineer chez Bedrock. De nombreux microservices de notre plateforme de VOD et de Replay utilisent DynamoDB comme base de données. Les performances sont très bonnes si les données sont architecturées pour, la scalabilité est raisonnablement rapide, et l’aspect serverless nous décharge d’une bonne partie des travaux d’administration et d’hébergement : nous avons juste à spécifier la capacité dont nous avons besoin et à configurer un auto-scaler. Que ce soit sur des aspects performance, résilience ou time-to-market, DynamoDB nous aide à atteindre nos objectifs business.

Cela dit, lorsque nous dépensons plusieurs centaines de milliers de dollars sur DynamoDB tous les ans, toute optimisation est bonne à prendre !

Avec DynamoDB, s’engager pendant un an sur une certaine capacité peut aider à réduire les couts – jusqu’à 50% d’économie, en théorie, sur cette capacité. Mais comment savoir combien réserver, alors que le trafic sur notre plateforme varie tout au long de la journée ?


🇺🇸 English version of this content, @Bedrock
I am a Principal Engineer at Bedrock. This article is the French translation of « How many DynamoDB RCU and WCU should we reserve to achieve maximum cost reductions, when our workloads are changing all the time? », a post I wrote and published on Bedrock’s tech blog in November 2022.


Table des matières


DynamoDB : un modèle de couts pas toujours évident !

Pour sauter toute la théorie à propos du pricing de DynamoDB et des WCU / RCU et des modes de facturation on-demand et provisionned, cliquez ici…

DynamoDB est serverless1 !

Mais, comme pour beaucoup de services AWS, il faut réfléchir un moment avant de vraiment comprendre les coûts DynamoDB…

Des couts hors-périmètre

Nous payons le volume de données stockées, le volume de données sauvegardées.
Ces coûts sont en dehors du périmètre de cet article et je n’en reparlerai pas aujourd’hui.

Ils ne sont toutefois pas nuls et peuvent même représenter une part importante de votre facture – par exemple, si vous stockez des données volumineuses à chaud pendant longtemps2 dans DynamoDB. Chose que vous ne devriez probablement pas faire !

Les WCU et RCU

Chaque table DynamoDB peut être configurée en mode de facturation on-demand ou en mode provisionné.

Dans le second cas, nous payons des RCU (Read Capacity Unit) et des WCU (Write Capacity Unit), en fonction de la capacité que nous provisionnons pour chaque table.
Les réservations portent uniquement sur ces RCU et WCU, en violet dans le screenshot ci-dessous :

Sur l’année passée, nos couts de WCU et RCU en mode provisionné représentent environ la moitié de nos couts DynamoDB. Le stockage et les backups ont des couts que nous considérons aujourd’hui comme négligeables.

Et, d’un point de vue financier, nous travaillons avec beaucoup trop de tables en mode pay-per-request3 à mon gout.

La documentation vous en dira plus mais, dans les très grandes lignes :

  • Une WCU est consommée pour écrire une ligne de données. Ou pour chaque bloc de 1 KB écrit.
  • Une RCU est consommée pour lire une ligne de données. Ou pour chaque bloc de 4 KB lu.
  • En mode de lecture eventually-consistent, seule 1/2 RCU est consommée pour lire une ligne de données. Ou pour chaque bloc de 4 KB.
  • Le mode transactionnel coute le double.

Vous vous en doutez, la première optimisation est de ne stocker que ce qui est nécessaire et de requêter DynamoDB de la manière qui réponde au mieux, y compris en termes de cohérence et de couts, aux besoins de l’application.
Élaborer un schéma de données qui réponde efficacement aux besoins de l’application est primordial.
Je vous recommande d’ailleurs vivement de lire le très bon livre The DynamoDB Book, d’Alex DeBrie ! L’optimisation financière à base de réservations ne doit et ne peut venir qu’après.

Le mode on-demand / pay-per-request

En mode on-demand, nous n’avons théoriquement pas à nous soucier de scalabilité, DynamoDB gère pour nous4.

Dans ce mode, nous payons pour chaque RCU et chaque WCU consommées. Si nous n’utilisons pas DynamoDB, nous ne payons pas. Si nous utilisons DynamoDB, nous payons. La contrepartie est que les RCU et WCU sont plus chères dans ce mode que dans celui présenté plus bas.

Ce mode est donc très pratique dans deux cas :

  • Dans un environnement où nous n’effectuons que quelques requêtes de temps en temps (dev, staging).
  • Pour des tables généralement peu utilisées, mais qui reçoivent des gros pics de requêtes à certains instants.

Ce mode n’est pas adapté, pour raisons de coûts trop élevés :

  • Pour des tables où la consommation est stable ou varie lentement. Typiquement, sur les tables dont la consommation suit notre vague de trafic quotidienne, suffisamment douce sur la plupart des applications pour qu’un mécanisme d’auto-scaling réactif réponde au besoin.

Le mode provisionné

En mode provisionné, nous choisissons de combien de RCU et de WCU nous souhaitons disposer et nous payons ce nombre de RCU et de WCU – que nous les consommions ou non.
Ce mode de facturation est donc moins souple que le mode on-demand. En contrepartie, les RCU et WCU sont moins chères.

En mode provisionné, nous pouvons mettre en place un auto-scaler sur les RCU et sur les WCU des tables qui en ont besoin. Il reconfigurera dynamiquement les RCU et WCU provisionnées pour ces tables, pour se rapprocher de l’usage réel.
Avec un auto-scaler, nous pouvons payer au plus proche de notre consommation réelle, au tarif provisionné moins élevé que celui on-demand.

Toutefois, le scale-out n’est pas instantané : il lui faut plusieurs minutes pour détecter qu’il doit agir, puis jusqu’à plusieurs minutes (surtout sur une grosse table) pour agir. Aussi et en simplifiant, le scale-in ne peut être déclenché qu’une fois par heure.
Pour des informations plus détaillées, lisez la documentation et la page de quotas.

Ce mode est particulièrement recommandé :

  • Aussi souvent que possible, puisque chaque RCU et WCU coutent nettement moins cher qu’en mode on-demand.

Ce mode n’est pas adapté :

  • Sur les tables où la consommation varie très abruptement.

En mode provisionné, des réservations

En nous engageant pour un an (voire trois ans dans certaines regions) à payer une certaine quantité de RCU et de WCU, ces RCU et WCU deviennent encore moins chères : jusqu’à ~50%5 moins cher qu’en mode provisionné de base.
Réserver de la capacité est donc un très bon moyen pour réduire considérablement la facture des opérations read/write sur DynamoDB !

Les réservations nous engagent pour un an. Nous payerons les RCU et WCU réservées, que nous les utilisions ou non.
Il est donc important de calculer correctement les réservations à effectuer.

Aussi, nous payons une partie du montant total annuel en début d’engagement (= “upfront”) et devons donc pouvoir investir une certaine somme en avance.
L’autre partie du montant est étalée sur tous les mois de la période d’engagement.

La grande question, à laquelle la suite de ce document essaye de répondre, est donc « combien de RCU et de WCU devons-nous réserver pour baisser nos coûts au maximum ? »
Lorsque notre consommation varie tout au long de la journée, ce calcul est assez fun…

Ces réservations sont globales à un compte AWS, ou même à tous les comptes qui sont en facture consolidée6.

→ Le pricing “réservé” est documenté sur la page du pricing “provisionné”.
→ Vous pouvez aussi lire ce whitepaper.


Combien de WCU et de RCU consommons-nous ?

Pour la suite de notre raisonnement et de cet article, nous ne comptons que la consommation en mode provisionné (et pas on-demand), puisque c’est là que nous pouvons jouer avec des réservations.
Aussi, nous comptons les WCU et RCU provisionnés et pas ce qui est réellement consommé – attention au gaspillage donc.

Sur l’écran d’accueil de la console Web DynamoDB, nous pouvons voir, pour un compte et une région, combien de WCU et RCU nous avons de provisionnés à l’instant courant :

Mais ces nombres ne donnent qu’une vision à un instant donné, dans un seul compte AWS et dans une seule région.
Pour nous qui déployons notre plateforme à travers des dizaines de comptes et plusieurs régions, avec un trafic qui évolue tout au long de la journée, ce n’est pas suffisant.

Les WCU/RCU des tables

Pour avoir une vue globale sur toutes les tables d’un compte dans une région, nous pouvons requêter Cloudwatch Metrics, en analysant les métriques ProvisionedWriteCapacityUnits ou ProvisionedReadCapacityUnits :

L’affichage Stacked Area permet de voir, à chaque instant, le total de WCU (ou de RCU) provisionnées pour l’ensemble de nos tables, dans un compte et une région.

Les WCU/RCU des GSI

Attention, nous voulons aussi compter les WCU/RCU des Global Secondary Indexes – et ce sont des métriques différentes ! Ou, du moins, les métriques sont rangées dans une autre catégorie dans la console Web Cloudwatch.

Donc, au total…

Pour avoir le total, il faut prendre en compte cette métrique pour les tables et pour les Global Secondary Indexes ! Dans la console Cloudwatch, il faut donc chercher dans deux catégories.
En graphant le tout :

Bien sur, ceci est à regarder pour les WCU, mais également pour les RCU, en suivant exactement le même principe. Et, encore une fois, nous travaillons sur plusieurs comptes et régions.


En théorie : combien réserver pour économiser au maximum ?

Une fois que nous savons combien nous provisionnons réellement, nous pouvons passer aux réservations.

Mais le calcul serait bien trop facile si notre utilisation était plate !
En réalité, grâce à l’auto-scaling, notre capacité provisionnée suit notre vague de trafic habituelle…

Et, deux choses :

  • si nous réservons plus que ce que nous ne provisionnons, nous gaspillons de l’argent.
  • si nous réservons moins que ce que nous ne provisionnons, nous ne réalisons pas autant d’économies que nous pourrions.

Réserver en bas de la vague

Une première idée est de réserver la valeur la plus basse que nous provisionnons au long de la journée : ce que nous provisionnons au creux de la vague de trafic, la nuit.

Dans ce cas, nous ne gaspillons pas d’argent, puisque nous provisionnons toujours à 100% ou plus de notre réservation.
Mais nous minimisons sans doute notre économie, puisque nous provisionnons plus haut que la réservation, tout au long de la journée…

Réserver en haut de la vague

Une seconde idée, à l’opposé, est de réserver la valeur la plus “haute” que nous provisionnons au long de la journée.
Nous ne payerons ainsi jamais le plein tarif pour nos WCU/RCU.

Mais, dans ce cas, nous gaspillerons beaucoup d’argent, puisque, toute la journée, nous provisionnerons moins que notre réservation.
C’est une mauvaise idée.

Réserver “au milieu” en faisant les bons calculs

Reste donc la vraie solution : calculer un juste milieu et réserver :

  • Moins que la valeur la plus haute, pour minimiser le gaspillage.
  • Et plus que la valeur la plus basse, pour optimiser l’économie.

En pratique : calculons combien réserver !

Manipuler des métriques dans Cloudwatch, pour de la visualisation, peut être acceptable, même si nous ne le faisons que rarement puisque nous utilisons d’autres stacks pour nos métriques. Et regrouper les métriques de plusieurs comptes doit être faisable (nous n’avons pas essayé).
Mais pour des calculs, ce n’est pas suffisant.

Exporter les métriques

Comme première étape, nous avons exporté les métriques visualisées plus haut, pour pouvoir les manipuler dans un autre outil – dans un tableur, par exemple.
Pour exporter ces métriques depuis Cloudwatch, nous pouvons interroger son API. Nous devons le faire pour tous les comptes et pour chacune des tables. Compliqué de faire cela manuellement.

Pour nous simplifier la tâche, nous avons commencé à travailler avec un script permettant d’exporter ces données vers un fichier CSV.
Plus précisément, ce script exporte un point de donnée par heure : le nombre de WCU ou de RCU réellement provisionnées pendant cette heure.

En lançant ce script sur une durée d’une semaine représentative, nous avons suffisamment de données pour calculer les réservations idéales…

🗓️ Semaine représentative ?
Bien sûr, nous devons veiller à bien choisir la semaine sur laquelle nous nous concentrons.
Si nous travaillons avec les données d’une semaine avec un énorme pic, ou creux, de trafic inexpliqué, les résultats de notre calcul seront adaptés à cette semaine, mais pas tellement au reste de l’année !

Un Google Spreasheet de calcul

En important ces données dans un Google Spreadsheet, nous obtenons deux colonnes : une date+heure et un nombre de WCU.
Et ce, pour chaque plage d’une heure pendant une semaine :

ℹ️ Seulement douze heures
Je ne reproduis ici que douze lignes correspondant à douze heures, mais considérez qu’il y a en réalité 168 lignes dans mon tableur : une ligne par heure, 24 heures par jour, pendant 7 jours.
Aussi, les valeurs utilisées pour cet article sont toutes simulées, pour ne pas partager d’informations sensibles, mais elles respectent scrupuleusement la forme de notre vague de trafic et de consommation.

L’étape suivante est d’intégrer le cout de ces WCU.
Facile, nous multiplions le nombre de WCU par le cout d’un WCU à Paris, soit $0.000772.
Et la somme du cout de chaque ligne nous donne le cout total, sans réservation :

Les calculs, sur une hypothèse

Maintenant, partons, pour l’exemple, sur l’hypothèse que nous réservons 25,000 WCU :

  • L’upfront, chaque heure, est donc de $5.07991.
  • Et, chaque heure, nous devons également payer $3.82500 pour cette capacité, puisque l’upfront n’est que partiel.

En complément :

  • Sur certaines heures, celles où nous consommons moins de 25,000 WCU, nous ne payerons rien de plus.
  • Sur d’autres heures, par contre, lorsque nous consommons plus que 25,000 WCU, nous devrons payer un complément, au plein-tarif provisionné.

En additionnant ces données, nous obtenons un cout horaire différent, souvent inférieur à celui déterminé plus haut.
Et, donc, nous obtenons un cout total lui aussi plus bas :

Avec cette hypothèse de réservation de 25,000 WCU, sur ces douze heures, nous payerions 135 dollars au lieu de 229 dollars sans réservation.
Nous réaliserons alors 40.96% d’économies !

Les calculs, jusqu’à trouver la bonne valeur

Bien sûr, pendant les heures où nous consommons moins de 25,000 WCU, nous gaspillons de la capacité : nous la payons, sans l’exploiter.

Le but du jeu est de trouver le bon nombre de WCU à réserver : nous souhaitons réduire au maximum le cout total, maximiser le pourcentage d’économie.

Pour cela, nous essayons différentes valeurs pour le nombre de WCU réservés, jusqu’à trouver celle qui maximise le pourcentage d’économies :

Ou la même chose sous forme d’un graphique :

Ici, sur ces douze heures, l’optimal serait de réserver 23,000 WCU.

💪 En réalité : une semaine entière
En réalité, nous réalisons exactement le même calcul, nous suivons exactement cette logique, sur 168 lignes de données, correspondant à une semaine représentative.

Faciliter les calculs ?

Nous avons rapidement, dès la première année, écrit un script pour collecter les données depuis Cloudwatch et les exporter en CSV.

Nous n’avons toujours pas, après trois ou quatre ans maintenant, écrit de programme qui effectuerait les calculs basés sur ces données pour sortir la bonne valeur de nombre de WCU ou de RCU à réserver.
En effet, copier-coller les données depuis le CSV vers un spreadsheet ne prend que quelque dizaines de secondes, nous réutilisons le même d’une année sur l’autre, et son côté visuel est apréciable…

Aussi, puisque nos réservations durent un an, nous n’effectuons ces calculs que deux fois par an : nous n’effectuons que deux réservations par an, pour ne pas y passer trop de temps, tout en affinant plus souvent qu’une seule fois chaque année.
Chaque fois, le processus nous prend environ deux heures en pair7, soit une journée par an au total… Et le plus long est de discuter avec nos collègues gros consommateurs de DynamoDB, pour leur demander “tu ne comptes pas réduire la consommation de ton projet sur l’année qui vient ?”.


Finalement, réservons !

Nous avons calculé combien de WCU et combien de RCU réserver pour réaliser la meilleure économie possible, dans les conditions de la semaine représentative sur laquelle nous nous sommes basés.

Un engagement : soyons prudents…

Une réservation nous engage à payer pour un an, que nous consommions ou non la capacité sur laquelle nous nous engageons.

Il est donc toujours bon de prendre un moment pour valider avec nos collègues qu’ils ne prévoient pas d’utiliser moins DynamoDB prochainement.
Bien sûr, la réponse est souvent en partie « ça dépend », puisque la consommation dépend des nouveaux projets ainsi que de la fréquentation de nos plateformes, mais si nous pouvons déjà anticiper les prochaines optimisations prévues, c’est toujours ça de gagné.

En novembre 2022, nous ne pouvons ouvrir de réservation DynamoDB que pour un an si nous travaillons dans la région AWS Paris.
D’autres régions (us-east-1 par exemple) permettent de réserver sur trois ans et réaliser des économies plus substantielles. D’un autre côté, serions-nous prêts à nous engager sur trois ans et perdre un avantage majeur du Cloud, sa souplesse ?

Sur quel compte réserver ?

La documentation dit (emphasis mine) :

If you have multiple accounts linked with consolidated billing, reserved capacity units purchased either at the payer account level or linked account level are shared with all accounts connected to the payer account.
Reserved capacity is applied first to the account that purchased it and then any unused capacity is applied to other linked accounts.

Nous avons configuré nos comptes AWS pour avoir un unique payer account.
Nous avons choisi d’effectuer toutes nos réservations dans ce compte et elles s’appliquent sur les comptes enfants sans discrimination. Ce pour DynamoDB mais aussi pour RDS, EC2, Elasticache…

Réserver

Pour réserver, nous passons par la console Web AWS DynamoDB, en nous positionnant dans le payer account et dans la région où ces réservations seront utilisées.

C’est sur cet écran que vous pouvez visualiser combien de WCU et de RCU nous avons déjà réservé.
Puisque nous effectuons plusieurs réservations au cours de l’année, les réservations déjà en cours sont à retrancher aux valeurs calculées plus haut !

Pour créer une nouvelle réservation, cliquer sur “Purchase reserved capacity” et remplissez le formulaire ;-)


Après réservation, visualiser les coûts

Une fois les réservations effectuées, dans AWS Cost Explorer, le coût d’upfront est bien visible.
Il est facturé en une fois le jour où nous avons ouvert la réservation :

Pour avoir une vue “quotidienne” des coûts de WCU/RCU (réservées + provisionnées en plus des réservations), pensez à renseigner “Show costs as: Amortized costs” pour lisser le prix mensuel des réservations sur tous les jours du mois :

🏦 Réservations et un seul payer account
Puisque les réservations, qui couvrent le plus gros de nos coûts DynamoDB, sont effectuées sur notre payer account, le gros de nos coûts DynamoDB remontent sur ce compte… Et pas sur les comptes des tenants/environnements.
Bon courage pour le suivi et la répartition des couts sur les projets et équipes 💪


Conclusion

Nous travaillons beaucoup avec DynamoDB, pour plusieurs dizaines de microservices et affrontons plusieurs types de couts d’infrastructure : lectures/écriture on-demand, lecture/écritures en mode provisionné, stockage, backups.
En échange d’une perte de souplesse et par le biais de réservations qui nous engagent pendant un an, AWS permet de réduire le cout des lectures/écritures en mode provisionné.

Déterminer combien réserver, en cas de charge qui varie en permanence, n’est pas facile.
Nous avons besoin d’une certaine vision sur les évolutions d’usages, sur un an et devons accepter de perdre en souplesse.
Et nous devons trouver les bonnes valeurs à réserver pour la capacité en lecture et en écriture.

Avec trois ou quatre ans de recul, en effectuant des réservations deux fois par an et en suivant à chaque fois la méthode détaillée dans cet article, nous réalisons de l’ordre de 30% à 35% d’économie sur nos lectures et écritures en mode provisionné.
À notre échelle, cette économie représente plusieurs dizaines de milliers de dollars par an et nous rentabilisons donc très bien les quelques heures que nous y passons tous les six mois !


Si le sujet de la réduction des couts d’hébergement chez AWS vous intéresse, vous voudrez peut-être enchainer avec l’enregistrement de mon talk « Comment nous réduisons l’augmentation de nos coûts AWS » :

J’y montre par exemple l’économie substantielle que nous avons réalisé en basculant certaines tables DynamoDB du mode on-demand au mode provisionné avec auto-scaling ;-)


🇺🇸 English version of this content, @Bedrock
I am a Principal Engineer at Bedrock. This article is the French translation of « How many DynamoDB RCU and WCU should we reserve to achieve maximum cost reductions, when our workloads are changing all the time? », a post I wrote and published on Bedrock’s tech blog in November 2022.



  1. DynamoDB est un des services les plus serverless que nous utilisons et je l’aime beaucoup. Cela dit, il y a toujours quelques tâches d’administration qui nous reviennent encore. Typiquement, nous devons spécifier la capacité dont nous avons besoin et configurer un auto-scaler. Nous devons aussi activer le chiffrement, les backups, configurer des permissions – et vérifier que tout ceci soit fait, pour toutes les tables, gérées par de nombreuses équipes. ↩︎

  2. Si vous stockez beaucoup de données pendant longtemps dans DynamoDB, jetez un coup d’oeil à Standard-IA, qui pourrait vous aider à réduire vos couts. ↩︎

  3. Pourquoi utilisons-nous autant l’approche pay-per-request? Et bien, en bref, parce que ce mode est plus flexible que le mode provisionné, et une partie de nos projets acceptent de payer bien plus cher, en échange de cette flexibilité. ↩︎

  4. DynamoDB en mode on-demand et scalabilité: en pratique, AWS cache ce qu’il se passe, mais ne scale pas à l’infini instantanément non plus. ↩︎

  5. 50% est à peu près le maximum théorique qu’il est possible d’économiser, si notre utilisation est plate et si nous réservons exactement ce que nous provisionons. Une utilisation plate est peut-être ce que vous avez sur vos applications, mais ça ne correspond pas à la manière font notre plateforme fonctionne ! ↩︎

  6. Chez Bedrock, nous disposons d’un compte AWS dédié à la facturation : un “payer account”. Il aggrége les couts de tous nos autres comptes. Les réservations sont aussi partagées entre tous les comptes (whitelistés) qui partagent le même payer account↩︎

  7. Pour ce type de calculs et de réservations, nous travaillons généralement en pair, puisque les sommes d’argent en jeu sont importantes. Diminuer le risque d’une erreur couteuse est une plutôt bonne idée. ↩︎