缓存和避免缓存走火
我们有一个非常昂贵的计算,我们想缓存。 所以我们做类似的事情:
my $result = $cache->get( $key );
unless ($result) {
$result = calculate( $key );
$cache->set( $key, $result, '10 minutes' );
}
return $result;
现在,在calculate($key)
期间,在将结果存储在缓存中之前,还有其他几个请求进来,它们也开始运行calculate($key)
,并且系统性能受到影响,因为许多进程都在计算相同的内容。
想法:让我们在缓存中放置一个正在计算值的标志,所以其他请求只是等待一个计算完成,所以它们都使用它。 就像是:
my $result = $cache->get( $key );
if ($result) {
while ($result =~ /Wait, d+ is running calculate../) {
sleep 0.5;
$result = $cache->get( $key );
}
} else {
$cache->set( $key, "Wait, $$ is running calculate()", '10 minutes' );
$result = calculate( $key );
$cache->set( $key, $result, '10 minutes' );
}
return $result;
现在,这打开了一个全新的蠕虫罐。 如果$$在设置缓存之前死亡,该怎么办? 如果......如果......所有这些都是可以解决的,但是由于CPAN中没有这样做(CPAN中的所有内容都有),我开始怀疑:
有更好的方法吗? 是否有一个特殊的原因,例如Perl的Cache
和Cache::Cache
类不提供这样的机制? 有没有一个我可以使用的尝试和真正的模式?
理想情况是CPAN模块的debian软件包已经在挤压或者尤里卡时刻,在那里我看到了我的方式错误...... :-)
编辑:我从那以后才知道这被称为缓存踩踏事件并更新了问题的标题。
flock()
它。
由于您的工作进程都在同一个系统上,因此您可以使用良好的老式文件锁定来序列化昂贵的calculate()
离子。 作为奖励,这种技术出现在几个核心文档中。
use Fcntl qw(:DEFAULT :flock); # warning: this code not tested
use constant LOCKFILE => 'you/customize/this/please';
my $result = $cache->get( $key );
unless ($result) {
# Get an exclusive lock
my $lock;
sysopen($lock, LOCKFILE, O_WRONLY|O_CREAT) or die;
flock($lock, LOCK_EX) or die;
# Did someone update the cache while we were waiting?
$result = $cache->get( $key );
unless ($result) {
$result = calculate( $key );
$cache->set( $key, $result, '10 minutes' );
}
# Exclusive lock released here as $lock goes out of scope
}
return $result;
好处:工人死亡会立即释放$lock
。
风险:LOCK_EX可以永远阻止,这是一段很长的时间。 避免使用SIGSTOPs,可能会适应alarm()
。
扩展:如果您不想序列化所有calculate()
调用,而只是调用相同的$key
或某组键,则您的工作人员可以flock()
/some/lockfile.$key_or_a_hash_of_the_key
。
使用锁定? 或者,也许这将是一个矫枉过正的? 或者如果可能的话,预先离线计算结果然后在线使用它?
虽然它可能(或可能不)对您的用例过度,但您是否考虑过使用消息队列进行处理? RabbitMQ目前似乎是Perl社区的热门选择,它通过AnyEvent :: RabbitMQ模块提供支持。
在这种情况下,基本策略是在需要calculate
新密钥时向消息队列提交请求。 然后可以将队列设置为一次只calculate
一个键(按请求的顺序),如果这是您可以可靠处理的所有内容。 或者,如果您可以同时安全地计算多个密钥,则队列还可以用于合并对同一个密钥的多个请求,计算一次并将结果返回给请求该密钥的所有客户端。
当然,这会增加一些复杂性,AnyEvent要求的编程风格有些不同于你可能习惯的(我会提供一个例子,但我从来没有真正掌握过它),但它可能会提供在效率和可靠性方面获得足够的收益,以使这些成本值得您享受
链接地址: http://www.djcxy.com/p/10801.html上一篇: Caching & avoiding Cache Stampedes
下一篇: Finite Field (Galois Field) Linear Algebra Library for C (not C++)