La tarification des objets durables semble simple jusqu'à ce que vous calculiez le premier mois réel. Trois composants en interaction, un niveau gratuit qui semble généreux jusqu'à ce que vous mesuriez l'empreinte mémoire correcte, et un plafond de débit qui apparaît bien avant ce que la plupart des ingénieurs attendent lorsque les chiffres de production arrivent. Comprendre la structure avant de la mettre en production évite une facture surprise et une refonte architecturale sous pression.
La structure de coûts à plusieurs niveaux
Le plan Workers Paid est la condition préalable – 5 $/mois, sans cela, les DO ne sont pas disponibles. A partir de là :
Réclamations : 0,15 $/million après le premier million gratuit par mois. Chaque appel à un stub DO compte comme une demande. Le travailleur effectuant le routage utilise le quota de demandes normal des travailleurs, distinct de celui-ci.
Calcul en Go-secondes : 12,50 $/million de Go-secondes après 400 000 gratuits par mois. Go-seconde est l'unité de travail : mémoire utilisée en Go multipliée par le temps d'exécution en secondes. L'empreinte mémoire minimale par instance DO est de 128 Mo (0,125 Go). Une requête qui prend 10 ms à 128 Mo consomme 0,00125 Go-seconde.
Stockage : 0,20 $/Go-mois après 1 Go gratuit. Cumulatif : si vous disposez de 1 000 DO de 10 Ko chacun, cela représente 10 Mo de stockage, bien dans la plage libre. Si vous conservez des données plus volumineuses par instance, le coût de stockage commence à apparaître.
Alarmes : 0,15 $/million d'invocations. Le même tableau que les demandes normales.
Le vrai calcul du niveau de calcul gratuit
400 000 Go-secondes/mois, c'est le chiffre. Avec une empreinte minimale de 128 Mo par instance, cela équivaut à 3,2 millions de secondes d'exécution, soit environ 889 heures de DO actif par mois, réparties entre tous vos DO.
Le compte qui compte est celui de la charge de travail et non celui de la DO. Si vous disposez de DO qui traitent des requêtes allant de 10 ms à 128 Mo, chaque requête consomme 0,00125 Go-seconde. Le niveau gratuit couvre 320 millions de ces demandes, soit bien plus que le niveau gratuit de demandes (1 million). Le goulot d'étranglement du plan gratuit, pour les charges de travail avec des DO légers et rapides, est le quota de requêtes, et non le quota de calcul.
Le scénario qui inverse ce compte est celui des DO qui conservent un état volumineux en mémoire. Si un DO charge un document de 2 Mo en mémoire pour traiter des modifications collaboratives, son empreinte n'est pas de 0,125 Go, elle est plus proche de 0,127 Go, plus la surcharge d'isolation. Pour les DO qui chargent du JSON volumineux, des tampons d'image pour le traitement ou des caches locaux volumineux, le Go-seconde réel augmente avec la taille de l'état en mémoire, et non avec le temps d'exécution de la requête.
Combien coûte une charge de travail concrète ? 1 million de requêtes de 100 ms à 128 Mo : 100 000 Go-secondes = 1,25 $ en calcul (dans le niveau de calcul gratuit, mais au-dessus du niveau de requêtes gratuit : 0,15 $ × (1 − 1) = gratuit s'il s'agit du premier million, 0,15 $ s'il s'agit du deuxième). Au total : 1,25 $ de calcul + 0,15 $ de requêtes supplémentaires = 1,40 $ en plus des 5 $ du forfait.
Le plafond de débit qui apparaît plus tôt que prévu
L'exécution en série garantit la cohérence des DO et leur plafond de débit. Un DO traite une demande à la fois. Le débit maximum par instance est inversement proportionnel au temps moyen par requête.
La formule : débit maximum (req/s) = 1000 ms / temps moyen par requête (ms).
Traitement de 5 ms par requête : 200 req/s par instance DO. Traitement 10 ms : 100 req/s. Traitement 50 ms (y compris les E/S comme appel à un service externe) : 20 req/s.
Ce plafond semble élevé jusqu'à ce que vous disposiez d'une fonctionnalité populaire qui achemine toutes les demandes vers le même DO ID. Une salle de discussion avec 500 messages par seconde envoyés au même DO mettra en file d'attente plus de 300 messages par seconde si le temps de traitement moyen est de 4 ms. La latence perçue par les clients augmente proportionnellement à la taille de la file d'attente.
La solution est le partage. Au lieu de dériver le DO ID directement de la salle ou de la ressource, vous ajoutez un suffixe numérique basé sur un hachage de l'identifiant :
const shardCount = 10; const shard = Math.abs(hashCode(roomId)) % shardCount; const id = env.ROOMS.idFromName(`room-${roomId}-shard-${shard}`);
Chaque partition est une instance DO indépendante, avec son propre plafond de débit. Le partage fonctionne bien pour les opérations où la cohérence doit être garantie uniquement au sein d'une partition. Si vous avez besoin d'une cohérence globale sur toutes les partitions d'une ressource, la solution devient plus complexe.
Limites de stockage surprenantes
list() renvoie un maximum de 128 entrées par appel. Cette limite n'est pas clairement documentée, mais elle apparaît chaque fois que vous avez un DO avec plus de 128 clés en stockage et que vous appelez list() en attendant l'ensemble complet.
La pagination utilise le curseur :
async listAll(): Promise<Map<string, unknown>> { const result = new Map<string, unknown>(); let cursor: string | undefined; while (true) { const batch = await this.ctx.storage.list({ cursor, limit: 128 }); for (const [key, value] of batch) { result.set(key, value); } if (batch.size < 128) break; cursor = [...batch.keys()].at(-1); } return result; }
Ignorer cela en développement (où les DO ont peu de données) et le découvrir en production avec 500 clés est un bug qui produit silencieusement des résultats incorrects : l'application reçoit les 128 premiers éléments et agit comme s'ils l'étaient tous.
Autre limite : les transactions sont confinées à une seule instance DO. Il n'existe aucune transaction atomique qui modifie deux instances DO différentes. Si votre conception nécessite une atomicité entre deux DO (par exemple, le transfert de crédit d'un DO à un autre), vous devez implémenter un protocole de validation en deux phases au niveau de la couche application, avec compensation en cas d'échec. Dans la plupart des cas, cela indique que la conception doit être revue : soit l’État doit vivre dans le même DO, soit l’opération n’a pas besoin d’une atomicité stricte entre les instances.
Que surveiller après la mise en production
La latence de réponse par DO ID est l’indicateur le plus direct du goulot d’étranglement du débit. Si des DO spécifiques ont une latence croissante tandis que d'autres deviennent rapides, ces DO spécifiques mettent en file d'attente les demandes – candidats au partitionnement.
La consommation en Go-secondes par rapport au nombre de requêtes révèle des DO avec une empreinte mémoire plus importante que prévu. Si le rapport Go-secondes/requête augmente sans modifier le temps de traitement, certains DO chargent davantage d'état en mémoire.
Le stockage par espace de noms montre la croissance des données que vous pouvez accumuler sans routine de nettoyage. Les DO qui écrivent sur le stockage sans jamais supprimer accumulent des données indéfiniment – 0,20 $/Go par mois semble bon marché jusqu'à ce que vous disposiez de quelques Go de données historiques auxquelles personne n'a plus accès.
Où 5 $/mois rapportent plus
La base de référence de 5 $/mois couvre le forfait payant. Pour les petites applications utilisées dans les niveaux gratuits, il s’agit du coût total. Pour les applications qui se développent, le coût marginal des trois dimensions (requêtes, calcul, stockage) augmente de différentes manières en fonction du type de charge.
Chargements de requêtes fréquents mais traitement léger : le niveau de requête est épuisé avant le calcul. Solution : vérifiez si l'une des requêtes peut être mise en cache dans la couche Worker avant d'atteindre le DO.
Charges de traitement lourdes avec peu de requêtes : le calcul domine. Solution : mesurez l'empreinte mémoire réelle et le temps d'exécution moyen, et vérifiez si une partie du calcul peut être déplacée vers le Worker qui effectue le routage.
De nombreux DO avec des données persistantes : le stockage domine. Solution : définissez la durée de vie pour les données qui n'ont pas besoin de durer indéfiniment et implémentez des routines de nettoyage via l'API d'alarme.
Les limites les plus répandues en production sont le débit en série et le list(). Le reste vous pourrez le retrouver dans la documentation avant d'être une surprise. Ces deux-là, vous les trouvez dès les premiers jours avec un trafic réel.
A lire aussi
- KV en production : les schémas qui marchent et ceux qui trompent au début
- Objets durables Cloudflare : état cohérent à la périphérie – ce qui change vraiment
- D1 en production : performances, limites et ce qui ne évolue pas seul
- Le modèle de programmation d'objets durables : ce qui ne ressemble à rien de ce que vous avez déjà utilisé
- Durable Objects et WebSockets : multijoueur sans serveur dédié
- Quand les objets durables ne sont pas la bonne réponse
