webiny / hrc
基于进入的HTTP请求的缓存规则进行缓存的缓存管理层。
Requires
- php: >=7
- webiny/mongo: ~1.6 || dev-master
Requires (Dev)
- mybuilder/phpunit-accelerator: dev-master
- phpunit/phpunit: ~4
README
这是一个提供围绕您的缓存的控制机制的缓存管理系统。缓存与进入的HTTP请求相关联。实际上,这意味着您可以根据请求路径、cookies、发送的头部、查询字符串和一些自定义回调的组合来创建缓存。
...但我使用memcache(或redis)
当然,但这不是一个缓存管理系统,而只是一个存储...管理缓存需要很多知识,这不是一件容易的事情(特别是使用memcache)。
比我聪明得多的人曾经说过
在计算机科学中,只有两件困难的事情:缓存失效和命名事物。
-- Phil Karlton
您仍然可以使用memcache、redis或其他您想要的任何缓存存储系统,只需为其创建一个驱动程序并将其连接到Hrc。(请参阅下面的指南)
安装
composer require webiny/hrc
需要PHP 7.0或更高版本。
工作原理
// define cache rules $cacheRules = [ 'FooBar' => [ 'Ttl' => 60, 'Tags' => ['cacheAll'], 'Match' => [ 'Url' => '*' ] ] ]; // where and how to store cache files $cacheStorage = new Webiny\Hrc\CacheStorage\FileSystem('/path/to/cache/folder/'); // where and how to keep a record of all stored cache files $indexStorage = new Webiny\Hrc\IndexStorage\FileSystem('/path/to/index/folder'); // create Hrc instance $hrc = new Hrc($cacheRules, $cacheStorage, $indexStorage); // store something into cache $hrc->save('entryName', 'some content'); // retrieve something from cache $data = $hrc->read('entryName'); // some content
1. 定义一组缓存规则
缓存规则定义了如何以及是否可以缓存某物。例如,一个简单的缓存规则看起来像这样
$cacheRules = [ 'SimpleRule' => [ 'Ttl' => 60, 'Tags' => ['simple', 'rule'], 'Match' => [ 'Url' => '/some/*' ] ], ];
Ttl
(生存时间)定义了该条目应在缓存中保留多长时间。
Tags
用于标记内容,以便您可以更容易地使其失效。
Match
是一组匹配标准,规则需要满足这些标准,您才能存储内容。它们还定义了用于创建缓存键的内容。
匹配标准
您可以在匹配标准中使用几个不同的东西
- URL路径
- 查询字符串
- 请求头部
- cookies
- 自定义回调
匹配选项
true
:参数需要存在,但只有参数名,而不是其值,将用于缓存键。false
:参数必须未设置,规则才能匹配。*
:参数需要存在,并且需要具有某些值,其值将用于缓存键。?
:参数是可选的,如果存在,则其值将用于缓存键。- 任何PHP正则表达式
preg_match
标准 - 任何固定字符串用于精确匹配
以下是一些匹配示例
$mockRules = [ 'AdvancedMatch' => [ 'Ttl' => 100, 'Tags' => ['advanced', 'one'], 'Match' => [ 'Url' => '/simple/url/([\w]+)/page/([\d]+)/(yes|no)/', 'Cookie' => [ 'X-Cart' => 'cart value (\d+) currency ([\w]{2})', 'X-CacheByCookie' => 'yes' ], 'Header' => [ 'X-Cache-Me' => 'foo (\w+)', 'X-Cache-Header' => '*' ], 'Query' => [ 'Cache' => true, 'foo' => ? ], 'Callback' => [ 'Webiny\Hrc\UnitTests\CacheRules\MockCallbacks::returnValue' ] ] ] ];
在Callback
部分中,用于调用自定义回调,这基本上是对匹配规则的扩展。回调方法应返回一个值,该值将用于构建缓存键。如果回调返回布尔值false
,则规则将不匹配请求。
回调方法接受两个参数,分别是Webiny\Hrc\Request
和Webiny\Hrc\CacheRules\CacheRule\CacheRule
class MockCallbacks { public static function returnTrue(Webiny\Hrc\Request $r, Webiny\Hrc\CacheRules\CacheRule\CacheRule $cr) { // do you thing here } }
尽管不推荐,但您可以在Cookie
、Header
和Query
上不严格指定匹配选项,而是将一个*
放在那里,以简单地取所有接收到的参数(例如,所有查询参数),并为请求的任何变化构建一个缓存键。
$mockRules = [ 'GetAllParameters' => [ 'Ttl' => 86400, 'Tags' => ['global', 'all'], 'Match' => [ 'Url' => '/match/all', 'Cookie' => '*', 'Header' => '*', 'Query' => '*' ] ] ];
2. 缓存存储
Hrc设计成可以存储您想要的任何存储中的缓存,从memcache到mongodb。默认情况下,我们提供了文件系统存储和MongoDb。如果您为任何其他存储机制编写了驱动程序,请发送拉取请求,我们将很乐意将其合并。
创建存储驱动程序相当简单,只需创建一个类并实现Webiny\Hrc\CacheStorage\CacheStorageInterface
。您只需实现3个简单的方法即可完成任务。
3. 索引存储
索引存储用于存储额外的缓存信息,你可以将其视为缓存元数据和分类法的组合。索引主要用于实现更广泛的缓存失效功能和更快的缓存失效时间。
默认情况下,我们提供文件系统缓存索引和MongoDb缓存索引,要创建自定义的索引,只需实现Webiny\Hrc\IndexStorage\IndexStorageInterface
。
Mongo存储和索引
如果你计划使用Mongo
缓存存储和缓存索引,确保在使用驱动程序之前运行installCollections
方法,否则不会创建所需的索引,性能会变慢。
$this->cacheStorage->installCollections(); $this->indexStorage->installCollections();
你只需运行一次。另一种方法是通过手动创建两个集合和索引
HrcCacheStorage
集合应具有以下索引key
=> 在key
字段上创建唯一索引,sparse应设置为falsettl
=> 在ttl
字段上创建索引,expireAfterSeconds设置为0秒
HrcIndexStorage
集合应具有以下索引key
=> 在key
字段上创建唯一索引,sparse应设置为falsetags
=> 在tags
字段上创建索引ttl
=> 在ttl
字段上创建索引,expireAfterSeconds设置为0秒
4. 匹配缓存规则
当你调用read
或save
方法时,如果你没有提供缓存规则的名称,类将遍历所有定义的缓存规则,并选择第一个与请求匹配的规则。但是,如果你提供了缓存规则名称,缓存规则匹配模式仍然必须匹配,但检查将仅针对该特定规则进行。通过提供缓存规则名称,你可以在同一HTTP请求内匹配多个缓存规则。
// use the first matched cache rule $hrc->save('entryName', 'some content'); $data = $hrc->read('entryName'); // use fooBar cache rule $hrc->save('block 122', 'some content', 'fooBar'); $data = $hrc->read('block 122');
5. 回调
支持两种主要的回调事件
beforeSave(SavePayload)
afterSave(SavePayload)
beforeRead(ReadPayload)
afterRead(ReadPayload)
要为这些事件注册回调,创建一个实现\Webiny\Hrc\EventCallbackInterface
的类。你将不得不实现所有回调方法。两个save方法都接收1个参数,即SavePayload
实例。该实例包含有关即将创建或已创建的当前缓存条目的所有相关数据。对于读取方法也是类似的,它们接收ReadPayload
实例,它让你可以访问当前缓存条目以及设置清除标志的选项,这样内容实际上被清除而不是从数据库检索。
回调方法不需要返回任何内容,但由于SavePayload
实例是一个对象,在beforeSave
中你可以使用它来操作你的缓存条目,例如更改缓存内容、添加或删除标签等。在afterSave
回调中,你会得到相同的对象,但这只是一个确认对象已成功保存。
// your Hrc instance $hrc = new Hrc($cacheRules, $cacheStorage, $indexStorage); // my callback handler -> must implement \Webiny\Hrc\EventCallbackInterface $handler = new MyCallbackHandler(); // register callbacks $hrc->registerCallback($handler);
缓存清除
你可以通过几种方式清除缓存
通过缓存键清除
当你保存缓存条目时,保存方法将返回一个缓存键,使用该键,你可以清除该特定的条目
// save the cache and get back the cache key $key = $hrc->save('entryName', 'some content'); // purge that cache entry $hrc->purgeByCacheKey($key);
通过标签清除
每个缓存规则都关联一个或多个标签。使用相同的标签,你可以清除多个缓存条目。注意:在提供多个标签时,只有匹配所有标签的条目将被清除,或者换句话说,我们在标签之间使用逻辑AND条件。
$hrc->purgeByTag(['tag1', 'tag2']);
通过请求清除
你可以设置一个标志,以便当前请求中匹配的每个缓存条目都将自动被清除。
// first set the purge flag to true $hrc->setPurgeFlag(true); // once the flag is set to true, every `read` call, that has a cache hit, will actually do a purge $hrc->read('entryName');
另一种方法是,在你的请求中发送一个特殊的请求头。该头是X-HRC-Purge
,只需定义它,不需要设置任何值。发送该头具有将清除标志设置为true相同的效果,但这种方式不需要设置标志,并且实际上仅对特定请求有效。
安全性
基于上一节的内容,你可能认为存在很大的风险,因为每个人都可以在每次请求时清除缓存并击中你的数据库/后端...这是真的,但有一个内置的机制来防止这种情况。你可以设置一个控制键
,这样只有带有有效键的请求才能通过头部清除缓存。
// set the control header $hrc->setControlKey('someSecretString');
一旦设置了控制头部,你现在需要发送一个包含相同值的X-HRC-Control-Key
请求头部。只有当这两个值匹配时,清除请求才会执行。
错误和改进
只需在问题下报告它们,或者更好的是,发送一个拉取请求:)
许可证
MIT
资源
要运行单元测试,你需要使用以下命令
$ cd path/to/Webiny/Hrc/
$ composer install
$ phpunit