使用Memcached:在更新数据库时更新缓存是一种好习惯吗?


13

这个问题是关于架构的最佳实践。

我们目前的架构

我有一个PHP类,可访问MySQL获取用户信息。叫它UserUser可以多次访问,因此我们实现了缓存层以减少负载。

第一层是我们所谓的“每个请求”缓存。从MySQL检索数据后,我们将数据存储在的私有属性中User。任何后续的数据请求都返回该属性,而不是从MySQL重新请求数据。

由于Web请求是根据每个请求生存和终止的,因此此缓存仅阻止应用程序在单个请求中多次访问MySQL。

我们的第二层是Memcached。当私有属性为空时,我们首先检查Memcached中的数据。如果Memcached为空,我们向MySQL查询数据,更新Memcached,然后更新的private属性User

问题

我们的应用程序是一个游戏,有时必须使某些数据尽可能最新。在大约五分钟的时间内,对用户数据的读取请求可能会发生10到11次;那么可能会发生更新。随后的读取请求必须是最新的,否则游戏机制将失败。

因此,我们要做的是实现在数据库更新发生时执行的一段代码。此代码使用更新的数据在Memcached中设置密钥,因此所有后续对Memcached的请求都是最新的。

这是最优的吗?在尝试维护此类“活动缓存”时,是否应注意性能问题或其他“陷阱”?


这与删除和重新添加数据有什么关系?
Mike Nakis 2011年

阐明了问题标题。
斯蒂芬

为什么不只是使缓存的数据过期?更新意味着您需要确保更新得以维护(因此,如果需要以这种方式更新新数据,则必须继续更改更新)。缓存过期意味着所有内容都是从数据库中新提取的,并且任何新的更新都不需要对更新代码进行新的更改。缺点是数据库负载可能更高。
Peter K.

@Peter Yeah,我们也考虑过这一点。如果目前的方法没有其他问题,我们将坚持下去。否则,我们可能会按照您的描述进行操作。
斯蒂芬,

1
@Stephen您描述的方法称为“通过缓存写入”,这是一种相当普遍的方法。
Sripathi Krishnan 2012年

Answers:


10

我的建议是查看您的使用情况配置文件和对缓存的要求。

我看不出有任何理由将过时的数据保留在memcached中。我认为您选择了正确的方法,即:更新数据库。

无论如何,您将需要在数据库更新上使用包装器(已完成)。您用于更新数据库和内存中用户的代码也应该推送到memcached,或者在memcached中到期。

例如-如果您的用户通常在注销时每个会话进行一次更新,则更新缓存中的数据没有多大意义(例如,总分较高)-您应立即使它过期。

但是,如果他们要更新数据(例如当前游戏状态),然后在0.2秒后立即有一个PHP页面命中请求数据,那么您希望它在缓存中新鲜。


3

我不会像您概述的那样去做。您需要做的是确定您是否实际上需要完整的最新数据。然后,如果确实需要它,请确定始终需要更新数据的哪些部分,并将它们与可以在体系结构中缓存的内容分开。

例如,您可能希望用户更改电子邮件地址后立即对其进行更新,因此您不会将邮件发送到错误的地址,但是用户的出生日期或姓氏不太可能需要完整最新,以提供体面的用户体验。(注意,我不使用游戏架构示例,因为我不知道该游戏针对的是哪种游戏,我认为这很容易理解)。

这样,您将获得两组清晰的数据集:短期和长期可缓存数据。您也许可以在短期数据上保留大约一分钟的缓存时间,这只是为了减轻数据库上的负载,但是长期数据可以在滑动时间内保留在缓存中用过的。

然后,您需要处理更新。首先,我将看一下使用DB触发器来将过期的项目从缓存中简单地删除。这将迫使您的业务层在下次请求数据时触发高速缓存刷新,如果未使用数据(例如,如果用户更改了电子邮件地址然后立即注销),则释放高速缓存中的一些空间。 。如果这将导致UI性能问题(例如,在等待缓存刷新时引入过多的延迟),则可以将项目从缓存中删除后简单地触发缓存调用。我还将研究如何针对这一小数据集优化数据库读取时间,以确保在刷新高速缓存时引起的任何延迟都最小(这应该更容易,因为您只需要加载真正需要的数据)。

在任何情况下,我都不会添加填充缓存的其他方法,因为那样您将需要在两个位置维护调用(和API挂钩等)。

至于陷阱,如果要直接写入缓存,则需要注意的主要事情是同步。如果您在执行静默更新时尝试读取多个线程,则可能会遇到一些严重的无效数据问题,这将使尝试首先保持数据最新的观点成为现实。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.