sobstel/metaphore

使用信号量进行PHP缓存击穿防御,以防止击狗效应(也称为覆盖更新或羊群效应)。

资助软件包维护!
Ko Fi

v2.0.1 2024-02-24 11:37 UTC

README

使用信号量进行PHP缓存击穿防御,以防止击狗效应(也称为覆盖更新、羊群效应或Slashdot效应)。

问题:当网站尝试重新生成相同内容并击中数据库时,同时有太多请求,例如缓存过期时。

解决方案:第一个请求生成新内容,而所有后续请求在第一次请求刷新之前都从缓存获取(陈旧)的内容。

阅读 http://www.sobstel.org/blog/preventing-dogpile-effect/ 了解更多详情。

Buy Me a Coffee at ko-fi.com

安装

在 composer.json 文件中

"require": {
  "sobstel/metaphore": "2.0.*"
}

或直接 composer require sobstel/metaphore

用法

use Metaphore\Cache;
use Metaphore\Store\MemcachedStore;

// initialize $memcached object (new Memcached())

$cache = new Cache(new MemcachedStore($memcached));
$cache->cache('key', function() {
    // generate content
}, 30);

公共API(方法)

  • __construct(ValueStoreInterface $valueStore, LockManager $lockManager = null)

  • cache($key, callable $callable, [$ttl, [$onNoStaleCacheCallable]]) - 返回结果

  • delete($key)

  • getValue($key) - 返回值对象

  • setResult($key, $result, Ttl $ttl) - 设置结果(不使用抗击狗效应机制)

  • onNoStaleCache($callable)

  • getValueStore()

  • getLockManager()

值存储与锁存储

缓存值和锁可以由不同的存储处理。

$valueStore = new Metaphore\MemcachedStore($memcached);

$lockStore = new Your\Custom\MySQLLockStore($connection);
$lockManager = new Metaphore\LockManager($lockStore);

$cache = new Metaphore\Cache($valueStore, $lockManager);

默认情况下 - 如果没有传递第二个参数给Cache构造函数 - 值存储用作锁存储。

示例用例可能是使用自定义MySQL GET_LOCK/RELEASE_LOCK进行锁操作,同时使用内置的Memcached存储来存储值。

生存时间

您可以传递简单的整数值...

$cache->cache('key', callback, 30); // cache for 30 secs

...或使用更高级的 Metaphore\TTl 对象,它让您控制宽限期和锁生存时间。

// $ttl, $grace_ttl, $lock_ttl
$ttl = new Ttl(30, 60, 15);

$cache->cache('key', callback, $ttl);
  • $ttl - 正常缓存时间(以秒为单位)
  • $grace_ttl - 宽限期,允许在生成新内容的同时提供陈旧内容的时间(以秒为单位),类似于HTTP的stale-while-revalidate,默认为60秒
  • $lock_ttl - 锁定时间,防止其他请求生成相同内容的时间,默认为5秒

将Ttl值添加到当前时间戳(time() + $ttl)。

无陈旧缓存

在罕见情况下,当缓存过期且没有可用的陈旧(之前生成)内容时,所有请求都将开始生成新内容。

您可以添加监听器来捕获此情况

$cache->onNoStaleCache(function (NoStaleCacheEvent $event) {
    Logger::log(sprintf('no stale cache detected for key %s', $event->getKey()));
});

您还可以影响返回的值

$cache->onNoStaleCache(function (NoStaleCacheEvent $event) {
    $event->setResult('new custom result');
});

测试

运行所有测试:phpunit

如果没有安装memcached或redis:phpunit --exclude-group=notisolatedphpunit --exclude-group=memcached,redis