Cloudflare
Durable Objects
Arquitetura
Trade-offs
Decisão Técnica

Quand les objets durables ne sont pas la bonne réponse

Une analyse honnête des cas où il ne faut pas utiliser les objets durables, avec les alternatives correctes pour chaque cas d'utilisation et la question de diagnostic qui simplifie la décision.

Les objets durables prennent de l'importance parce qu'ils résolvent quelque chose de difficile – un état cohérent avec un accès sérialisé à la périphérie – et cela crée un biais : les ingénieurs qui viennent d'apprendre l'outil ont tendance à l'appliquer à des problèmes qu'il n'a pas besoin de résoudre. Le résultat n’est pas un mauvais code. C'est un code correct, fonctionnel, plus cher et plus complexe qu'il ne devrait l'être. Pour un simple CRUD construit sur des DO lorsque D1 suffirait, la facture pourrait être entre dix et cinquante fois plus importante, sans aucun avantage de cohérence qu'exigerait le cas d'utilisation.

La question qui détermine si vous avez besoin de FAIRE

Avant de choisir des objets durables, il y a une question concrète : l'état que vous devez gérer nécessite-t-il un accès sérialisé à partir de plusieurs clients simultanés ?

Sérialisé signifie que l'ordre des opérations est important et que deux opérations simultanées sur les mêmes données doivent s'exclure mutuellement. Plusieurs clients concurrents signifient que plusieurs agents peuvent tenter de modifier les mêmes données en même temps et que les deux agents doivent obtenir un résultat cohérent.

Si la réponse est non (si les données sont lues par plusieurs mais écrites rarement, ou si les écritures simultanées dans le même enregistrement sont peu probables ou gérées par une autre couche), un DO ajoute de la complexité et des coûts sans ajouter de garantie utile.

Où D1 est la bonne réponse

Pour les données relationnelles, D1 est la place naturelle au sein de la pile Cloudflare. Il dispose d'un SQL complet, prend en charge les JOIN, les index, les transactions, les requêtes ad hoc — tout ce que D1 a et que DO n'a pas. Un DO est un magasin clé-valeur linéarisable avec API procédurale. Il n'a aucun moyen de répondre « lister tous les utilisateurs qui se sont connectés au cours des 7 derniers jours et qui ont toujours un solde positif » sans que vous ayez explicitement pré-calculé et stocké ces données.

D1 a un coût beaucoup plus faible pour les charges de lecture : 0,001 $/million de lignes lues, 1,00 $/million de lignes écrites. La latence d'écriture supplémentaire dans la région bancaire principale, qui constitue l'inconvénient le plus cité de D1, n'affecte que les opérations d'écriture. Pour les applications où les lectures dominent, ce compromis est largement en faveur de D1.

Le cas déroutant : "mais j'ai besoin que les écritures soient atomiques". D1 a des transactions. BEGIN; UPDATE a...; UPDATE b...; COMMIT; garantit l’atomicité. La différence est que D1 utilise des verrous de base de données — avec un potentiel de conflit en cas de concurrence élevée — tandis qu'un DO utilise la sérialisation dès la conception. Pour l'écrasante majorité des applications avec des charges d'écriture normales, D1 avec transactions est suffisant et beaucoup moins cher.

Où KV est la bonne réponse

KV est optimisé pour le modèle qui domine la plupart des cas d'utilisation Edge : beaucoup de lectures, écritures occasionnelles, aucune exigence de cohérence forte entre les différents PoP. Cache de configuration, résultats de calcul précalculés, sessions utilisateur où la cohérence éventuelle est acceptable : KV répond aux lectures de cache local dans le PoP avec une latence inférieure à la milliseconde et un modèle de tarification qui favorise les lectures intensives.

L'erreur est de supposer que, comme KV n'a pas d'opérations atomiques de lecture-modification-écriture, vous avez besoin de DO pour tout ce qui change. La grande majorité des données dans les applications Web changent selon des modèles qui ne nécessitent pas une atomicité stricte : le profil utilisateur mis à jour lorsque l'utilisateur modifie ses préférences n'a pas besoin d'exclusion mutuelle avec un autre script concurrent, car personne d'autre ne modifie le même profil en même temps.

DO commence à avoir un sens lorsque la fréquence des écritures simultanées sur les mêmes données est suffisamment élevée pour que la cohérence éventuelle de KV produise des résultats incorrects visibles pour l'utilisateur.

La limitation de débit n'est pas un cas d'utilisation DO

La limitation de débit est l'exemple le plus courant de "on dirait qu'il a besoin de DO mais ce n'est pas le cas". L'intuition est correcte : la limitation de débit nécessite un compteur par utilisateur qui est incrémenté atomiquement à chaque requête. Si deux Workers incrémentent le même compteur en même temps, il peut y avoir une condition de concurrence qui permet à un utilisateur de faire plus de demandes que la limite.

L'API Cloudflare Rate Limiting résout ce problème de manière native, sans code, sans DO, et sans coût supplémentaire au-delà du plan. Il est disponible sur tous les forfaits payants, prend en charge les limites par IP, par utilisateur authentifié, par itinéraire, par en-tête et avec des périodes configurables. Pour la limitation de débit en périphérie, l'utilisation de l'API native est plus simple, moins chère et plus fiable que la mise en œuvre d'un compteur DO.

Le cas légitime de DO pour la limitation de débit est lorsque vous avez des exigences que l'API native ne couvre pas : une logique de fenêtre coulissante personnalisée avec une précision exacte, des limites qui dépendent des données de session utilisateur qui ne figurent pas dans les en-têtes ou une limitation de débit qui doit être cohérente avec d'autres données qui résident déjà dans un DO d'application.

## Files d'attente de travailleurs pour le traitement asynchrone

Un autre modèle qui apparaît parfois comme candidat pour DO : une file d'attente de travail où plusieurs producteurs mettent les tâches en file d'attente et plusieurs consommateurs traitent. DO pourrait modéliser cela comme un objet avec une liste de tâches et une boucle de traitement.

Les files d'attente des travailleurs résolvent ce problème de manière native : les producteurs gagnent env.QUEUE.send(message), les consommateurs reçoivent des lots via un gestionnaire, avec une nouvelle tentative automatique, une file d'attente de lettres mortes et des frais distincts de 0,40 $/million de messages. Pour le traitement asynchrone avec tentatives et interruptions, les files d'attente sont mieux adaptées, moins chères et n'ont pas le plafond de débit série d'un DO.

DO pour le traitement asynchrone a du sens lorsque la consommation doit être sérialisée par identité (traitant toutes les actions d'un utilisateur dans l'ordre, sans parallélisme) et lorsque ce traitement doit de toute façon accéder à un état local du DO.

Le stockage de fichiers est R2, pas le stockage DO

Le stockage DO est un magasin clé-valeur optimisé pour les petits objets : paramètres, compteurs, état de session, messages. Il n'a pas de limites documentées par valeur, mais est conçu pour les données qui peuvent raisonnablement s'intégrer dans une requête. Pour les fichiers, les images, les vidéos et tout blob plus volumineux, R2 est le bon endroit : 0,015 $/Go-mois de stockage (moins d'un dixième du coût du stockage DO), aucun coût de sortie pour les travailleurs, avec une API compatible S3.

Le stockage DO ne remplace pas le stockage objet : il s'agit d'un magasin d'état transactionnel pour DO lui-même.

Diagnostic avant de choisir

Quatre cas d'utilisation où DO résout quelque chose que les alternatives ne résolvent pas avec les mêmes garanties : édition collaborative avec plusieurs clients modifiant le même document simultanément, coordination de présence en temps réel où la liste de ceux qui sont en ligne doit être cohérente, verrous distribués avec délai d'expiration où l'expiration doit être garantie même si le titulaire plante, et journaux d'événements classés par arrivée où l'ordre d'insertion est sémantiquement important.

Pour tout ce qui ne rentre pas dans cette liste, il existe une alternative au sein de la plateforme qui est moins chère, plus simple ou les deux. La décision d'utiliser DO commence par la question de la sérialisation. Si vous ne parvenez pas à expliquer pourquoi la sérialisation de l'accès aux données est nécessaire pour le cas d'utilisation, DO n'est probablement pas l'outil.

Le risque d’utiliser DO là où ce n’est pas nécessaire n’est pas que cela casse quoi que ce soit : le code fonctionnera. Le coût est d'entraîner une complexité inutile : une abstraction qui impose des limites de débit en série, nécessite un plan Workers Paid comme condition préalable, a une courbe d'apprentissage distincte et coûte plus cher que les alternatives pour les cas que les alternatives résolvent bien. Pour une équipe qui utilise déjà des DO ailleurs dans le système, le coût marginal d’un DO supplémentaire est inférieur. Pour une équipe commençant chez Cloudflare avec un simple CRUD, commencer par D1 et KV et ajouter des DO où la sérialisation est véritablement nécessaire est le bon ordre de complexité.

A lire aussi

-Cloudflare Durable Objects : État cohérent à la périphérie – ce qui change vraiment