Maison  >  Article  >  base de données  >  Parlons de l'utilisation de Redis pour implémenter la mise en cache distribuée

Parlons de l'utilisation de Redis pour implémenter la mise en cache distribuée

WBOY
WBOYavant
2022-07-14 17:01:172643parcourir

Cet article vous apporte des connaissances pertinentes sur Redis, qui organise principalement les problèmes liés à la mise en cache distribuée. Cela signifie qu'il se compose de plusieurs applications, qui peuvent être distribuées sur différents serveurs. En fin de compte, elles fournissent toutes des services côté Web. . Jetons-y un coup d'œil. J'espère que cela sera utile à tout le monde.

Parlons de l'utilisation de Redis pour implémenter la mise en cache distribuée

Apprentissage recommandé : Tutoriel vidéo Redis

Description du cache distribué :

L'accent est mis sur la distribution. Je pense que vous êtes entré en contact avec de nombreuses méthodes distribuées, telles que le développement distribué. existe de nombreux déploiements distribués, verrous distribués, objets, systèmes, etc. Cela nous donne une compréhension claire de la distribution elle-même. La distribution est composée de plusieurs applications, qui peuvent être distribuées sur différents serveurs et finalement fournir des services côté Web.
La mise en cache distribuée présente les avantages suivants :

  1. Les données mises en cache sur tous les serveurs Web sont les mêmes et les données mises en cache ne seront pas différentes en raison des différentes applications et des différents serveurs.
  2. Le cache est indépendant et n'est pas affecté par le redémarrage du serveur Web ni par la suppression et l'ajout, ce qui signifie que ces modifications dans le Web n'entraîneront pas de modifications dans les données mises en cache.

Dans l'architecture traditionnelle à application unique, étant donné que le nombre de visites d'utilisateurs n'est pas élevé, la majeure partie du cache existe pour stocker les informations utilisateur et certaines pages sont directement des interactions de lecture et d'écriture avec la base de données. est simple, également appelé architecture simple.
Les projets OA traditionnels tels que les ERP, SCM, CRM et autres systèmes ont un petit nombre d'utilisateurs et sont également dus aux raisons commerciales de la plupart des entreprises. L'architecture d'application unique est encore une architecture très courante. , mais certains systèmes le sont. À mesure que le nombre d'utilisateurs augmente et que l'activité se développe, des goulots d'étranglement apparaissent dans la base de données.

Il y a deux façons de gérer cette situation que j'ai apprises ci-dessous

(1) : Lorsque le nombre de visites d'utilisateurs n'est pas important, mais que la quantité de données lues et écrites est importante, ce que nous adoptons généralement est de traiter avec la base de données Séparez la lecture et l'écriture, utilisez un maître avec plusieurs esclaves et mettez à niveau le matériel pour résoudre le problème de goulot d'étranglement de la base de données.
De telles lacunes sont également purement :

1. Que faire lorsque le nombre d'utilisateurs est important ? ,
2. L'amélioration des performances est limitée,
3. Le rapport qualité/prix n'est pas élevé. Améliorer les performances nécessite beaucoup d'argent (par exemple, le débit d'E/S actuel est de 0,9 et doit être augmenté à 1,0. Ce prix est en effet considérable lorsque l'on augmente la configuration de la machine)

(2) : Lorsque le nombre d'utilisateurs les visites augmentent également, nous devons introduire la mise en cache pour résoudre le problème. Une image décrit le rôle général de la mise en cache.

La mise en cache est principalement destinée aux données qui changent rarement et est très visitée. La base de données DB peut être comprise comme uniquement utilisée pour solidifier les données ou uniquement pour lire les données qui changent fréquemment. Je ne l'ai pas dans l'image ci-dessus. Le fonctionnement du dessin SET consiste à expliquer spécifiquement que l'existence du cache peut être utilisée comme base de données temporaire. Nous pouvons synchroniser les données dans le cache et la base de données via des tâches planifiées. de la base de données au milieu du cache.

L'émergence du cache résout le problème de la pression de la base de données, mais lorsque les situations suivantes se produisent, le cache ne jouera plus de rôle, la pénétration du cache, la panne du cache et l'avalanche de cache sont trois situations.

Pénétration du cache : Lorsque nous utilisons le cache dans nos programmes, nous allons généralement d'abord dans le cache pour interroger les données du cache que nous voulons. Si les données que nous voulons n'existent pas dans le cache, le cache perdra son rôle. Échec du cache) Nous devons simplement contacter la bibliothèque de base de données pour demander des données. À ce stade, s'il y a trop de telles actions, la base de données plantera. Cette situation doit être évitée par nous. Par exemple : nous obtenons des informations utilisateur à partir du cache, mais entrons délibérément des informations utilisateur qui n'existent pas dans le cache, évitant ainsi le cache et renvoyant la pression sur les données. Pour résoudre ce problème, nous pouvons mettre en cache les données consultées pour la première fois, car le cache ne peut pas trouver les informations utilisateur et la base de données ne peut pas interroger les informations utilisateur. À ce stade, pour éviter des accès répétés, nous mettons la demande en cache et la mettons. En ce qui concerne le cache, certaines personnes peuvent avoir des questions. Que faire lorsqu'il y a des dizaines de milliers de paramètres accessibles qui sont uniques et peuvent éviter le cache. Nous stockons également les données et définissons un délai d'expiration plus court pour vider le cache.

Panne du cache :  Le problème est comme ceci. Pour certaines clés de cache avec un délai d'expiration défini, lorsqu'elles expirent, le programme est accessible avec un accès simultané élevé (invalidation du cache). À ce stade, un verrou mutex est utilisé pour résoudre. le problème.

Principe de verrouillage Mutex : La description populaire est que 10 000 utilisateurs ont accédé, mais un seul utilisateur peut obtenir l'autorisation d'accéder à la base de données. Lorsque cet utilisateur obtient cette autorisation, le cache est recréé. temps, le reste Parce que le visiteur n'a pas la permission, il attend pour accéder au cache.

N'expire jamais : Certaines personnes peuvent penser : cela ne peut-il pas suffire si je ne règle pas le délai d'expiration ? Oui, mais cela présente aussi des inconvénients. Nous devons mettre à jour le cache régulièrement. À l'heure actuelle, les données dans le cache sont relativement retardées.

Avalanche de cache : signifie que plusieurs caches doivent expirer en même temps. À ce moment-là, un grand nombre d'accès aux données surviennent (Invalidation du cache) et la pression sur la base de données revient. La solution consiste à ajouter un nombre aléatoire au délai d'expiration lors de la définition du délai d'expiration pour garantir que le cache ne tombe pas en panne dans une zone étendue.

Préparation du projet

1. Installez d'abord Redis, vous pouvez vous référer à ici
2. Ensuite, téléchargez et installez : outil client : RedisDesktopManager (gestion pratique)
3. Référencez Microsoft.Extensions.Caching.Redis dans notre projet Nuget

Pour cela, nous créons un nouveau projet ASP.NET Core MVC et enregistrons d'abord le service Redis dans la méthode ConfigureServices de la classe de démarrage du projet :

public void ConfigureServices(IServiceCollection services)
{
    //将Redis分布式缓存服务添加到服务中
    services.AddDistributedRedisCache(options =>
    {
        //用于连接Redis的配置  Configuration.GetConnectionString("RedisConnectionString")读取配置信息的串
        options.Configuration = "localhost";// Configuration.GetConnectionString("RedisConnectionString");
        //Redis实例名DemoInstance
        options.InstanceName = "DemoInstance";
    });
    services.AddMvc();
}

Vous pouvez également spécifier l'adresse IP, le numéro de port et l'adresse IP. du serveur Redis lors de l'enregistrement du service Redis ci-dessus. Mot de passe de connexion :

public void ConfigureServices(IServiceCollection services)
{
    //将Redis分布式缓存服务添加到服务中
    services.AddDistributedRedisCache(options =>
    {
        //用于连接Redis的配置  Configuration.GetConnectionString("RedisConnectionString")读取配置信息的串
        options.Configuration = "192.168.1.105:6380,password=1qaz@WSX3edc$RFV";//指定Redis服务器的IP地址、端口号和登录密码
        //Redis实例名DemoInstance
        options.InstanceName = "DemoInstance";
    });
    services.AddMvc();
}

Plus tard, nous expliquerons à quoi sert le nom de l'instance Redis DemoInstance défini par options.InstanceName ci-dessus

De plus, vous pouvez également spécifier le délai d'expiration du. Serveur Redis dans la méthode services.AddDistributedRedisCache. Si vous appelez le IDistributedCache introduit plus tard, la méthode dans l'interface lancera RedisConnectionException et RedisTimeoutException lorsque l'opération sur le serveur Redis expirera, donc lorsque nous enregistrons le service Redis ci-dessous, nous spécifions trois délais d'attente :

public void ConfigureServices(IServiceCollection services)
{
    //将Redis分布式缓存服务添加到服务中
    services.AddDistributedRedisCache(options =>
    {
        options.ConfigurationOptions = new StackExchange.Redis.ConfigurationOptions()
        {
            Password = "1qaz@WSX3edc$RFV",
            ConnectTimeout = 5000,//设置建立连接到Redis服务器的超时时间为5000毫秒
            SyncTimeout = 5000,//设置对Redis服务器进行同步操作的超时时间为5000毫秒
            ResponseTimeout = 5000//设置对Redis服务器进行操作的响应超时时间为5000毫秒
        };

        options.ConfigurationOptions.EndPoints.Add("192.168.1.105:6380");
        options.InstanceName = "DemoInstance";
    });
    services.AddMvc();
}

Parmi eux, ConnectTimeout consiste à établir une connexion au serveur Redis. Le délai d'attente, et SyncTimeout et ResponseTimeout sont les délais d'attente pour les opérations de données sur le serveur Redis. Notez que ci-dessus, nous avons utilisé l'attribut options.ConfigurationOptions pour définir l'adresse IP, le numéro de port et le mot de passe de connexion du serveur Redis

Interface IDistributedCache

Référencé dans le projet : using Microsoft.Extensions.Caching.Distributed using IDistributedCache

 ;

Interface IDistributedCache Contient des méthodes synchrones et asynchrones. L'interface permet d'ajouter, de récupérer et de supprimer des éléments dans une implémentation de cache distribué. L'interface IDistributedCache contient les méthodes suivantes :
Get, GetAsync
qui prend une clé de chaîne et récupère l'élément du cache sous forme d'octet[] s'il est trouvé dans le cache.
Set, SetAsync
Ajoutez ou modifiez des éléments (forme octet[]) dans le cache à l'aide de clés de chaîne.
Refresh, RefreshAsync
Actualisez un élément dans le cache en fonction d'une clé et réinitialisez sa valeur de délai d'expiration réglable (le cas échéant).
Supprimer, RemoveAsync
Supprimez les éléments du cache en fonction de la clé. Si la clé passée dans la méthode Remove n'existe pas dans Redis, la méthode Remove ne signalera pas d'erreur, mais rien ne se passera. Cependant, si le paramètre passé dans la méthode Remove est nul, une exception sera levée.

Comme mentionné ci-dessus, étant donné que les méthodes Set et Get de l'interface IDistributedCache accèdent aux données de Redis via des tableaux d'octets byte[], ce n'est pas très pratique dans un sens. Ci-dessous, j'encapsule une classe RedisCache, tout type de données est accessible. de Redis.

Le package Json.NET Nuget est utilisé pour sérialiser et désérialiser le format Json :

using Microsoft.Extensions.Caching.Distributed;
using Newtonsoft.Json;
using System.Text;

namespace AspNetCoreRedis.Assembly
{
    /// <summary>
    /// RedisCache缓存操作类
    /// </summary>
    public class RedisCache
    {
        protected IDistributedCache cache;

        /// <summary>
        /// 通过IDistributedCache来构造RedisCache缓存操作类
        /// </summary>
        /// <param name="cache">IDistributedCache对象</param>
        public RedisCache(IDistributedCache cache)
        {
            this.cache = cache;
        }

        /// <summary>
        /// 添加或更改Redis的键值,并设置缓存的过期策略
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <param name="value">缓存值</param>
        /// <param name="distributedCacheEntryOptions">设置Redis缓存的过期策略,可以用其设置缓存的绝对过期时间(AbsoluteExpiration或AbsoluteExpirationRelativeToNow),也可以设置缓存的滑动过期时间(SlidingExpiration)</param>
        public void Set(string key, object value, DistributedCacheEntryOptions distributedCacheEntryOptions)
        {
            //通过Json.NET序列化缓存对象为Json字符串
            //调用JsonConvert.SerializeObject方法时,设置ReferenceLoopHandling属性为ReferenceLoopHandling.Ignore,来避免Json.NET序列化对象时,因为对象的循环引用而抛出异常
            //设置TypeNameHandling属性为TypeNameHandling.All,这样Json.NET序列化对象后的Json字符串中,会包含序列化的类型,这样可以保证Json.NET在反序列化对象时,去读取Json字符串中的序列化类型,从而得到和序列化时相同的对象类型
            var stringObject = JsonConvert.SerializeObject(value, new JsonSerializerSettings()
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                TypeNameHandling = TypeNameHandling.All
            });

            var bytesObject = Encoding.UTF8.GetBytes(stringObject);//将Json字符串通过UTF-8编码,序列化为字节数组

            cache.Set(key, bytesObject, distributedCacheEntryOptions);//将字节数组存入Redis
            Refresh(key);//刷新Redis
        }

        /// <summary>
        /// 查询键值是否在Redis中存在
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <returns>true:存在,false:不存在</returns>
        public bool Exist(string key)
        {
            var bytesObject = cache.Get(key);//从Redis中获取键值key的字节数组,如果没获取到,那么会返回null

            if (bytesObject == null)
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// 从Redis中获取键值
        /// </summary>
        /// <typeparam name="T">缓存的类型</typeparam>
        /// <param name="key">缓存键</param>
        /// <param name="isExisted">是否获取到键值,true:获取到了,false:键值不存在</param>
        /// <returns>缓存的对象</returns>
        public T Get<T>(string key, out bool isExisted)
        {
            var bytesObject = cache.Get(key);//从Redis中获取键值key的字节数组,如果没获取到,那么会返回null

            if (bytesObject == null)
            {
                isExisted = false;
                return default(T);
            }

            var stringObject = Encoding.UTF8.GetString(bytesObject);//通过UTF-8编码,将字节数组反序列化为Json字符串

            isExisted = true;

            //通过Json.NET反序列化Json字符串为对象
            //调用JsonConvert.DeserializeObject方法时,也设置TypeNameHandling属性为TypeNameHandling.All,这样可以保证Json.NET在反序列化对象时,去读取Json字符串中的序列化类型,从而得到和序列化时相同的对象类型
            return JsonConvert.DeserializeObject<T>(stringObject, new JsonSerializerSettings()
            {
                TypeNameHandling = TypeNameHandling.All
            });
        }

        /// <summary>
        /// 从Redis中删除键值,如果键值在Redis中不存在,该方法不会报错,只是什么都不会发生
        /// </summary>
        /// <param name="key">缓存键</param>
        public void Remove(string key)
        {
            cache.Remove(key);//如果键值在Redis中不存在,IDistributedCache.Remove方法不会报错,但是如果传入的参数key为null,则会抛出异常
        }

        /// <summary>
        /// 从Redis中刷新键值
        /// </summary>
        /// <param name="key">缓存键</param>
        public void Refresh(string key)
        {
            cache.Refresh(key);
        }
    }
}

Test d'utilisation

Ensuite, nous créons un nouveau CacheController dans le projet ASP.NET Core MVC, puis l'ajoutons à la méthode Index pour tester le méthodes associées de la classe RedisCache :

public class CacheController : Controller
{
    protected RedisCache redisCache;

    //由于我们前面在Startup类的ConfigureServices方法中调用了services.AddDistributedRedisCache来注册Redis服务,所以ASP.NET Core MVC会自动依赖注入下面的IDistributedCache cache参数
    public CacheController(IDistributedCache cache)
    {
        redisCache = new RedisCache(cache);
    }

    public IActionResult Index()
    {
        bool isExisted;
        isExisted = redisCache.Exist("abc");//查询键值"abc"是否存在
        redisCache.Remove("abc");//删除不存在的键值"abc",不会报错

        string key = "Key01";//定义缓存键"Key01"
        string value = "This is a demo key !";//定义缓存值

        redisCache.Set(key, value, new DistributedCacheEntryOptions()
        {
            AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10)
        });//设置键值"Key01"到Redis,使用绝对过期时间,AbsoluteExpirationRelativeToNow设置为当前系统时间10分钟后过期

        //也可以通过AbsoluteExpiration属性来设置绝对过期时间为一个具体的DateTimeOffset时间点
        //redisCache.Set(key, value, new DistributedCacheEntryOptions()
        //{
        //    AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(10)
        //});//设置键值"Key01"到Redis,使用绝对过期时间,AbsoluteExpiration设置为当前系统时间10分钟后过期

        var getVaue = redisCache.Get<string>(key, out isExisted);//从Redis获取键值"Key01",可以看到getVaue的值为"This is a demo key !"

        value = "This is a demo key again !";//更改缓存值

        redisCache.Set(key, value, new DistributedCacheEntryOptions()
        {
            SlidingExpiration = TimeSpan.FromMinutes(10)
        });//将更改后的键值"Key01"再次缓存到Redis,这次使用滑动过期时间,SlidingExpiration设置为10分钟

        getVaue = redisCache.Get<string>(key, out isExisted);//再次从Redis获取键值"Key01",可以看到getVaue的值为"This is a demo key again !"

        redisCache.Remove(key);//从Redis中删除键值"Key01"

        return View();
    }
}

Plus tôt, dans la méthode ConfigureServices de la classe Startup du projet, lors de l'appel de services.AddDistributedRedisCache pour enregistrer le service Redis, nous définissons options.InstanceName = "DemoInstance", alors qu'est-ce que cela fait exactement InstanceName a-t-il ?

Après avoir appelé le code suivant de la méthode Index dans le CacheController ci-dessus :

string key = "Key01";//定义缓存键"Key01"
string value = "This is a demo key !";//定义缓存值

redisCache.Set(key, value, new DistributedCacheEntryOptions()
{
    AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10)
});//设置键值"Key01"到Redis,使用绝对过期时间,AbsoluteExpirationRelativeToNow设置为当前系统时间10分钟后过期

Nous utilisons redis-cli pour nous connecter au serveur Redis et utilisons la commande Keys * pour afficher toutes les clés stockées dans le service Redis actuel, vous pouvez voir les résultats comme suit :

Vous pouvez voir que bien que la clé stockée dans Redis dans notre code soit "Key01", la clé réellement stockée dans le service Redis est "DemoInstanceKey01", donc la clé réellement stockée dans le Service Redis La clé est une combinaison de touches "InstanceName+key", nous pouvons donc isoler les données dans Redis pour différentes applications en définissant différents InstanceNames. C'est le rôle de InstanceName

Apprentissage recommandé : Tutoriel vidéo Redis

.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer