Redis
 sql >> Base de données >  >> NoSQL >> Redis

Stack Overflow, Redis et invalidation du cache

Honnêtement, je ne peux pas décider s'il s'agit d'une question SO ou d'une question MSO, mais :

Passer à un autre système n'est jamais plus rapide que d'interroger la mémoire locale (tant qu'elle est saisie) ; réponse simple :nous utilisons les deux ! Nous utilisons donc :

  • mémoire locale
  • Sinon, vérifiez redis et mettez à jour la mémoire locale
  • sinon récupérer à partir de la source et mettre à jour redis et la mémoire locale

Cela, comme vous le dites, provoque alors un problème d'invalidation du cache - bien qu'en réalité ce ne soit pas critique dans la plupart des endroits. Mais pour cela - les événements redis (pub/sub) permettent de diffuser facilement les clés qui changent à tous les nœuds, afin qu'ils puissent supprimer leur copie locale - ce qui signifie :la prochaine fois que cela sera nécessaire, nous récupérerons la nouvelle copie de redis . Par conséquent, nous diffusons les noms de clé qui changent par rapport à un seul nom de canal d'événement.

Outils :redis sur le serveur ubuntu; BookSleeve comme wrapper Redis ; protobuf-net et GZipStream (activé/désactivé automatiquement selon la taille) pour les données d'empaquetage.

Donc :les événements redis pub/sub sont utilisés pour invalider le cache pour une clé donnée à partir de une nœud (celui qui sait que l'état a changé) immédiatement (presque) à tous nœuds.

En ce qui concerne les processus distincts (d'après les commentaires, "utilisez-vous un type de modèle de mémoire partagée pour plusieurs processus distincts se nourrissant des mêmes données ?") :non, nous ne le faisons pas. Chaque boîtier de niveau Web n'héberge réellement qu'un seul processus (de n'importe quel niveau donné), avec une multi-location à l'intérieur cela, donc dans le même processus, nous pourrions avoir 70 sites. Pour des raisons d'héritage (c'est-à-dire "cela fonctionne et n'a pas besoin d'être corrigé"), nous utilisons principalement le cache http avec l'identité du site dans le cadre de la clé.

Pour les quelques parties massivement consommatrices de données du système, nous avons des mécanismes pour persister sur le disque afin que le modèle en mémoire puisse être transmis entre les domaines d'application successifs au fur et à mesure que le Web se recycle naturellement (ou est redéployé), mais c'est sans rapport avec redis.

Voici un exemple connexe qui montre la version large uniquement de la façon dont cela pourrait fonctionner - lancez un certain nombre d'instances des éléments suivants, puis tapez quelques noms de clé dans :

static class Program
{
    static void Main()
    {
        const string channelInvalidate = "cache/invalidate";
        using(var pub = new RedisConnection("127.0.0.1"))
        using(var sub = new RedisSubscriberConnection("127.0.0.1"))
        {
            pub.Open();
            sub.Open();

            sub.Subscribe(channelInvalidate, (channel, data) =>
            {
                string key = Encoding.UTF8.GetString(data);
                Console.WriteLine("Invalidated {0}", key);
            });
            Console.WriteLine(
                    "Enter a key to invalidate, or an empty line to exit");
            string line;
            do
            {
                line = Console.ReadLine();
                if(!string.IsNullOrEmpty(line))
                {
                    pub.Publish(channelInvalidate, line);
                }
            } while (!string.IsNullOrEmpty(line));
        }
    }
}

Ce que vous devriez voir, c'est que lorsque vous tapez un nom de clé, il s'affiche immédiatement dans toutes les instances en cours d'exécution, qui videraient alors leur copie locale de cette clé. De toute évidence, en utilisation réelle, les deux connexions devraient être placées quelque part et maintenues ouvertes, donc pas être en using déclarations. Nous utilisons un quasi-singleton pour cela.