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

5
这里有一个问题。我们本来想采用完全静态的html方式解决性能问题,但由于网站将部分动态化,这对我们来说行不通。 我们考虑的替代方案是使用memcache + eAccelerator来加速PHP并处理最常用数据的缓存。
这里是我们目前考虑的两种方法: 1. 在所有主要查询中使用memcache,并让它独立工作。 2. 对于最常检索的数据使用memcache,并与标准硬盘缓存相结合以进一步使用。
只使用memcache的主要优势当然是性能,但随着用户数量的增加,内存使用量会变得很大。尽管理论上会影响性能,但在我们看来,将两者结合起来似乎是更自然的方法。 当需要增加节点时,Memcached似乎也提供了一些复制功能,这可能会很方便。
我们应该采用哪种方法呢? - 折衷和结合两种方法是否愚蠢?我们应该专注于利用memcache,并专注于随着用户数量的增加而升级内存吗?
非常感谢!
5个回答

5
折中并结合这两种方法是一种非常聪明的方式,我认为。
最明显的缓存管理规则是延迟和大小规则,它也用于CPU缓存。在多级缓存中,每个下一级应该有更大的大小来补偿更高的延迟。我们有更高的延迟但更高的缓存命中率。因此,我不建议您将基于磁盘的缓存放置在memcache前面。相反,它应该放在memcache后面。唯一的例外是如果您的缓存目录挂载在内存中(tmpfs)。在这种情况下,基于文件的缓存可以弥补对memcache的高负载,并且还可以获得延迟优势(因为数据局部性)。
这两个存储(基于文件的和memcache)不仅是方便缓存的存储方式。您还可以使用几乎任何KV数据库,因为它们非常擅长并发控制。
缓存失效是一个单独的问题,需要引起您的注意。有几个技巧可以用来提供更细致的缓存更新。其中之一是狗堆效应预测。如果几个并发线程同时出现缓存未命中,则所有线程都会进入后端(数据库)。应用程序只应允许其中一个继续进行,其余的应该在缓存上等待。第二个是后台缓存更新。最好不要在Web请求线程中更新缓存,而是在后台中更新。在后台中,您可以更优雅地控制并发级别和更新超时。
实际上,有一种很酷的方法可以进行基于标签的缓存跟踪(例如,memcached-tag)。它在幕后非常简单。对于每个缓存条目,您保存它所属的标签版本向量(例如:{directory#5: 1, user#8: 2})。当您读取缓存行时,还会从memcached中读取所有实际向量号码(这可以使用multiget有效地执行)。如果至少有一个实际标签版本大于缓存行中保存的标签版本,则缓存将失效。当您更改对象(例如目录)时,应适当地增加标签版本。这是一种非常简单而强大的方法,但它也有自己的缺点。在此方案中,您无法执行有效的缓存失效。Memcached可以轻松删除活动条目并保留旧条目。
当然,您应该记住:“计算机科学中只有两件难事:缓存失效和命名”- Phil Karlton。

嗨Dotsid,你的想法非常有趣。非常感谢!你是说它应该分层,请求的数据经过第一层缓存(即memcache),如果memcache中的数据无效,则下一层缓存是基于硬盘的,如果不再有效,则打开到数据库的连接并获取用户请求的数据? - Industrial
1
是的,我也加入了一些有关缓存失效的想法。 - Denis Bazhenov
这是我以前发的一个关于此事的帖子:https://dev59.com/qUzSa4cB1Zd3GeqPpcZ6不过没有得到任何回复 :( - Industrial
1
在基于标签的缓存失效方面添加了一些想法。 - Denis Bazhenov
1
这可能是一个不错的选择,但前提是你要知道所有缓存行(以及系统中的查询)。如果你只有少量的查询(例如为用户A、用户B等缓存),那么这可能是正确的。但如果不是这样(例如在目录A中价格低于1000美元的公告缓存,在目录A中价格低于250美元且完好无损的公告缓存等),那么这就不是一个好主意,因为你根本无法预测哪些缓存行经常使用,哪些不经常使用。因此,即使你有良好的缓存层,你也应该考虑提供低延迟的数据存储。 - Denis Bazhenov
显示剩余3条评论

4
Memcached是一个非常可扩展的系统。例如,您可以复制缓存以减少对某些关键桶的访问时间,或者实施Ketama算法,使您可以添加/删除Memcached实例而无需重新映射所有密钥。这样,当您有额外的内存时,可以轻松添加专用于Memcached的新机器。此外,由于它的实例可以以不同的大小运行,因此您可以通过向旧机器添加更多RAM来启动一个实例。一般来说,这种方法更经济,并且在某种程度上不劣于第一种方法,特别是对于multiget()请求。关于数据增长导致性能下降的问题,Memcached中使用的算法的运行时与数据大小无关,因此访问时间仅取决于同时请求的数量。最后,如果您想调整内存/性能优先级,可以设置过期时间和可用内存配置值,这将限制RAM使用或增加缓存命中率。
同时,当您使用硬盘时,文件系统可能会成为应用程序的瓶颈。除了一般的I/O延迟外,诸如碎片化和巨大的目录等问题也会明显影响您的整体请求速度。此外,请注意,Linux默认的硬盘设置更多是针对兼容性而不是速度进行调整,因此建议在使用之前进行适当配置(例如,您可以尝试使用hdparm实用程序)。
因此,在添加一个以上的集成点之前,我认为您应该调整现有的系统。通常,正确设计的数据库、配置的PHP、Memcached和静态数据处理应该足以满足高负载的网站。

嗨Vitalii。非常感谢你对这个问题的帮助和思考! - Industrial

2
我建议您首先使用memcache来处理所有重要的查询。然后,测试一下哪些查询最不常用或者数据很少发生变化,然后为此提供缓存。
如果您可以将常见数据与不常用的数据分离开来,那么您就可以集中精力改善更常用的数据的性能。

@AKRamkumar 谢谢你的帮助!这是这个问题另一个有趣的角度。 - Industrial

2

当你确定需要使用时,Memcached是一个非常有用的工具。你不必担心它会占用太多内存,因为在评估它时,你会考虑到你将要部署它的专用服务器的成本。

在大多数情况下,在共享服务器上使用memcached是浪费时间的,因为它的内存可以更好地用于缓存其他东西。

使用memcached的好处在于,您可以将其用作许多机器之间的共享缓存,从而增加命中率。此外,您可以使缓存大小和性能高于单个服务器可以提供的水平,因为您可以(通常会)在每个地理位置部署多台服务器。

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

流程如下:

  1. 识别性能问题
  2. 决定需要多少性能提升
  3. 在测试实验室中,在生产级硬件上重现问题,并使用必要的驱动程序机器 - 这是不容易的,您可能需要很多专用(甚至专业)硬件来使您的应用程序足够强大。
  4. 测试提议的解决方案
  5. 如果有效,则发布到生产环境;如果无效,则尝试更多选项并重新开始。

你不应该:

  • 缓存“所有内容”
  • 做事情而不测量它们的实际影响。

由于您的性能测试环境永远不会完美,因此您应该有足够的工具/监视器,可以在生产中测量性能并对您的应用程序进行分析。

这也意味着您缓存的每个单独的项目都应该有一个缓存命中/未命中计数器。您可以使用此来确定何时浪费了缓存。如果缓存的命中率较低(例如<90%),则可能没有必要。

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

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


嗨。我们将使用VPS来处理memcache部分,为其提供特定的盒子。但是,您认为利用基于磁盘的“不受欢迎”数据或完全依靠memcache都是错误的吗? - Industrial
1
我认为你应该使用专用的真实硬件。如果虚拟机存在性能问题,显而易见的解决方法是使用真实硬件。不要浪费开发工作并添加无意义的缓存以引入错误。将数据缓存到磁盘上通常没有用,因为如果数据已经在其他地方的磁盘上,除非另一个磁盘非常繁忙,否则它并不更加高效。磁盘IO操作需要多长时间,无论它是从缓存还是从原始位置读取数据。 - MarkR

1
你可以委托操作系统来组合磁盘/内存缓存(如果你的操作系统足够聪明)。 对于Solaris,你甚至可以在中间添加SSD层;这项技术称为L2ARC。
我建议你先阅读这篇文章:http://blogs.oracle.com/brendan/entry/test

嗨!目前看来,我们将使用CentOS。我会查看Solaris,但那将是一个完全新的需要学习的东西。我不确定我们是否可以为了从操作系统的开始重新学习而放弃那一部分...非常感谢您的帮助。您知道其他支持此功能的操作系统吗? - Industrial
1
嗯,这是你的选择...但使用Solaris可能会更便宜/更快,因为你可以免费获得缓存。而且你还能使用 ZFS,它可能是当今最好的文件系统。不幸的是,我不知道Linux有类似的东西。 - mindas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接