Mise en cache distribuée dans ASP.NET Core

Par Mohsin Nasir et smandia

Remarque

Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 8 de cet article.

Important

Ces informations portent sur la préversion du produit, qui est susceptible d’être en grande partie modifié avant sa commercialisation. Microsoft n’offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.

Pour la version actuelle, consultez la version .NET 8 de cet article.

Un cache distribué est un cache partagé par plusieurs serveurs d’applications, généralement géré en tant que service externe pour les serveurs d’applications qui y accèdent. Un cache distribué peut améliorer les performances et la scalabilité d’une application ASP.NET Core, en particulier lorsque l’application est hébergée par un service cloud ou une batterie de serveurs.

Le cache distribué présente plusieurs avantages par rapport à d’autres scénarios de mise en cache où les données mises en cache sont stockées sur des serveurs d’applications individuels.

Lorsque les données mises en cache sont distribuées, les données :

  • sont cohérentes entre les demandes adressées à plusieurs serveurs.
  • survivent aux redémarrages du serveur et aux déploiements d’applications.
  • n’utilisent pas la mémoire locale.

La configuration du cache distribué est spécifique à l’implémentation. Cet article explique comment configurer des caches distribués SQL Server et Redis. Des implémentations tierces sont également disponibles, telles que NCache (NCache sur GitHub). Quelle que soit l’implémentation sélectionnée, l’application interagit avec le cache à l’aide de l’interface IDistributedCache.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)

Prérequis

Ajoutez une référence de package pour le fournisseur de cache distribué utilisé :

Interface IDistributedCache

L’interface IDistributedCache fournit les méthodes suivantes pour manipuler des éléments dans l’implémentation du cache distribué :

  • Get, GetAsync : accepte une clé de chaîne et récupère un élément mis en cache sous forme de tableau byte[] s’il est trouvé dans le cache.
  • Set, SetAsync : ajoute un élément (sous forme de tableau byte[]) au cache à l’aide d’une clé de chaîne.
  • Refresh, RefreshAsync : actualise un item du cache en fonction de sa clé, en réinitialisant son délai d’expiration décalé (si celui-ci a été défini).
  • Remove, RemoveAsync : supprime un élément de cache en fonction de sa clé de chaîne.

Établir des services de mise en cache distribuée

Inscrivez une implémentation de IDistributedCache dans Program.cs. Les implémentations fournies par l’infrastructure décrites dans cette rubrique sont les suivantes :

Cache Redis distribué

Nous recommandons aux applications de production d’utiliser le cache Redis distribué, car il est le plus performant. Pour plus d’informations, consultez Recommandations.

Redis est un magasin de données open source en mémoire, qui est souvent utilisé comme cache distribué. Vous pouvez configurer un Cache Azure pour Redis pour une application ASP.NET Core hébergée par Azure et utiliser Azure Cache pour Redis pour le développement local.

Une application configure l’implémentation du cache à l’aide d’une instance de RedisCache, en appelant AddStackExchangeRedisCache. Pour mise en cache de sortie, utilisez AddStackExchangeRedisOutputCache.

  1. Créer une instance d’Azure Cache pour Redis.
  2. Copiez la chaîne de connexion principale (StackExchange.Redis) dans Configuration.
    • Développement local : enregistrez la chaîne de connexion avec le Gestionnaire de secrets.
    • Azure : enregistrez la chaîne de connexion dans la configuration App Service ou dans un autre magasin sécurisé.

Le code suivant active Azure Cache pour Redis :

builder.Services.AddStackExchangeRedisCache(options =>
 {
     options.Configuration = builder.Configuration.GetConnectionString("MyRedisConStr");
     options.InstanceName = "SampleInstance";
 });

Le code précédent suppose que la chaîne de connexion principale (StackExchange.Redis) a été enregistrée dans la configuration avec le nom de clé MyRedisConStr.

Pour plus d’informations, consultez Azure Cache pour Redis.

Consultez ce problème GitHub pour une discussion sur les approches alternatives à un cache Redis local.

Cache de mémoire distribuée

Le cache de mémoire distribuée (AddDistributedMemoryCache) est une implémentation fournie par l’infrastructure de IDistributedCache qui stocke les éléments en mémoire. Le cache de mémoire distribuée n’est pas un véritable cache distribué. Les éléments mis en cache sont stockés par l’instance d’application sur le serveur sur lequel l’application s’exécute.

Le cache de mémoire distribuée est une implémentation utile :

  • Dans les scénarios de développement et de test.
  • Lorsqu’un serveur unique est utilisé en production et que la consommation de mémoire n’est pas un problème. L’implémentation du cache de mémoire distribuée extrait le stockage des données mises en cache. Elle permet d’implémenter une véritable solution de mise en cache distribuée à l’avenir si plusieurs nœuds ou une tolérance de panne deviennent nécessaires.

L’exemple d’application utilise le cache de mémoire distribuée quand l’application est exécutée dans l’environnement de développement dans Program.cs :

builder.Services.AddDistributedMemoryCache();

Cache SQL Server distribué

L’implémentation du cache SQL Server distribué (AddDistributedSqlServerCache) permet au cache distribué d’utiliser une base de données SQL Server comme magasin de stockage. Pour créer une table d’éléments mis en cache SQL Server dans un SQL Server instance, vous pouvez utiliser l’outil sql-cache. L’outil crée une table avec le nom et le schéma que vous spécifiez.

Créez une table dans SQL Server en exécutant la commande sql-cache create. Fournissez le SQL Server instance (Data Source), la base de données (Initial Catalog), le schéma (par exemple, dbo) et le nom de la table (par exemple, TestCache) :

dotnet sql-cache create "Data Source=(localdb)/MSSQLLocalDB;Initial Catalog=DistCache;Integrated Security=True;" dbo TestCache

Un message est enregistré pour indiquer que l’outil a réussi :

Table and index were created successfully.

La table créée par l’outil sql-cache a le schéma suivant :

SqlServer Cache Table

Remarque

Une application doit manipuler les valeurs de cache à l’aide d’un instance de IDistributedCache, et non d’un SqlServerCache.

L’exemple d’application implémente SqlServerCache dans un environnement non-développement dans Program.cs :

builder.Services.AddDistributedSqlServerCache(options =>
{
    options.ConnectionString = builder.Configuration.GetConnectionString(
        "DistCache_ConnectionString");
    options.SchemaName = "dbo";
    options.TableName = "TestCache";
});

Remarque

Un ConnectionString (et éventuellement, SchemaName et TableName) sont généralement stockés en dehors du contrôle de code source (par exemple, stockés par le Gestionnaire de secrets ou dans des appsettings.json/appsettings.{Environment}.json fichiers). La chaîne de connexion peut contenir des informations d’identification qui doivent être conservées en dehors des systèmes de contrôle de code source.

Cache NCache distribué

NCache est un cache distribué open source en mémoire développé en mode natif dans .NET et .NET Core. NCache fonctionne à la fois localement et configuré en tant que cluster de cache distribué pour une application ASP.NET Core s’exécutant dans Azure ou sur d’autres plateformes d’hébergement.

Pour installer et configurer NCache sur votre ordinateur local, consultez Prise en main Guide pour Windows (.NET et .NET Core).

Pour configurer NCache :

  1. Installez NCache open source NuGet.
  2. Configurez le cluster de cache dans client.ncconf.
  3. Ajoutez le code suivant à Program.cs :
builder.Services.AddNCacheDistributedCache(configuration =>
{
    configuration.CacheName = "democache";
    configuration.EnableLogs = true;
    configuration.ExceptionsEnabled = true;
});

Cache distribué Azure CosmosDB

Azure Cosmos DB peut être utilisé dans ASP.NET Core comme fournisseur d’état de session à l’aide de l’interface IDistributedCache. Azure Cosmos DB est une base de données NoSQL, entièrement managée et relationnelle pour le développement d’applications modernes, qui offre une haute disponibilité, une scalabilité et un accès à faible latence aux données pour les applications stratégiques.

Après avoir installé le package NuGet Microsoft.Extensions.Caching.Cosmos, configurez un cache distribué Azure Cosmos DB comme suit :

Réutiliser un client existant

Le plus simple moyen de configurer le cache distribué consiste à réutiliser un client Azure Cosmos DB existant. Dans ce cas, l’instance CosmosClient ne va pas être supprimée lorsque le fournisseur est supprimé.

services.AddCosmosCache((CosmosCacheOptions cacheOptions) =>
{
    cacheOptions.ContainerName = Configuration["CosmosCacheContainer"];
    cacheOptions.DatabaseName = Configuration["CosmosCacheDatabase"];
    cacheOptions.CosmosClient = existingCosmosClient;
    cacheOptions.CreateIfNotExists = true;
});

Créer un client

Vous pouvez également instancier un nouveau client. Dans ce cas, l’instance CosmosClient va être supprimée lorsque le fournisseur est supprimé.

services.AddCosmosCache((CosmosCacheOptions cacheOptions) =>
{
    cacheOptions.ContainerName = Configuration["CosmosCacheContainer"];
    cacheOptions.DatabaseName = Configuration["CosmosCacheDatabase"];
    cacheOptions.ClientBuilder = new CosmosClientBuilder(Configuration["CosmosConnectionString"]);
    cacheOptions.CreateIfNotExists = true;
});

Utiliser le cache distribué

Pour utiliser l’interfaceIDistributedCache, demandez un instance de IDistributedCache dans l’application. L’instance est fournie par l’injection de dépendances (DI).

Lorsque l’exemple d’application démarre, IDistributedCache est injecté dans Program.cs. L’heure actuelle est mise en cache à l’aide de IHostApplicationLifetime (pour plus d’informations, consultez Hôte générique : IHostApplicationLifetime) :

app.Lifetime.ApplicationStarted.Register(() =>
{
    var currentTimeUTC = DateTime.UtcNow.ToString();
    byte[] encodedCurrentTimeUTC = System.Text.Encoding.UTF8.GetBytes(currentTimeUTC);
    var options = new DistributedCacheEntryOptions()
        .SetSlidingExpiration(TimeSpan.FromSeconds(20));
    app.Services.GetService<IDistributedCache>()
                              .Set("cachedTimeUTC", encodedCurrentTimeUTC, options);
});

L’exemple d’application injecte IDistributedCache dans le IndexModel pour une utilisation par la page Index.

Chaque fois que la page Index est chargée, le cache est vérifié pour l’heure mise en cache dans OnGetAsync. Si l’heure mise en cache n’a pas expiré, l’heure s’affiche. Si 20 secondes se sont écoulées depuis le dernier accès à l’heure mise en cache (la dernière fois que cette page a été chargée), la page affiche l’heure mise en cache expirée.

Mettez immédiatement à jour l’heure mise en cache à l’heure actuelle en sélectionnant le bouton Réinitialiser l’heure mise en cache. Le bouton déclenche la méthode de gestionnaire OnPostResetCachedTime.

public class IndexModel : PageModel
{
    private readonly IDistributedCache _cache;

    public IndexModel(IDistributedCache cache)
    {
        _cache = cache;
    }

    public string? CachedTimeUTC { get; set; }
    public string? ASP_Environment { get; set; }

    public async Task OnGetAsync()
    {
        CachedTimeUTC = "Cached Time Expired";
        var encodedCachedTimeUTC = await _cache.GetAsync("cachedTimeUTC");

        if (encodedCachedTimeUTC != null)
        {
            CachedTimeUTC = Encoding.UTF8.GetString(encodedCachedTimeUTC);
        }

        ASP_Environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
        if (String.IsNullOrEmpty(ASP_Environment))
        {
            ASP_Environment = "Null, so Production";
        }
    }

    public async Task<IActionResult> OnPostResetCachedTime()
    {
        var currentTimeUTC = DateTime.UtcNow.ToString();
        byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC);
        var options = new DistributedCacheEntryOptions()
            .SetSlidingExpiration(TimeSpan.FromSeconds(20));
        await _cache.SetAsync("cachedTimeUTC", encodedCurrentTimeUTC, options);

        return RedirectToPage();
    }
}

Il n’est pas nécessaire d’utiliser un singleton ou une durée de vie étendue pour les instances IDistributedCache avec les implémentations intégrées.

Vous pouvez également créer une instance IDistributedCache partout où vous en avez besoin au lieu d’utiliser l’injonction de dépendances, mais la création d’une instance dans le code peut rendre votre code plus difficile à tester et violer le principe des dépendances explicites.

Recommandations

Lorsque vous décidez quelle implémentation de IDistributedCache est la mieux adaptée à votre application, tenez compte des points suivants :

  • Infrastructure existante
  • Exigences en matière de performances
  • Coût
  • Expérience d’équipe

Les solutions de mise en cache s’appuient généralement sur le stockage en mémoire pour fournir une récupération rapide des données mises en cache, mais la mémoire est une ressource limitée et coûteuse à développer. Stockez uniquement les données couramment utilisées dans un cache.

Pour la plupart des applications, un cache Redis offre un débit plus élevé et une latence inférieure à celle d’un cache SQL Server. Toutefois, l’évaluation est recommandée pour déterminer les caractéristiques de performances des stratégies de mise en cache.

Lorsque SQL Server est utilisé comme magasin de stockage de cache distribué, l’utilisation de la même base de données pour le cache et le stockage et la récupération des données ordinaires de l’application peuvent avoir un impact négatif sur les performances de ces deux éléments. Nous vous recommandons d’utiliser un SQL Server instance dédié pour le magasin de stockage du cache distribué.

Ressources supplémentaires

Un cache distribué est un cache partagé par plusieurs serveurs d’applications, généralement géré en tant que service externe pour les serveurs d’applications qui y accèdent. Un cache distribué peut améliorer les performances et la scalabilité d’une application ASP.NET Core, en particulier lorsque l’application est hébergée par un service cloud ou une batterie de serveurs.

Le cache distribué présente plusieurs avantages par rapport à d’autres scénarios de mise en cache où les données mises en cache sont stockées sur des serveurs d’applications individuels.

Lorsque les données mises en cache sont distribuées, les données :

  • sont cohérentes entre les demandes adressées à plusieurs serveurs.
  • survivent aux redémarrages du serveur et aux déploiements d’applications.
  • n’utilisent pas la mémoire locale.

La configuration du cache distribué est spécifique à l’implémentation. Cet article explique comment configurer des caches distribués SQL Server et Redis. Des implémentations tierces sont également disponibles, telles que NCache (NCache sur GitHub). Quelle que soit l’implémentation sélectionnée, l’application interagit avec le cache à l’aide de l’interface IDistributedCache.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)

Prérequis

Ajoutez une référence de package pour le fournisseur de cache distribué utilisé :

Interface IDistributedCache

L’interface IDistributedCache fournit les méthodes suivantes pour manipuler des éléments dans l’implémentation du cache distribué :

  • Get, GetAsync : accepte une clé de chaîne et récupère un élément mis en cache sous forme de tableau byte[] s’il est trouvé dans le cache.
  • Set, SetAsync : ajoute un élément (sous forme de tableau byte[]) au cache à l’aide d’une clé de chaîne.
  • Refresh, RefreshAsync : actualise un item du cache en fonction de sa clé, en réinitialisant son délai d’expiration décalé (si celui-ci a été défini).
  • Remove, RemoveAsync : supprime un élément de cache en fonction de sa clé de chaîne.

Établir des services de mise en cache distribuée

Inscrivez une implémentation de IDistributedCache dans Program.cs. Les implémentations fournies par l’infrastructure décrites dans cette rubrique sont les suivantes :

Cache Redis distribué

Nous recommandons aux applications de production d’utiliser le cache Redis distribué, car il est le plus performant. Pour plus d’informations, consultez Recommandations.

Redis est un magasin de données open source en mémoire, qui est souvent utilisé comme cache distribué. Vous pouvez configurer un cache Redis Azure pour une application ASP.NET Core hébergée par Azure et utiliser un cache Redis Azure pour le développement local.

Une application configure l’implémentation du cache à l’aide d’une instance RedisCache (AddStackExchangeRedisCache).

  1. Créer une instance d’Azure Cache pour Redis.
  2. Copiez la chaîne de connexion principale (StackExchange.Redis) dans Configuration.
    • Développement local : enregistrez la chaîne de connexion avec le Gestionnaire de secrets.
    • Azure : enregistrez la chaîne de connexion dans la configuration App Service ou dans un autre magasin sécurisé.

Le code suivant active Azure Cache pour Redis :

builder.Services.AddStackExchangeRedisCache(options =>
 {
     options.Configuration = builder.Configuration.GetConnectionString("MyRedisConStr");
     options.InstanceName = "SampleInstance";
 });

Le code précédent suppose que la chaîne de connexion principale (StackExchange.Redis) a été enregistrée dans la configuration avec le nom de clé MyRedisConStr.

Pour plus d’informations, consultez Azure Cache pour Redis.

Consultez ce problème GitHub pour une discussion sur les approches alternatives à un cache Redis local.

Cache de mémoire distribuée

Le cache de mémoire distribuée (AddDistributedMemoryCache) est une implémentation fournie par l’infrastructure de IDistributedCache qui stocke les éléments en mémoire. Le cache de mémoire distribuée n’est pas un véritable cache distribué. Les éléments mis en cache sont stockés par l’instance d’application sur le serveur sur lequel l’application s’exécute.

Le cache de mémoire distribuée est une implémentation utile :

  • Dans les scénarios de développement et de test.
  • Lorsqu’un serveur unique est utilisé en production et que la consommation de mémoire n’est pas un problème. L’implémentation du cache de mémoire distribuée extrait le stockage des données mises en cache. Elle permet d’implémenter une véritable solution de mise en cache distribuée à l’avenir si plusieurs nœuds ou une tolérance de panne deviennent nécessaires.

L’exemple d’application utilise le cache de mémoire distribuée quand l’application est exécutée dans l’environnement de développement dans Program.cs :

builder.Services.AddDistributedMemoryCache();

Cache SQL Server distribué

L’implémentation du cache SQL Server distribué (AddDistributedSqlServerCache) permet au cache distribué d’utiliser une base de données SQL Server comme magasin de stockage. Pour créer une table d’éléments mis en cache SQL Server dans un SQL Server instance, vous pouvez utiliser l’outil sql-cache. L’outil crée une table avec le nom et le schéma que vous spécifiez.

Créez une table dans SQL Server en exécutant la commande sql-cache create. Fournissez le SQL Server instance (Data Source), la base de données (Initial Catalog), le schéma (par exemple, dbo) et le nom de la table (par exemple, TestCache) :

dotnet sql-cache create "Data Source=(localdb)/MSSQLLocalDB;Initial Catalog=DistCache;Integrated Security=True;" dbo TestCache

Un message est enregistré pour indiquer que l’outil a réussi :

Table and index were created successfully.

La table créée par l’outil sql-cache a le schéma suivant :

SqlServer Cache Table

Remarque

Une application doit manipuler les valeurs de cache à l’aide d’un instance de IDistributedCache, et non d’un SqlServerCache.

L’exemple d’application implémente SqlServerCache dans un environnement non-développement dans Program.cs :

builder.Services.AddDistributedSqlServerCache(options =>
{
    options.ConnectionString = builder.Configuration.GetConnectionString(
        "DistCache_ConnectionString");
    options.SchemaName = "dbo";
    options.TableName = "TestCache";
});

Remarque

Un ConnectionString (et éventuellement, SchemaName et TableName) sont généralement stockés en dehors du contrôle de code source (par exemple, stockés par le Gestionnaire de secrets ou dans des appsettings.json/appsettings.{Environment}.json fichiers). La chaîne de connexion peut contenir des informations d’identification qui doivent être conservées en dehors des systèmes de contrôle de code source.

Cache NCache distribué

NCache est un cache distribué open source en mémoire développé en mode natif dans .NET et .NET Core. NCache fonctionne à la fois localement et configuré en tant que cluster de cache distribué pour une application ASP.NET Core s’exécutant dans Azure ou sur d’autres plateformes d’hébergement.

Pour installer et configurer NCache sur votre ordinateur local, consultez Prise en main Guide pour Windows (.NET et .NET Core).

Pour configurer NCache :

  1. Installez NCache open source NuGet.
  2. Configurez le cluster de cache dans client.ncconf.
  3. Ajoutez le code suivant à Program.cs :
builder.Services.AddNCacheDistributedCache(configuration =>
{
    configuration.CacheName = "democache";
    configuration.EnableLogs = true;
    configuration.ExceptionsEnabled = true;
});

Utiliser le cache distribué

Pour utiliser l’interfaceIDistributedCache, demandez un instance de IDistributedCache dans l’application. L’instance est fournie par l’injection de dépendances (DI).

Lorsque l’exemple d’application démarre, IDistributedCache est injecté dans Program.cs. L’heure actuelle est mise en cache à l’aide de IHostApplicationLifetime (pour plus d’informations, consultez Hôte générique : IHostApplicationLifetime) :

app.Lifetime.ApplicationStarted.Register(() =>
{
    var currentTimeUTC = DateTime.UtcNow.ToString();
    byte[] encodedCurrentTimeUTC = System.Text.Encoding.UTF8.GetBytes(currentTimeUTC);
    var options = new DistributedCacheEntryOptions()
        .SetSlidingExpiration(TimeSpan.FromSeconds(20));
    app.Services.GetService<IDistributedCache>()
                              .Set("cachedTimeUTC", encodedCurrentTimeUTC, options);
});

L’exemple d’application injecte IDistributedCache dans le IndexModel pour une utilisation par la page Index.

Chaque fois que la page Index est chargée, le cache est vérifié pour l’heure mise en cache dans OnGetAsync. Si l’heure mise en cache n’a pas expiré, l’heure s’affiche. Si 20 secondes se sont écoulées depuis le dernier accès à l’heure mise en cache (la dernière fois que cette page a été chargée), la page affiche l’heure mise en cache expirée.

Mettez immédiatement à jour l’heure mise en cache à l’heure actuelle en sélectionnant le bouton Réinitialiser l’heure mise en cache. Le bouton déclenche la méthode de gestionnaire OnPostResetCachedTime.

public class IndexModel : PageModel
{
    private readonly IDistributedCache _cache;

    public IndexModel(IDistributedCache cache)
    {
        _cache = cache;
    }

    public string? CachedTimeUTC { get; set; }
    public string? ASP_Environment { get; set; }

    public async Task OnGetAsync()
    {
        CachedTimeUTC = "Cached Time Expired";
        var encodedCachedTimeUTC = await _cache.GetAsync("cachedTimeUTC");

        if (encodedCachedTimeUTC != null)
        {
            CachedTimeUTC = Encoding.UTF8.GetString(encodedCachedTimeUTC);
        }

        ASP_Environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
        if (String.IsNullOrEmpty(ASP_Environment))
        {
            ASP_Environment = "Null, so Production";
        }
    }

    public async Task<IActionResult> OnPostResetCachedTime()
    {
        var currentTimeUTC = DateTime.UtcNow.ToString();
        byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC);
        var options = new DistributedCacheEntryOptions()
            .SetSlidingExpiration(TimeSpan.FromSeconds(20));
        await _cache.SetAsync("cachedTimeUTC", encodedCurrentTimeUTC, options);

        return RedirectToPage();
    }
}

Il n’est pas nécessaire d’utiliser un singleton ou une durée de vie étendue pour les instances IDistributedCache avec les implémentations intégrées.

Vous pouvez également créer une instance IDistributedCache partout où vous en avez besoin au lieu d’utiliser l’injonction de dépendances, mais la création d’une instance dans le code peut rendre votre code plus difficile à tester et violer le principe des dépendances explicites.

Recommandations

Lorsque vous décidez quelle implémentation de IDistributedCache est la mieux adaptée à votre application, tenez compte des points suivants :

  • Infrastructure existante
  • Exigences en matière de performances
  • Coût
  • Expérience d’équipe

Les solutions de mise en cache s’appuient généralement sur le stockage en mémoire pour fournir une récupération rapide des données mises en cache, mais la mémoire est une ressource limitée et coûteuse à développer. Stockez uniquement les données couramment utilisées dans un cache.

Pour la plupart des applications, un cache Redis offre un débit plus élevé et une latence inférieure à celle d’un cache SQL Server. Toutefois, l’évaluation est recommandée pour déterminer les caractéristiques de performances des stratégies de mise en cache.

Lorsque SQL Server est utilisé comme magasin de stockage de cache distribué, l’utilisation de la même base de données pour le cache et le stockage et la récupération des données ordinaires de l’application peuvent avoir un impact négatif sur les performances de ces deux éléments. Nous vous recommandons d’utiliser un SQL Server instance dédié pour le magasin de stockage du cache distribué.

Ressources supplémentaires

Un cache distribué est un cache partagé par plusieurs serveurs d’applications, généralement géré en tant que service externe pour les serveurs d’applications qui y accèdent. Un cache distribué peut améliorer les performances et la scalabilité d’une application ASP.NET Core, en particulier lorsque l’application est hébergée par un service cloud ou une batterie de serveurs.

Le cache distribué présente plusieurs avantages par rapport à d’autres scénarios de mise en cache où les données mises en cache sont stockées sur des serveurs d’applications individuels.

Lorsque les données mises en cache sont distribuées, les données :

  • sont cohérentes entre les demandes adressées à plusieurs serveurs.
  • survivent aux redémarrages du serveur et aux déploiements d’applications.
  • n’utilisent pas la mémoire locale.

La configuration du cache distribué est spécifique à l’implémentation. Cet article explique comment configurer des caches distribués SQL Server et Redis. Des implémentations tierces sont également disponibles, telles que NCache (NCache sur GitHub). Quelle que soit l’implémentation sélectionnée, l’application interagit avec le cache à l’aide de l’interface IDistributedCache.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)

Prérequis

Pour utiliser un cache distribué SQL Server, ajoutez une référence de package au package Microsoft.Extensions.Caching.SqlServer.

Pour utiliser un cache distribué SQL Server, ajoutez une référence de package au package Microsoft.Extensions.Caching.SqlServer.

Pour utiliser le cache distribué NCache, ajoutez une référence de package au package NCache.Microsoft.Extensions.Caching.OpenSource.

Interface IDistributedCache

L’interface IDistributedCache fournit les méthodes suivantes pour manipuler des éléments dans l’implémentation du cache distribué :

  • Get, GetAsync : accepte une clé de chaîne et récupère un élément mis en cache sous forme de tableau byte[] s’il est trouvé dans le cache.
  • Set, SetAsync : ajoute un élément (sous forme de tableau byte[]) au cache à l’aide d’une clé de chaîne.
  • Refresh, RefreshAsync : actualise un item du cache en fonction de sa clé, en réinitialisant son délai d’expiration décalé (si celui-ci a été défini).
  • Remove, RemoveAsync : supprime un élément de cache en fonction de sa clé de chaîne.

Établir des services de mise en cache distribuée

Inscrivez une implémentation de IDistributedCache dans Startup.ConfigureServices. Les implémentations fournies par l’infrastructure décrites dans cette rubrique sont les suivantes :

Cache de mémoire distribuée

Le cache de mémoire distribuée (AddDistributedMemoryCache) est une implémentation fournie par l’infrastructure de IDistributedCache qui stocke les éléments en mémoire. Le cache de mémoire distribuée n’est pas un véritable cache distribué. Les éléments mis en cache sont stockés par l’instance d’application sur le serveur sur lequel l’application s’exécute.

Le cache de mémoire distribuée est une implémentation utile :

  • Dans les scénarios de développement et de test.
  • Lorsqu’un serveur unique est utilisé en production et que la consommation de mémoire n’est pas un problème. L’implémentation du cache de mémoire distribuée extrait le stockage des données mises en cache. Elle permet d’implémenter une véritable solution de mise en cache distribuée à l’avenir si plusieurs nœuds ou une tolérance de panne deviennent nécessaires.

L’exemple d’application utilise le cache de mémoire distribuée quand l’application est exécutée dans l’environnement de développement dans Startup.ConfigureServices :

services.AddDistributedMemoryCache();

Cache SQL Server distribué

L’implémentation du cache SQL Server distribué (AddDistributedSqlServerCache) permet au cache distribué d’utiliser une base de données SQL Server comme magasin de stockage. Pour créer une table d’éléments mis en cache SQL Server dans un SQL Server instance, vous pouvez utiliser l’outil sql-cache. L’outil crée une table avec le nom et le schéma que vous spécifiez.

Créez une table dans SQL Server en exécutant la commande sql-cache create. Fournissez le SQL Server instance (Data Source), la base de données (Initial Catalog), le schéma (par exemple, dbo) et le nom de la table (par exemple, TestCache) :

dotnet sql-cache create "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=DistCache;Integrated Security=True;" dbo TestCache

Un message est enregistré pour indiquer que l’outil a réussi :

Table and index were created successfully.

La table créée par l’outil sql-cache a le schéma suivant :

SqlServer Cache Table

Remarque

Une application doit manipuler les valeurs de cache à l’aide d’un instance de IDistributedCache, et non d’un SqlServerCache.

L’exemple d’application implémente SqlServerCache dans un environnement non-développement dans Startup.ConfigureServices :

services.AddDistributedSqlServerCache(options =>
{
    options.ConnectionString = 
        _config["DistCache_ConnectionString"];
    options.SchemaName = "dbo";
    options.TableName = "TestCache";
});

Remarque

Un ConnectionString (et éventuellement, SchemaName et TableName) sont généralement stockés en dehors du contrôle de code source (par exemple, stockés par le Gestionnaire de secrets ou dans des appsettings.json/appsettings.{Environment}.json fichiers). La chaîne de connexion peut contenir des informations d’identification qui doivent être conservées en dehors des systèmes de contrôle de code source.

Cache Redis distribué

Redis est un magasin de données open source en mémoire, qui est souvent utilisé comme cache distribué. Vous pouvez configurer un cache Redis Azure pour une application ASP.NET Core hébergée par Azure et utiliser un cache Redis Azure pour le développement local.

Une application configure l’implémentation du cache à l’aide d’une instance RedisCache (AddStackExchangeRedisCache).

  1. Créer une instance d’Azure Cache pour Redis.
  2. Copiez la chaîne de connexion principale (StackExchange.Redis) dans Configuration.
    • Développement local : enregistrez la chaîne de connexion avec le Gestionnaire de secrets.
    • Azure : enregistrez la chaîne de connexion dans la configuration App Service ou dans un autre magasin sécurisé.

Le code suivant active Azure Cache pour Redis :

public void ConfigureServices(IServiceCollection services)
{
    if (_hostContext.IsDevelopment())
    {
        services.AddDistributedMemoryCache();
    }
    else
    {
        services.AddStackExchangeRedisCache(options =>
        {
            options.Configuration = _config["MyRedisConStr"];
            options.InstanceName = "SampleInstance";
        });
    }

    services.AddRazorPages();
}

Le code précédent suppose que la chaîne de connexion principale (StackExchange.Redis) a été enregistrée dans la configuration avec le nom de clé MyRedisConStr.

Pour plus d’informations, consultez Azure Cache pour Redis.

Consultez ce problème GitHub pour une discussion sur les approches alternatives à un cache Redis local.

Cache NCache distribué

NCache est un cache distribué open source en mémoire développé en mode natif dans .NET et .NET Core. NCache fonctionne à la fois localement et configuré en tant que cluster de cache distribué pour une application ASP.NET Core s’exécutant dans Azure ou sur d’autres plateformes d’hébergement.

Pour installer et configurer NCache sur votre ordinateur local, consultez Prise en main Guide pour Windows (.NET et .NET Core).

Pour configurer NCache :

  1. Installez NCache open source NuGet.

  2. Configurez le cluster de cache dans client.ncconf.

  3. Ajoutez le code suivant à Startup.ConfigureServices :

    services.AddNCacheDistributedCache(configuration =>    
    {        
        configuration.CacheName = "demoClusteredCache";
        configuration.EnableLogs = true;
        configuration.ExceptionsEnabled = true;
    });
    

Utiliser le cache distribué

Pour utiliser l’interfaceIDistributedCache, demandez un instance de IDistributedCache à n’importe quel constructeur dans l’application. L’instance est fournie par l’injection de dépendances (DI).

Lorsque l’exemple d’application démarre, IDistributedCache est injecté dans Startup.Configure. L’heure actuelle est mise en cache à l’aide de IHostApplicationLifetime (pour plus d’informations, consultez Hôte générique : IHostApplicationLifetime) :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, 
    IHostApplicationLifetime lifetime, IDistributedCache cache)
{
    lifetime.ApplicationStarted.Register(() =>
    {
        var currentTimeUTC = DateTime.UtcNow.ToString();
        byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC);
        var options = new DistributedCacheEntryOptions()
            .SetSlidingExpiration(TimeSpan.FromSeconds(20));
        cache.Set("cachedTimeUTC", encodedCurrentTimeUTC, options);
    });

L’exemple d’application injecte IDistributedCache dans le IndexModel pour une utilisation par la page Index.

Chaque fois que la page Index est chargée, le cache est vérifié pour l’heure mise en cache dans OnGetAsync. Si l’heure mise en cache n’a pas expiré, l’heure s’affiche. Si 20 secondes se sont écoulées depuis le dernier accès à l’heure mise en cache (la dernière fois que cette page a été chargée), la page affiche l’heure mise en cache expirée.

Mettez immédiatement à jour l’heure mise en cache à l’heure actuelle en sélectionnant le bouton Réinitialiser l’heure mise en cache. Le bouton déclenche la méthode de gestionnaire OnPostResetCachedTime.

public class IndexModel : PageModel
{
    private readonly IDistributedCache _cache;

    public IndexModel(IDistributedCache cache)
    {
        _cache = cache;
    }

    public string CachedTimeUTC { get; set; }

    public async Task OnGetAsync()
    {
        CachedTimeUTC = "Cached Time Expired";
        var encodedCachedTimeUTC = await _cache.GetAsync("cachedTimeUTC");

        if (encodedCachedTimeUTC != null)
        {
            CachedTimeUTC = Encoding.UTF8.GetString(encodedCachedTimeUTC);
        }
    }

    public async Task<IActionResult> OnPostResetCachedTime()
    {
        var currentTimeUTC = DateTime.UtcNow.ToString();
        byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC);
        var options = new DistributedCacheEntryOptions()
            .SetSlidingExpiration(TimeSpan.FromSeconds(20));
        await _cache.SetAsync("cachedTimeUTC", encodedCurrentTimeUTC, options);

        return RedirectToPage();
    }
}

Remarque

Il n’est pas nécessaire d’utiliser un singleton ou une durée de vie étendue pour les instances IDistributedCache avec les implémentations intégrées.

Vous pouvez également créer une instance IDistributedCache partout où vous en avez besoin au lieu d’utiliser l’injonction de dépendances, mais la création d’une instance dans le code peut rendre votre code plus difficile à tester et violer le principe des dépendances explicites.

Recommandations

Lorsque vous décidez quelle implémentation de IDistributedCache est la mieux adaptée à votre application, tenez compte des points suivants :

  • Infrastructure existante
  • Exigences en matière de performances
  • Coût
  • Expérience d’équipe

Les solutions de mise en cache s’appuient généralement sur le stockage en mémoire pour fournir une récupération rapide des données mises en cache, mais la mémoire est une ressource limitée et coûteuse à développer. Stockez uniquement les données couramment utilisées dans un cache.

En règle générale, un cache Redis offre un débit plus élevé et une latence inférieure à celle d’un cache SQL Server. Toutefois, l’évaluation est généralement nécessaire pour déterminer les caractéristiques de performances des stratégies de mise en cache.

Lorsque SQL Server est utilisé comme magasin de stockage de cache distribué, l’utilisation de la même base de données pour le cache et le stockage et la récupération des données ordinaires de l’application peuvent avoir un impact négatif sur les performances de ces deux éléments. Nous vous recommandons d’utiliser un SQL Server instance dédié pour le magasin de stockage du cache distribué.

Ressources supplémentaires