Magasins de mémoire

*Ce contenu est traduit en utilisant l'IA (Beta) et peut contenir des erreurs. Pour consulter cette page en anglais, clique ici.

MemoryStoreService est un service de données à haut débit et faible latence qui fournit un stockage de données en mémoire rapide accessible depuis tous les serveurs dans une session en direct. Les magasins de mémoire sont adaptés aux données fréquentes et éphémères qui changent rapidement et n'ont pas besoin d'être durables, car ils sont plus rapides d'accès et disparaissent lorsqu'ils atteignent la durée de vie maximale. Pour les données qui doivent persister entre les sessions, utilisez les magasins de données.

Structures de données

Au lieu d'accéder directement aux données brutes, les magasins de mémoire disposent de trois structures de données primitives partagées entre les serveurs pour un traitement rapide : carte triée, file d'attente et carte de hachage. Chaque structure de données est bien adaptée à certains cas d'utilisation :

  • Appariement basé sur les compétences - Enregistrez les informations des utilisateurs, telles que le niveau de compétence, dans une file d'attente partagée entre les serveurs, et utilisez des serveurs de lobby pour exécuter l'appariement périodiquement.
  • Échanges et enchères inter-serveurs - Permettez un échange universel entre différents serveurs, où les utilisateurs peuvent enchérir sur des objets avec des prix changeant en temps réel, avec une carte triée de paires clé-valeur.
  • Classements mondiaux - Stockez et mettez à jour les classements des utilisateurs sur un classement partagé à l'intérieur d'une carte triée.
  • Inventaires partagés - Enregistrez les objets d'inventaire et les statistiques dans une carte de hachage partagée, où les utilisateurs peuvent utiliser les objets d'inventaire simultanément les uns avec les autres.
  • Cache pour les données persistantes - Synchronisez et copiez vos données persistantes dans un magasin de données vers une carte de hachage de magasin de mémoire qui peut agir comme un cache et améliorer les performances de votre jeu.

En général, si vous devez accéder aux données en fonction d'une clé spécifique, utilisez une carte de hachage. Si vous avez besoin que ces données soient ordonnées, utilisez une carte triée. Si vous devez traiter vos données dans un ordre spécifique, utilisez une file d'attente.

Limites et quotas

Pour maintenir la scalabilité et la performance du système, les magasins de mémoire ont des quotas d'utilisation des données pour la taille de la mémoire, les requêtes API et la taille de la structure de données.

Les magasins de mémoire ont une politique d'éviction basée sur le temps d'expiration, également connu sous le nom de temps de vie (TTL). Les éléments sont évincés après leur expiration, et le quota de mémoire est libéré pour de nouvelles entrées. Lorsque vous atteignez la limite de mémoire, les requêtes qui augmentent l'utilisation de la mémoire échouent jusqu'à ce que vous libériez de la mémoire ou augmentiez votre quota. Consultez Récupérer d'une épuisement de quota de mémoire pour les options.

Quota de taille de mémoire

Le quota de mémoire limite la quantité totale de mémoire qu'un jeu peut consommer. Ce n'est pas une valeur fixe ; au lieu de cela, elle change au fil du temps en fonction du nombre d'utilisateurs dans le jeu selon la formule 64 Ko + 1,2 Ko * [nombre d'utilisateurs]. Le quota s'applique au niveau du jeu plutôt qu'au niveau du serveur.

Lorsque des utilisateurs rejoignent le jeu, le quota de mémoire supplémentaire est disponible immédiatement. Lorsque des utilisateurs quittent le jeu, le quota ne diminue pas immédiatement. Il y a une période de retour de huit jours avant que le quota ne soit réévalué à une valeur inférieure.

Après que votre jeu ait atteint le quota de taille de mémoire, toutes les requêtes API qui augmentent la taille de la mémoire échouent toujours. Les requêtes qui diminuent ou ne changent pas la taille de la mémoire réussissent toujours.

Avec le tableau de bord observabilité, vous pouvez voir le quota de taille de mémoire de votre jeu en temps réel à l'aide du graphique Utilisation de la mémoire.

Limites de requêtes API

Un quota de unité de requête s'applique à tous les appels API de MemoryStoreService. Ce quota est de 1000 + 120 * [nombre d'utilisateurs simultanés] unités de requête par minute.

La plupart des appels API ne consomment qu'une unité de requête, avec quelques exceptions :

  • MemoryStoreSortedMap:GetRangeAsync()

    Consomme des unités en fonction du nombre d'éléments retournés. Par exemple, si cette méthode retourne 10 éléments, l'appel compte comme 10 unités de requête. S'il retourne une réponse vide, cela compte comme une unité de requête.

  • MemoryStoreQueue:ReadAsync()

    Consomme des unités en fonction du nombre d'éléments retournés, tout comme MemoryStoreSortedMap:GetRangeAsync(), mais consomme une unité supplémentaire toutes les deux secondes pendant la lecture. Spécifiez le temps de lecture maximum avec le paramètre waitTimeout.

  • MemoryStoreHashMap:UpdateAsync()

    Consomme un minimum de deux unités.

  • MemoryStoreHashMap:ListItemsAsync()

    Consomme [nombre de partitions scannées] + [éléments retournés] unités.

Le quota de requêtes s'applique également au niveau du jeu plutôt qu'au niveau du serveur. Cela offre une flexibilité pour répartir les requêtes entre les serveurs tant que le taux total de requêtes ne dépasse pas le quota. Si vous dépassez le quota, vous recevez une réponse d'erreur lorsque le service limite vos requêtes.

Avec la fonctionnalité observabilité disponible, vous pouvez voir le quota d'unités de requête de votre jeu en temps réel.

Limites de taille de structure de données

Pour une seule carte triée ou file d'attente, les limites de taille et de nombre d'éléments suivantes s'appliquent :

  • Nombre maximum d'éléments : 1 000 000
  • Taille totale maximale (y compris les clés pour la carte triée) : 100 Mo

Limites par partition

En plus du quota d'unités de requête au niveau du jeu, les magasins de mémoire appliquent des limites de requêtes à chaque partition comme mesure de protection qui préserve la stabilité du service pour tous les jeux. Ces limites ne sont pas un quota qui est alloué à votre jeu, et elles ne constituent pas un plafond strict sur le débit que votre jeu peut atteindre. Les valeurs suivantes sont des estimations. Elles sont configurées sur le backend de Roblox et peuvent changer, donc ne les concevez pas comme des chiffres fixes.

Chaque requête compte pour la limite de la partition qui détient l'élément, quelle que soit la structure de données. Vous pouvez actuellement vous attendre à ce que la limitation commence à environ 30 000 unités de requête par minute pour une seule partition, donc visez à rester bien en dessous de ce taux. La quantité de ce quota qu'une structure de données consomme dépend de la façon dont ses éléments sont distribués :

  • Les cartes triées et les files d'attente résident chacune sur une seule partition, donc chaque requête à l'une de ces structures de données compte pour la même limite de partition.
  • Les cartes de hachage répartissent leurs éléments sur de nombreuses partitions, donc le trafic réparti sur de nombreuses clés d'éléments n'atteint que rarement la limite d'une seule partition.

Les cartes de hachage ont une limite supplémentaire sur chaque clé d'élément d'environ 5 000 unités de requête d'écriture par minute et 15 000 unités de requête de lecture par minute. Cette limite par clé s'applique en plus de la limite par partition, donc une clé fréquemment accédée peut atteindre l'une ou l'autre. La limite par clé s'applique uniquement aux opérations à clé unique : la limite de lecture s'applique à MemoryStoreHashMap:GetAsync(), la limite d'écriture s'applique à MemoryStoreHashMap:SetAsync() et MemoryStoreHashMap:RemoveAsync(), et MemoryStoreHashMap:UpdateAsync() compte à la fois contre les limites de lecture et d'écriture. MemoryStoreHashMap:ListItemsAsync() scanne les partitions plutôt qu'une seule clé, donc seule la limite par partition s'applique à elle.

Si vous n'avez pas besoin de tri ou de fonctionnalité de premier arrivé, premier servi, une carte de hachage est généralement le meilleur choix car elle peut répartir la charge sur les partitions.

Lorsque les requêtes dépassent une limite de partition ou par clé, le service les limite et renvoie un code d'état PartitionRequestsOverLimit, que vous pouvez surveiller avec le tableau de bord observabilité.

Si vous vous attendez à ce qu'une structure de données ou une clé d'élément reçoive un taux de requêtes élevé et soutenu, shard pour que la charge se répartisse sur plus de partitions ou de clés. Répartissez les lectures et les écritures uniformément sur plusieurs clés d'éléments pour rester dans les limites par clé. Vous pouvez également réduire le taux de requêtes en mettant en cache des valeurs sur le serveur et en les vérifiant à nouveau après un intervalle, en regroupant les requêtes lorsque cela est possible, et en appliquant un retour exponentiel lorsque vous recevez des réponses de limitation.

Récupérer d'une épuisement de quota de mémoire

Si votre jeu reçoit des erreurs TotalMemoryOverLimit, vérifiez le graphique Utilisation de la mémoire dans le tableau de bord d'observabilité. Pour reprendre les écritures qui augmentent l'utilisation de la mémoire, supprimez les éléments non nécessaires, attendez que les éléments expirent ou utilisez l'une des options suivantes.

Vider les magasins de mémoire avec Open Cloud

Si vous n'avez plus besoin des données stockées, utilisez le point de terminaison Open Cloud Vider le magasin de mémoire pour effacer de manière asynchrone toutes les structures de données de magasin de mémoire dans un univers pour la portée sélectionnée.

Pour vider les magasins de mémoire :

  1. Créez une clé API avec des autorisations pour vider les magasins de mémoire et obtenir le statut de l'opération de vidage pour l'univers cible.
  2. Envoyez une requête POST à https://apis.roblox.test1709.icu/cloud/v2/universes/{universe_id}/memory-store:flush avec la clé API dans l'en-tête x-api-key. Remplacez {universe_id} par l'ID de l'univers de votre jeu. Définissez le paramètre de requête scope sur LIVE pour les données de production ou TEST pour les données de Studio. Si vous omettez scope, le point de terminaison utilise LIVE.
  3. Utilisez Obtenir l'opération de vidage du magasin de mémoire pour interroger l'opération retournée par la requête de vidage jusqu'à ce que done soit true, et vérifiez s'il y a une erreur. Utilisez la même portée lors de l'interrogation. Le path retourné inclut déjà cloud/v2, donc interrogez à https://apis.roblox.test1709.icu/{path} sans ajouter un autre préfixe.

Les magasins de mémoire de Studio et de production sont isolés. Vider une portée ne vide pas l'autre. Après avoir effacé les données non nécessaires, suivez les meilleures pratiques, telles que des temps d'expiration plus courts et une suppression explicite, pour éviter que l'utilisation de la mémoire n'atteigne à nouveau le quota.

Augmenter la capacité avec les services étendus

Si votre jeu doit conserver les données et utiliser plus de stockage que le quota par défaut ne le permet, activez les services étendus pour les magasins de mémoire. Les services étendus vous permettent de payer pour le stockage et les requêtes de magasin de mémoire au-delà des quotas par défaut.

Pour commencer, répondez aux exigences d'éligibilité, ajoutez des détails de compte et un mode de paiement, puis sélectionnez votre jeu dans le tableau de bord des créateurs. Sous Services étendus, activez les magasins de mémoire et définissez des budgets mensuels pour les ressources dont vous avez besoin. Consultez Activer un service et Tarification des services pour plus de détails.

Les services étendus limitent le service si l'utilisation dépasse votre budget. Surveillez l'utilisation et la facturation, et continuez à supprimer les données non nécessaires.

Meilleures pratiques

Pour garder votre modèle d'utilisation de la mémoire optimal et éviter d'atteindre les limites, suivez ces meilleures pratiques :

  • Supprimez les éléments traités. Nettoyer régulièrement les éléments lus en utilisant la méthode MemoryStoreQueue:RemoveAsync() pour les files d'attente et MemoryStoreSortedMap:RemoveAsync() pour les cartes triées peut libérer de la mémoire et garder la structure de données à jour.

  • Définissez le temps d'expiration sur le plus petit intervalle possible lors de l'ajout de données. Bien que le temps d'expiration par défaut soit de 45 jours pour MemoryStoreQueue:AddAsync() et MemoryStoreSortedMap:SetAsync(), définir le temps le plus court possible peut automatiquement nettoyer les anciennes données pour éviter qu'elles ne remplissent votre quota d'utilisation de mémoire.

    • Ne stockez pas une grande quantité de données avec une longue expiration, car cela risque de dépasser votre quota de mémoire et de potentiellement causer des problèmes qui peuvent casser votre jeu entier.
    • Supprimez toujours explicitement les éléments non nécessaires ou définissez une courte expiration pour les éléments.
    • En général, vous devriez utiliser la suppression explicite pour libérer de la mémoire et l'expiration des éléments comme un mécanisme de sécurité pour empêcher les éléments inutilisés d'occuper la mémoire pendant une période prolongée.
  • Ne gardez que les valeurs nécessaires en mémoire.

    Par exemple, pour un jeu de maison de vente aux enchères, vous n'avez besoin de maintenir que la plus haute enchère. Vous pouvez utiliser MemoryStoreSortedMap:UpdateAsync() sur une clé pour garder la plus haute enchère plutôt que de garder toutes les enchères dans votre structure de données.

  • Utilisez le retour exponentiel pour aider à rester en dessous des limites de requêtes API.

    Par exemple, si vous recevez un DataUpdateConflict, vous pourriez réessayer après deux secondes, puis quatre, huit, etc. plutôt que d'envoyer constamment des requêtes à MemoryStoreService pour obtenir la bonne réponse.

  • Divisez les grandes structures de données en plusieurs plus petites en shardant.

    Il est souvent plus facile de gérer des données dans des structures plus petites plutôt que de tout stocker dans une grande structure de données. Cette approche peut également aider à éviter les limites d'utilisation et de taux. Par exemple, si vous avez une carte triée qui utilise des préfixes pour ses clés, envisagez de séparer chaque préfixe dans sa propre carte triée. Pour un jeu particulièrement populaire, vous pourriez même séparer les utilisateurs en plusieurs cartes en fonction des derniers chiffres de leurs ID d'utilisateur.

  • Shard les clés fréquemment accédées dans les cartes de hachage avec plusieurs copies de la clé pour répartir la charge.

  • Compressez les valeurs stockées.

    Par exemple, envisagez d'utiliser l'algorithme LZW pour réduire la taille des valeurs stockées.

  • Inscrivez-vous aux services étendus.

    Pour un stockage ou une utilisation de requêtes au-delà des quotas par défaut, activez les services étendus pour les magasins de mémoire.

Observabilité

Le tableau de bord d'observabilité fournit des informations et des analyses pour surveiller et dépanner votre utilisation des magasins de mémoire. Avec des graphiques se mettant à jour en temps réel sur différents aspects de votre utilisation de la mémoire et des requêtes API, vous pouvez suivre le modèle d'utilisation de la mémoire de votre jeu, voir les quotas alloués actuels, surveiller l'état de l'API et identifier les problèmes potentiels pour l'optimisation des performances.

Le tableau suivant répertorie et décrit tous les codes d'état des réponses API disponibles sur les graphiques Nombre de requêtes par état et Requêtes par API x État du tableau de bord d'observabilité. Pour plus d'informations sur la façon de résoudre ces erreurs, consultez Dépannage. Pour le quota ou la limite spécifique à laquelle une erreur se rapporte, consultez Limites et Quotas.

Code d'étatDescription
SuccèsSuccès.
DataStructureMemoryOverLimitDépasse la limite de taille de mémoire au niveau de la structure de données (100 Mo).
DataUpdateConflictConflit dû à une mise à jour concurrente.
AccessDeniedNon autorisé à accéder aux données du jeu. Cette requête ne consomme pas d'unités de requête ni n'utilise de quota.
InternalErrorErreur interne.
InvalidRequestLa requête n'a pas les informations requises ou a des informations mal formées.
DataStructureItemsOverLimitDépasse la limite de nombre d'éléments au niveau de la structure de données (1M).
NoItemFoundAucun élément trouvé dans MemoryStoreQueue:ReadAsync() ou MemoryStoreSortedMap:UpdateAsync(). ReadAsync() interroge toutes les 2 secondes et renvoie ce code d'état jusqu'à ce qu'il trouve des éléments dans la file d'attente.
DataStructureRequestsOverLimitDépasse la limite d'unités de requête au niveau de la structure de données (100 000 unités de requête par minute).
PartitionRequestsOverLimitDépasse une limite d'unités de requête par partition ou par clé.
TotalRequestsOverLimitDépasse la limite d'unités de requête au niveau de l'univers.
TotalMemoryOverLimitDépasse le quota de mémoire au niveau de l'univers.
ItemValueSizeTooLargeLa taille de la valeur dépasse la limite (32 Ko).

Le tableau suivant répertorie les codes d'état du côté client, qui ne sont actuellement pas disponibles sur le tableau de bord d'observabilité.

Code d'étatDescription
InternalErrorErreur interne.
UnpublishedPlaceVous devez publier cet endroit pour utiliser MemoryStoreService.
InvalidClientAccessMemoryStoreService doit être appelé depuis le serveur.
InvalidExpirationTimeLe champ 'expiration' doit être compris entre 0 et 3 888 000.
InvalidRequestImpossible de convertir la valeur en json.
InvalidRequestImpossible de convertir sortKey en un nombre ou une chaîne valide.
TransformCallbackFailedÉchec de l'invocation de la fonction de rappel de transformation.
RequestThrottledLes requêtes récentes de MemoryStores ont atteint une ou plusieurs limites.
UpdateConflictDépassement du nombre maximum de tentatives.

Dépannage

Le tableau suivant répertorie et décrit la solution recommandée pour chaque code d'état de réponse :

ErreurOptions de dépannage
DataStructureRequestsOverLimit / PartitionRequestsOverLimit
  • Ajoutez un cache local en enregistrant des informations dans une autre variable et en vérifiant à nouveau après un certain intervalle de temps, comme 30 secondes.
  • Utilisez le graphique Nombre de requêtes par état pour vérifier que vous recevez plus de réponses Succès que de Aucun élément trouvé. Limitez le nombre de fois où vous atteignez MemoryStoreService avec une requête échouée.
  • Implémentez un court délai entre les requêtes.
  • Suivez les meilleures pratiques, y compris :
    • Shard vos structures de données si vous recevez un nombre significatif de réponses DataStructureRequestsOverLimit/PartitionRequestsOverLimit.
    • Shard vos clés de carte de hachage si vous recevez un nombre significatif de réponses PartitionRequestsOverLimit sur les appels de carte de hachage.
    • Réduisez ou regroupez les appels à des structures de données spécifiques ou des clés de carte de hachage si vous voyez des réponses PartitionRequestsOverLimit.
    • Implémentez un retour exponentiel pour trouver un taux raisonnable de requêtes à envoyer.
TotalRequestsOverLimit
DataStructureItemsOverLimit
DataStructureMemoryOverLimit
TotalMemoryOverLimit
DataUpdateConflict
  • Implémentez un court délai entre les requêtes pour éviter que plusieurs requêtes ne mettent à jour la même clé en même temps.
  • Pour les cartes triées, utilisez la fonction de rappel sur la méthode MemoryStoreSortedMap:UpdateAsync() pour annuler une requête après un certain nombre de tentatives, comme le montre l'exemple de code suivant :
  • Exemple d'annulation de requête
    local MemoryStoreService = game:GetService("MemoryStoreService")
    local map = MemoryStoreService:GetSortedMap("AuctionItems")
    function placeBid(itemKey, bidAmount)
    map:UpdateAsync(itemKey, function(item)
    item = item or { highestBid = 0 }
    if item.highestBid < bidAmount then
    item.highestBid = bidAmount
    return item
    end
    print("l'élément est "..item.highestBid)
    return nil
    end, 1000)
    end
    placeBid("MyItem", 50)
    placeBid("MyItem", 40)
    print("terminé")
  • Enquêtez pour voir si vous appelez MemoryStoreService de manière efficace pour éviter les conflits. Idéalement, vous ne devriez pas envoyer trop de requêtes.
  • Supprimez systématiquement les éléments une fois qu'ils sont lus en utilisant la méthode MemoryStoreQueue:RemoveAsync() pour les files d'attente et MemoryStoreSortedMap:RemoveAsync() pour les cartes triées.
Erreur interne
InvalidRequest
  • Assurez-vous d'inclure des paramètres corrects et valides dans votre requête. Des exemples de paramètres invalides incluent :
    • Une chaîne vide
    • Une chaîne qui dépasse la limite de longueur
ItemValueSizeTooLarge
  • Shard ou divisez la valeur de l'élément en plusieurs clés.
    • Pour organiser les clés groupées, triez-les par ordre alphabétique en ajoutant un préfixe à la clé.
  • Encodage ou compression des valeurs stockées.

Tester et déboguer dans Studio

Les données dans MemoryStoreService sont isolées entre Studio et production, donc changer les données dans Studio n'affecte pas le comportement de production. Cela signifie que vos appels API depuis Studio n'accèdent pas aux données de production, vous permettant de tester en toute sécurité les magasins de mémoire et les nouvelles fonctionnalités avant de passer à la production.

Les tests en Studio ont les mêmes limites et quotas que la production. Pour les quotas calculés en fonction du nombre d'utilisateurs, le quota résultant peut être très faible puisque vous êtes le seul utilisateur pour les tests en Studio. Lorsque vous testez depuis Studio, vous pourriez également remarquer une latence légèrement plus élevée et des taux d'erreur accrus par rapport à l'utilisation en production en raison de certaines vérifications supplémentaires effectuées pour vérifier l'accès et les autorisations.

Pour des informations sur la façon de déboguer un magasin de mémoire sur des jeux en direct ou lors de tests dans Studio, utilisez la Console de développement.

©2026 Société Roblox. Roblox, le logo Roblox et Powering Imagination font partie de nos marques déposées aux États-Unis et dans d'autres pays.