Честно говоря, я не могу решить, является ли это вопрос SO или вопрос MSO, но:
Выход на другую систему никогда не быстрее, чем запрос к локальной памяти (если она включена); простой ответ: мы используем оба! Поэтому мы используем:
- локальная память
- иначе проверьте redis и обновите локальную память
- еще получить из источника и обновить redis и локальную память
Это, как вы говорите, вызывает проблему аннулирования кэша - хотя на самом деле это не является критическим в большинстве мест. Но для этого - события redis (pub / sub) позволяют легко транслировать ключи, которые меняются на все узлы, поэтому они могут отбросить свою локальную копию - это означает: в следующий раз, когда это потребуется, мы заберем новую копию из redis. , Следовательно, мы транслируем имена ключей, которые меняются по отношению к одному имени канала события.
Инструменты: redis на сервере Ubuntu; BookSleeve в качестве оболочки для redis; protobuf-net и GZipStream (включается / отключается автоматически в зависимости от размера) для упаковки данных.
Итак: события redis pub / sub используются для аннулирования кэша для данного ключа от одного узла (того, который знает, что состояние изменилось) немедленно (в значительной степени) до всех узлы.
Относительно отдельных процессов (из комментариев: «Используете ли вы какую-либо модель совместно используемой памяти для нескольких различных процессов, использующих одни и те же данные?»): Нет, мы этого не делаем. Каждый блок веб-уровня действительно содержит только один процесс (любого данного уровня) с мультитенантностью в пределах , поэтому в одном и том же процессе у нас может быть 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
операторах. Для этого мы используем почти синглтон.