Подтвердить что ты не робот

Устранение статических ошибок, Redis и Cache

Теперь, когда stackoverflow использует redis, они обрабатывают недействительность кэша таким же образом? то есть список идентификаторов, хэшированных на строку запроса + имя (я думаю, это имя - это какая-то цель или имя типа объекта).

Возможно, они затем извлекают отдельные элементы, которые отсутствуют в кеше напрямую с помощью id (который обходит кучу индексов базы данных и вместо этого использует более эффективный кластеризованный индекс). Это было бы умным (регидратация, которую Джефф упоминает?).

Прямо сейчас, я изо всех сил пытаюсь найти способ все это свести к лучшему. Есть ли примеры такого рода вещей, которые я мог бы использовать, чтобы помочь прояснить мое мышление до того, как я сделаю первый разрез?

Кроме того, мне интересно, где происходит обрезание между кешем .net(System.Runtime.Caching или System.Web.Caching) и выходом и использованием redis. Или Redis просто стреляет быстрее?

Здесь исходный вопрос SO от 2009 года:

https://meta.stackexchange.com/info/6435/how-does-stackoverflow-handle-cache-invalidation

Несколько других ссылок:

https://meta.stackexchange.com/info/69164/does-stackoverflow-use-caching-and-if-so-how/69172#69172

https://meta.stackexchange.com/info/110320/stack-overflow-db-performance-and-redis-cache

4b9b3361

Ответ 1

Я честно не могу решить, является ли это вопросом SO или вопросом MSO, но:

Переход к другой системе никогда не быстрее, чем запрос к локальной памяти (при условии, что она активирована); простой ответ: мы используем оба! Поэтому мы используем:

  • локальная память
  • else проверить redis и обновить локальную память
  • else извлечь из источника и обновить redis и локальную память

Это, как вы говорите, вызывает проблему недействительности кеша - хотя на самом деле это не критично в большинстве мест. Но для этого - события redis (pub/sub) позволяют легко передавать широковещательные ключи, которые меняются на все узлы, поэтому они могут отбрасывать свою локальную копию - значение: в следующий раз, когда это необходимо, мы возьмем новую копию из redis, Следовательно, мы передаем имена ключей, которые изменяются в отношении одного имени канала события.

Инструменты: redis на сервере ubuntu; BookSleeve как оболочка redis; protobuf-net и GZipStream (включены/отключены автоматически в зависимости от размера) для упаковки данных.

Итак: события redis pub/sub используются для отмены кэша для заданного ключа от одного node (тот, который знает, что состояние изменилось) сразу (в значительной степени) до все.

Что касается отдельных процессов (из комментариев), вы используете какую-либо модель разделяемой памяти для нескольких разных процессов, загружающих одни и те же данные?): Нет, мы этого не делаем. В каждом ящике веб-уровня действительно есть только один процесс (любого уровня), в котором есть многоуровневая аренда, поэтому внутри одного процесса у нас может быть 70 сайтов. По причинам, связанным с наследием (например, "это работает и не требует исправления" ), мы в первую очередь используем кеш http с идентификатором сайта как частью ключа.

Для нескольких массивно важных для данных частей системы у нас есть механизмы для сохранения на диске, чтобы модель памяти могла быть передана между последовательными доменами приложения, так как веб, естественно, перерабатывает (или повторно развертывается) но это не связано с redis.

Вот пример, который показывает широкий вкус только того, как это может работать - выделите несколько экземпляров следующих, а затем введите некоторые ключевые имена в:

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));
        }
    }
}

Что вы должны видеть, так это то, что при вводе имени-ключа он сразу отображается во всех запущенных экземплярах, которые затем выгружают их локальную копию этого ключа. Очевидно, что в реальном использовании эти два соединения должны быть помещены где-то и оставаться открытыми, поэтому не находиться в операциях using. Для этого мы используем почти-одиночный.