Stack Overflow,Redis和Cache失效

时间:2012-03-07 06:37:28

标签: c# .net caching redis

现在Stack Overflow使用redis,它们是否以相同的方式处理缓存失效?即一个标识列表,用于查询字符串+名称(我猜这个名称是某种目的或对象类型名称)。

然后他们可能会直接通过id检索缓存中丢失的单个项目(绕过一堆数据库索引并使用更高效的聚簇索引)。那很聪明(杰夫提到的补液?)。

现在,我正在努力找到一种方法,以简洁的方式调整所有这些。在我自己做第一次切割之前,是否有任何可以用来帮助澄清我的想法的例子?

另外,我想知道在使用.net缓存(System.Runtime.Caching或System.Web.Caching)和外出并使用redis之间的截止点。或者Redis只是放得更快?

以下是2009年的原始SO问题:

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

其他几个链接:

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

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

1 个答案:

答案 0 :(得分:42)

老实说,我无法确定这是一个SO问题还是一个MSO问题,但是:

转到另一个系统从不比查询本地内存更快(只要它是键控的);简单回答:我们两个都用!所以我们使用:

  • 本地记忆
  • else检查redis,并更新本地内存
  • 从源获取,并更新redis和本地内存

然后,正如您所说,这会导致缓存失效问题 - 尽管在大多数地方实际上并非严重。但是为此 - redis事件(pub / sub)允许一种简单的方法来广播更改为所有节点的键,因此他们可以删除它们的本地副本 - 这意味着:下次需要时我们将从redis中获取新副本。因此,我们广播了针对单个事件通道名称进行更改的键名。

工具:ubuntu服务器上的redis; BookSleeve作为redis包装器; protobuf-net和GZipStream(根据大小自动启用/禁用)打包数据。

所以:redis pub / sub事件用于使一个节点(知道状态已经改变的节点)的给定键的缓存立即(几乎)无效到所有节点。

关于不同的进程(来自评论,“你是否使用任何类型的共享内存模型来处理相同数据的多个不同进程?”):不,我们不这样做。每个Web层框实际上只托管一个进程(任何给定层),多个租用中,因此在同一个进程中我们可能有70个站点。由于遗留原因(即“它工作且不需要修复”),我们主要使用带有site-identity的http缓存作为密钥的一部分。

对于系统中少数大量数据密集型部分,我们有机制持久存储到磁盘,以便内存模型可以在连续的应用程序域之间传递,因为Web自然地回收(或重新部署),但这与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语句中。我们使用几乎一个单身人士。