memcacheD这没关系?

时间:2009-09-17 06:49:24

标签: php memcached

我是memcached的新手。 此代码是否容易受到过期缓存竞争条件的影响? 你会如何改进它?

$memcache = new Memcache;
$memcache->connect('127.0.0.1');
$arts = ($memcache===FALSE) ? FALSE : $memcache->get($qparams);
if($arts===FALSE) {
    $arts=fetchdb($q, $qparams);
    $memcache->add($qparams, $arts, MEMCACHE_COMPRESSED, 60*60*24*3);
}
if($arts<>FALSE) {
    // do stuff
} else {
    // empty dataset
}
  • $ qparams包含查询的参数,因此我将其用作密钥。
  • $ arts get是一个包含每个项目所需字段的数组。

假设查询X获得100行。排在第50行之后的另一个过程(假设零售价格增加)。

  • 我应该怎么做缓存?
  • 如何知道第50行是否已缓存?
  • 我应该使缓存中的所有条目无效吗? (听起来有点矫枉过正)。

2 个答案:

答案 0 :(得分:3)

  

此代码是否容易受到过期缓存争用条件的影响?你会如何改进它?

即可。如果两个(或多个)并发客户端尝试从缓存中获取相同的密钥并最终从数据库中提取它。您将在数据库上出现峰值,并且数据库将在一段时间内处于高负载状态。这称为缓存标记。有几种方法可以解决这个问题:

  • 对于新项目预热缓存(基本上意味着您在网站上线之前预先加载了所需的对象)。
  • 对于定期过期的项目,创建一个未来的过期时间,而不是实际过期时间(比如说5-10分钟)。然后,当您从缓存中提取对象时,请检查过期时间是否已关闭,将来是否缓存以防止任何其他客户端更新缓存,以及从数据库进行更新。为了使其不使用缓存标记,您需要实现密钥锁定或使用cas令牌(需要最新的客户端库才能工作)。

有关详细信息,请查看memcached faq

  

假设查询X获得100行。 #50行后面的一点点被另一个流程修改(假设零售价格上涨)。

缓存中有三种类型的数据:

  1. 物件
  2. 对象列表
  3. 生成数据
  4. 我通常做的是将对象保持为单独的键,然后在列表中使用缓存“指针”。在你的情况下,你在缓存中的某个地方有N个objets(假设键是1,2..N),然后你有一个数组array(1,2,3,10,42...)中的对象列表。当您决定使用对象加载列表时,从缓存加载列表键,然后从缓存加载实际对象(使用getMulti来减少请求)。在这种情况下,如果任何对象得到更新,您只能在一个位置更新它,并且它会在任何地方自动更新(更不用说使用此技术可以节省大量空间)。

    修改:决定添加更多关于前瞻时间到期的信息。

    使用过期数据x设置对象,并将其保存到数据库中,其过期日期为x+5minutes。这是从缓存加载对象时执行的步骤:

    1. 检查是否需要更新(time() - x < 0
    2. 如果是这样,请锁定密钥,以便在刷新项目时没有人可以更新它。如果您无法锁定密钥,那么其他人已经在更新密钥,它就变成了SEP(Somebody Else的问题)。由于memcached没有锁的解决方案,因此您必须设计自己的机制。我通常通过在末尾添加一个单独的键和原始键值+ ":lock"来完成此操作。您必须将此密钥设置为以尽可能短的数量到期(对于1秒的memcached)。
    3. 如果您获得了密钥的锁定,则首先使用新的到期时间保存对象(这样您确定没有其他客户端会尝试锁定密钥),然后开始您的业务并更新密钥数据库并使用适当的超前期限再次保存新值(请参阅第1点)。
    4. 希望这能解决所有问题:)

答案 1 :(得分:1)

您必须使包含已修改项目的任何缓存对象无效。您必须修改缓存机制以更细粒度级别存储项目,或使整个条目无效。

这与说你在一个缓存条目中缓存整个数据库基本相同。你要么已经过期,要么没有过期。