DéveloppeurWeb.Com
    DéveloppeurWeb.Com
    • Agile Zone
    • AI Zone
    • Cloud Zone
    • Database Zone
    • DevOps Zone
    • Integration Zone
    • Web Dev Zone
    DéveloppeurWeb.Com
    Home»Uncategorized»Cosmos DB en tant que magasin d’objets clés
    Uncategorized

    Cosmos DB en tant que magasin d’objets clés

    février 5, 2023
    Cosmos DB en tant que magasin d'objets clés
    Share
    Facebook Twitter Pinterest Reddit WhatsApp Email

    Cosmos DB peut être un bon candidat pour un magasin clé-valeur. Cosmos DB est une base de données multimodale dans Azure qui prend en charge le stockage sans schéma. Par défaut, les conteneurs Cosmos DB ont tendance à indexer tous les champs d’un document téléchargé. Nous pouvons limiter les propriétés d’index uniquement à id et partitionkey pour faire du conteneur un pur magasin clé-valeur. L’interdiction d’indexer d’autres champs augmente les performances et réduit les RU pour interroger les enregistrements de points. (Le coût de Cosmos DB est mesuré en RU.) Pour le stockage d’objets clés, le RU a tendance à être inférieur, mais cela dépend toujours de la taille de la charge utile. Les tests de performances effectués sur 100 partitions et 100 000 enregistrements ont donné un P95 entre 25 et 30 ms en lecture et en écriture.

    Plongeons-nous et implémentons Cosmos DB en tant que magasin clé-valeur pur en C#.

    Conditions préalables:

    1. Avoir un compte dans le portail Azure
    2. Provisionnez Cosmos DB avec un compte SQL.

    Il existe plusieurs façons de connecter le cache à une application .NET. Définissons une interface générique de cache distribué avec quelques extensions.

    interface IDistributedObjectCache
        {
            Task<bool> SetObjectAsync<T>(string key, T value, CancellationToken cancellationToken = default);
            Task<bool> SetObjectAsync<T>(string key, string pk1, T value, CancellationToken cancellationToken = default);
    
            Task<T> GetObjectAsync<T>(string key, CancellationToken cancellationToken = default);
            Task<T> GetObjectAsync<T>(string key, string pk1, CancellationToken cancellationToken = default);
        }

    Par rapport à IDistributedCache du framework .NET, IDistributedObjectCache donne l’extensibilité d’ajouter une clé de partition selon les besoins de l’application.

    Prédéfinissons tous les paramètres de connexion nécessaires à la connexion CosmosClient

    public class DbConstants
        {
            public const string ConnectionString = "<CosmosDb connection string>";
    
            public const string CacheDatabaseId = "ObjectCacheDb";
    
            public const string CacheContainerId = "CacheContainer";
        }

    Définissons un CosmosClientManager qui nous aide à gérer l’objet de connexion CosmosClient. Vous pouvez modifier ApplicationRegion à l’emplacement souhaité.

    public class CosmosClientManager : IDisposable
        {
            public CosmosClientManager()
            {
                if (!string.IsNullOrWhiteSpace(DbConstants.ConnectionString))
                {
                    CosmosClient = new CosmosClient(DbConstants.ConnectionString, new CosmosClientOptions
                    {
                        ConnectionMode = ConnectionMode.Direct,
                        IdleTcpConnectionTimeout = TimeSpan.FromMinutes(30),
                        ApplicationRegion = Regions.WestUS2,
                    });
                }
            }
    
            public CosmosClient? CosmosClient { get; } = null;
    
            public void Dispose()
            {
                CosmosClient?.Dispose();
            }
        }

    Définissons un modèle d’objet sur la façon dont les enregistrements dans un conteneur de cache ressembleront

    public class ObjectContainer<TPayload>
        {
            [Required]
            [JsonProperty("id")]
            public string PrimaryKey { get; set; }
    
            [Required]
            public string PartitionKey { get; set; }
    
            public TPayload Payload { get; set; }
    
            [Required]
            public string ContainerId => DbConstants.CacheContainerId;
    
            public string PartitionKeyPath => $"/{nameof(PartitionKey)}";
    
            [JsonProperty("_etag")]
            public string ETag { get; }
    
            [JsonProperty("_ts")]
            public long DateTimestamp { get; set; }
        }

    J’ai créé un simple IWarmup pour initialiser les composants dans un thread d’arrière-plan.

    internal interface IWarmUp
        {
            Task<bool> WarmUpAsync();
        }

    Définissons le noyau CosmosDistributedObjectStore qui implémente toutes les interfaces nécessaires.

    public class CosmosDistributedObjectStore : IDistributedObjectCache, IWarmUp
        {
            private readonly CosmosClientManager cosmosClientManager;
    
            public CosmosDistributedObjectStore(
                CosmosClientManager cosmosClientManager
                )
            {
                this.cosmosClientManager = cosmosClientManager;
            }
    
            public Task<T> GetObjectAsync<T>(string key, CancellationToken cancellationToken = default)
            {
                cancellationToken.ThrowIfCancellationRequested();
    
                return GetObjectAsync<T>(key, key, cancellationToken);
            }
    
            public async Task<T> GetObjectAsync<T>(string key, string pk1, CancellationToken cancellationToken = default)
            {
                cancellationToken.ThrowIfCancellationRequested();
    
                var container = GetCurrentContainer();
    
                if (container == null) return default;
    
                var record = await container.ReadItemAsync<ObjectContainer<T>>(key, new PartitionKey(pk1), cancellationToken: cancellationToken);
    
                return record != null ? record.Resource.Payload : default;
            }
    
            public Task<bool> SetObjectAsync<T>(string key, T value, CancellationToken cancellationToken = default)
            {
                cancellationToken.ThrowIfCancellationRequested();
    
                return SetObjectAsync<T>(key, key, value, cancellationToken);
    
            }
    
            public async Task<bool> SetObjectAsync<T>(string key, string pk1, T value, CancellationToken cancellationToken = default)
            {
                cancellationToken.ThrowIfCancellationRequested();
    
                var container = GetCurrentContainer();
    
                if (container == null) return false;
    
                var record = new ObjectContainer<T>
                {
                    PartitionKey = key,
                    PrimaryKey = key,
                    Payload = value,
                };
    
                await container.CreateItemAsync(record);
    
                return true;
    
            }
    
            public async Task<bool> WarmUpAsync()
            {
                var entry = new ObjectContainer<dynamic>();
                var containerProperties = new ContainerProperties(entry.ContainerId, entry.PartitionKeyPath);
    
                // optimize container as a pure keyvalue store. Disable indexding other than id column
                containerProperties.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath() { Path = "/*" });
    
                var db = await cosmosClientManager.CosmosClient?.CreateDatabaseIfNotExistsAsync(DbConstants.CacheDatabaseId, 1000);
                var container = await db?.Database?.CreateContainerIfNotExistsAsync(containerProperties, 1000);
    
                return true;
            }
    
            private Container? GetCurrentContainer()
            {
                return cosmosClientManager?.CosmosClient?.GetContainer(DbConstants.CacheDatabaseId, DbConstants.CacheContainerId);
            }
        }

    Je voudrais mettre l’accent sur WarmUpAsync() et sur la manière d’affiner la création de conteneurs sur les champs d’ID d’index et de primaryKey uniquement afin que le conteneur fonctionne comme un pur magasin d’objets clés.

                containerProperties.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath() { Path = "/*" }); 

    Écrivons un appelant simple pour tester notre nouveau magasin d’objets clés.

    static async Task Main(string[] args)
        {
            var cosmosDistObjectStore = new CosmosDistributedObjectStore(new CosmosClientManager());
    
    
            IWarmUp components = cosmosDistObjectStore;
            IDistributedObjectCache objectCache = cosmosDistObjectStore;
    
            await components.WarmUpAsync();
    
            var studentKey = "alpha";
            var studentObject = new { Name = "alpha", Age = 10, Class = "Grade-V" };
    
            // set cache
            await objectCache.SetObjectAsync(studentKey, studentObject);
    
            // get student grade details
            var alphaDetails = await objectCache.GetObjectAsync<dynamic>(studentKey, studentObject.Class);
    
            // get all cache
            var alpha = await objectCache.GetObjectAsync<dynamic>(studentKey);
        }

    Nous disposons désormais d’un magasin d’objets de clé NoSQL alternatif robuste avec Azure Cosmos DB qui peut partitionner et évoluer à la demande.

    Share. Facebook Twitter Pinterest LinkedIn WhatsApp Reddit Email
    Add A Comment

    Leave A Reply Cancel Reply

    Catégories

    • Politique de cookies
    • Politique de confidentialité
    • CONTACT
    • Politique du DMCA
    • CONDITIONS D’UTILISATION
    • Avertissement
    © 2023 DéveloppeurWeb.Com.

    Type above and press Enter to search. Press Esc to cancel.