php - memcacheD 这个可以吗?

标签 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 得到一个数组,其中包含每个项目所需的所有字段。

假设查询 X 获得 100 行。在第 50 行被另一个进程修改后不久(假设零售价上涨)。

  • 我应该如何处理缓存?
  • 我怎么知道第 50 行被缓存了?
  • 我应该使缓存中的所有条目都无效吗? (对我来说听起来有点矫枉过正)。

最佳答案

Is this code vulnerable to the expired cache race condition? How would you improve it?

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

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

有关更多信息,请查看 memcached faq .

Let's say that query X gets 100 rows. A little after row #50 is modified by another process (lets say that the retail price gets increased).

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

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

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

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

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

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

希望这一切都清楚了:)

关于php - memcacheD 这个可以吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1437105/

相关文章:

php - 维基百科使用了什么样的缓存机制?

memcached - 是否有带有 Couchbase memcached 存储桶的代理?

php - 使用wordpress在外部数据库上创建用户

php - 使用 Twilio 发送短信后获取短信费用

php - MySQLi中如何检查表是否存在?

python - 使用 memcached.sock 路径连接到 python-memcached

go - Memcached Kubernetes 客户端 Golang

php - 我们可以在没有 require 或 include 的情况下导入另一个命名空间吗?

php - 从 jplayer 的 mysql 数据库获取 URL

memcached - 有哪些有用的提示/工具可用于监控/调整 memcached 运行状况?