组合缓存方法 - 基于内存缓存/磁盘

Posted

技术标签:

【中文标题】组合缓存方法 - 基于内存缓存/磁盘【英文标题】:Combining cache methods - memcache/disk based 【发布时间】:2011-01-31 09:51:34 【问题描述】:

这是交易。我们会采取完整的静态 html 路径来解决性能问题,但由于该站点将是部分动态的,这对我们来说是行不通的。 我们想到的是使用 memcache + eAccelerator 来加速 php 并负责缓存最常用的数据。

这是我们目前想到的两种方法:

在 >>all

将内存缓存用于最常检索的数据,并与标准硬盘存储的缓存结合以供进一步使用。

仅使用 memcache 的主要优势当然是性能,但随着用户的增加,内存使用量会变得很重。将两者结合起来听起来对我们来说是一种更自然的方法,尽管理论上会在性能上有所妥协。 Memcached 似乎也有一些可用的复制功能,当需要增加节点时可能会派上用场。

我们应该使用什么方法? - 妥协和结合这两种方法是愚蠢的吗?我们是否应该专注于使用 memcache,而不是专注于随着负载随着用户数量的增加而升级内存?

非常感谢!

【问题讨论】:

【参考方案1】:

您可以将磁盘/内存缓存的组合委托给操作系统(如果您的操作系统足够智能)。 对于 Solaris,实际上你甚至可以在中间添加 SSD 层;这种技术称为 L2ARC。

我建议您先阅读以下内容:http://blogs.oracle.com/brendan/entry/test。

【讨论】:

嗨!现在看来,我们将使用centOS。我将检查 Solaris,但这将是一个全新的学习内容。我不确定我们是否可以牺牲那部分来重新开始,从操作系统开始学习......不过非常感谢您的帮助。您知道其他支持此功能的操作系统吗? 嗯,这是你的选择......但使用 Solaris 并免费获得缓存可能更便宜/更快。你会得到 ZFS,它可能是当今最好的 fs。不幸的是,我不知道 Linux 有什么类似的东西。【参考方案2】:

Memcached 是一个可扩展的系统。例如,您可以复制缓存以减少某些密钥存储桶的访问时间,或实施 Ketama 算法,使您能够从池中添加/删除 Memcached 实例,而无需重新映射所有密钥。这样,当您碰巧有额外的内存时,您可以轻松地添加专用于 Memcached 的新机器。此外,由于它的实例可以以不同的大小运行,您可以通过向旧机器添加更多 RAM 来抛出一个实例。一般来说,这种方法更经济,并且在某种程度上并不逊于第一种,尤其是对于 multiget() 请求。关于性能随数据增长而下降的问题,Memcached 中使用的算法的运行时间不会随数据大小而变化,因此访问时间仅取决于同时请求的数量。最后,如果你想调整你的内存/性能优先级,你可以设置过期时间和可用内存配置值,这将严格 RAM 使用或增加缓存命中。

同时,当您使用硬盘时,文件系统可能会成为您应用程序的瓶颈。除了一般的 I/O 延迟之外,碎片和巨大的目录之类的事情也会显着影响您的整体请求速度。另外,请注意默认的 Linux 硬盘设置更多是为了兼容性而不是速度,因此建议在使用前正确配置它(例如,您可以尝试 hdparm 实用程序)。

因此,在再添加一个积分点之前,我认为您应该调整现有系统。通常,即使对于高负载的网站,正确设计的数据库、配置的 PHP、Memcached 和静态数据的处理也应该足够了。

【讨论】:

嗨维塔利。非常感谢您对这个问题的帮助和想法!【参考方案3】:

Memcached 是您确定需要时使用的东西。您不必担心它会占用大量内存,因为在评估它时,您会考虑将要部署它的专用盒子的成本。

在大多数情况下,将 memcached 放在共享机器上是浪费时间,因为它的内存最好用于缓存它所做的任何其他事情。

memcached 的好处是可以将它用作多台机器之间的共享缓存,从而提高命中率。此外,您可以拥有比单个盒子更高的缓存大小和性能,因为您可以(并且通常会)部署多个盒子(每个地理位置)。

此外,通常使用 memcached 的方式取决于来自应用服务器的低延迟链接;因此您通常不会在基础架构内的不同地理位置使用相同的 memcached 集群(每个 DC 都有自己的集群)

流程是:

    识别性能问题 确定多少性能改进就足够了 在您的测试实验室中,在具有必要驱动程序机器的生产级硬件上重现问题 - 这是非常重要的,您可能需要大量专用(甚至是专门的)硬件来足够努力地驱动您的应用程序。 测试建议的解决方案 如果可行,请将其发布到生产环境,如果不行,请尝试更多选项并重新开始。

你不应该

缓存“所有内容” 做事而不衡量其实际影响。

由于您的性能测试环境永远不会完美,您应该有足够的仪器/监控来衡量性能并在生产中分析您的应用程序。

这也意味着你缓存的每一件事都应该有一个缓存命中/未命中计数器。您可以使用它来确定缓存何时被浪费。如果缓存的命中率很低(例如,

在生产环境中让各个缓存可切换可能也是值得的。

记住:优化会引入功能性错误。尽可能少做优化,并确保它们是必要且有效的。

【讨论】:

嗨。我们将为 memcache 部分使用 VPS 为其放置特定的盒子。但是,您认为使用基于磁盘的“不受欢迎”数据或将其全部留给 memcache 是错误的? 我认为你应该使用专用的真锡。如果您在使用虚拟机时遇到性能问题,显而易见的举措是使用真正的锡。不要通过添加毫无意义的缓存来浪费您的开发工作并引入错误。磁盘上的数据缓存通常没有用,因为如果它已经在其他地方的磁盘上,除非另一个磁盘被大量过度竞争,否则它不会更有效率。磁盘 IO 操作需要多长时间,无论它是从缓存中读取数据还是从其原始位置读取数据。【参考方案4】:

我认为将这两种方法折中并结合是一种非常聪明的方法。

最明显的缓存管理规则是延迟与延迟。大小规则,也用于 CPU 缓存。在多级缓存中,每个下一级都应该有更大的大小来补偿更高的延迟。我们有更高的延迟但更高的缓存命中率。所以,我不建议你将基于磁盘的缓存放在 memcache 前面。相反,它应该放在内存缓存后面。唯一的例外是如果您缓存安装在内存中的目录 (tmpfs)。在这种情况下,基于文件的缓存可以补偿 memcache 上的高负载,并且还可以获得延迟收益(因为数据局部性)。

这两个存储(基于文件,memcache)不仅仅是方便缓存的存储。您还可以使用几乎任何 KV 数据库,因为它们非常擅长并发控制。

缓存失效是一个单独的问题,可以引起您的注意。您可以使用几种技巧来为缓存未命中提供更微妙的缓存更新。其中之一是狗桩效应预测。如果多个并发线程同时出现缓存未命中,则它们都将转到后端(数据库)。应用程序应该只允许其中一个继续,其余的应该等待缓存。其次是后台缓存更新。很高兴不在 Web 请求线程中而是在后台更新缓存。在后台,您可以更优雅地控制并发级别和更新超时。

实际上,有一种很酷的方法可以让您进行基于标签的缓存跟踪(例如memcached-tag)。引擎盖下非常简单。对于每个缓存条目,您可以保存它所属的标签版本向量(例如:directory#5: 1, user#8: 2)。当您读取缓存行时,您还会从 memcached 中读取所有实际的向量编号(这可以通过multiget 有效地执行)。如果至少一个实际标签版本大于保存在缓存行中的标签版本,则缓存无效。并且当您更改对象(例如目录)时,应增加适当的标签版本。这是一种非常简单而强大的方法,但也有其自身的缺点。在此方案中,您无法执行有效的缓存失效。 Memcached 可以轻松删除实时条目并保留旧条目。

当然,您应该记住:“计算机科学中只有两件困难的事情:缓存失效和命名事情”——Phil Karlton。

【讨论】:

嗨,Dotsid,你有非常有趣的想法。非常感激!你是说它的分层方式应该是请求的数据通过第一层缓存,也就是memcache,如果memcache中的数据无效,那么下一层缓存是基于硬盘的,如果它不再有效打开与数据库的连接并获取用户请求的数据? 是的。我被添加来回答一些关于缓存失效的想法。 您好,Dotsid!一个问题 - 您建议使用什么方法来跟踪应用程序中的键?我的意思是,没有明显的方法可以用它的来源“标记”内存缓存中的一个键?能够做到这一点并且使与一个或多个“类别”、“父母”相关的所有缓存数据无效,或者根据应用程序可以分类的任何内容,这将是非常棒的...... 添加了一些关于基于标签的缓存失效的想法。 嗯,这可能是一个不错的选择,但前提是您知道所有缓存行(因此知道系统中的查询)。如果您的查询种类较少(例如,userA、userB 等的缓存),这可能是正确的。如果不是(例如,缓存目录 A 中价格 【参考方案5】:

我建议您首先将 memcache 用于所有主要查询。然后,进行测试以找到最少使用的查询或很少更改的数据,然后为此提供缓存。

如果您可以将常用数据与很少使用的数据隔离开来,那么您可以专注于提高更常用数据的性能。

【讨论】:

@AKRamkumar 感谢您的帮助!这是这个问题的另一个有趣的角度。

以上是关于组合缓存方法 - 基于内存缓存/磁盘的主要内容,如果未能解决你的问题,请参考以下文章

Chrome 内存缓存与磁盘缓存

android磁盘缓存与内存缓存

iOS开发之缓存框架内存缓存磁盘缓存NSCacheTMMemoryCachePINMemoryCacheYYMemoryCacheTMDiskCachePINDiskCache(示例代

将 LRU 图像缓存与 HTTPResponseCache 结合用于磁盘和内存缓存

Glide:在内存缓存中预加载图像(有或没有磁盘缓存)

《InnoDB引擎‍》 MySQL缓存池