memcacheD这没关系?

The*_*tor 5 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
}
Run Code Online (Sandbox Code Playgroud)
  • $ qparams包含查询的参数,因此我将其用作密钥.
  • $ arts get是一个包含每个项目所需的所有字段的数组.

假设查询X得到100行.排在第50行之后的另一个过程(假设零售价格上涨).

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

Mih*_*bar 3

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

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

  • 对于新项目预热缓存(基本上意味着您在站点上线之前预加载所需的对象)。
  • 对于定期过期的项目,创建一个比实际过期时间晚一点的过期时间(假设 5-10 分钟)。然后,当您从缓存中提取对象时,检查过期时间是否接近,缓存到未来以防止任何其他客户端更新缓存,并从数据库进行更新。为了在没有缓存踩踏的情况下工作,您需要实现密钥锁定或使用 cas 令牌(需要最新的客户端库才能工作)。

有关更多信息,请查看memcached 常见问题解答

假设查询 X 获取 100 行。不久后,第 50 行被另一个进程修改(假设零售价格增加)。

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

  1. 对象
  2. 对象列表
  3. 生成的数据

我通常做的是将对象保留为单独的键,然后在列表中使用缓存“指针”。在您的情况下,您在缓存中的某处有 N 个对象(假设键是1,2..N),然后您在 array 中拥有对象列表array(1,2,3,10,42...)。当您决定加载包含对象的列表时,您可以从缓存加载列表键,然后从缓存加载实际对象(用于getMulti减少请求)。在这种情况下,如果任何对象被更新,您只在一个位置更新它,并且它会在所有地方自动更新(更不用说使用这种技术可以节省大量空间)。

编辑:决定添加更多有关前瞻时间到期的信息。

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

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

希望这能澄清一切:)