kadokweb / scrapbook
Scrapbook 是一个 PHP 缓存库,具有适配器,例如 Memcached、Redis、Couchbase、APC(u)、SQL 以及在底层构建的附加功能(例如事务、雪崩保护)。
Requires
- php: >=5.3.0
- psr/cache: ~1.0
- psr/simple-cache: ~1.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ~2.0
- phpunit/phpunit: >=4.8
Suggests
- ext-apc: >=3.1.1
- ext-couchbase: >=2.0.0
- ext-memcached: >=2.0.0
- ext-pdo: >=0.1.0
- ext-redis: >=2.2.0 || 0.0.0.0
- league/flysystem: ~1.0
Provides
This package is auto-updated.
Last update: 2024-09-14 20:41:50 UTC
README
文档: https://www.scrapbook.cash - API 参考: https://docs.scrapbook.cash
目录
安装与使用
如果您使用 Composer 来管理项目的依赖关系,只需在 composer.json 文件中添加 kadokweb/scrapbook 依赖即可
composer require kadokweb/scrapbook
具体的启动将取决于您想使用的适配器、功能和接口,所有这些都在下面详细说明。
此库以层的形式构建,所有层都是 KeyValueStore 实现,如果您想添加更多功能,可以相互包装。
这里有一个简单的示例:一个带有雪崩保护的基于 Memcached 的 psr/cache。
// create \Memcached object pointing to your Memcached server $client = new \Memcached(); $client->addServer('localhost', 11211); // create Scrapbook KeyValueStore object $cache = new \KadokWeb\Scrapbook\Adapters\Memcached($client); // create stampede protector layer over our real cache $cache = new \KadokWeb\Scrapbook\Scale\StampedeProtector($cache); // create Pool (psr/cache) object from cache engine $pool = new \KadokWeb\Scrapbook\Psr6\Pool($cache); // get item from Pool $item = $pool->getItem('key'); // get item value $value = $item->get(); // ... or change the value & store it to cache $item->set('updated-value'); $pool->save($item);
只需查看此 "构建您的缓存" 部分,即可生成您想使用的确切配置(适配器、接口、功能)和一些示例代码。
适配器
Memcached
Memcached 是一种内存中的键值存储,用于存储来自数据库调用、API 调用或页面渲染结果的小块任意数据(字符串、对象)。
使用 PECL Memcached 扩展 来与 Memcached 服务器进行接口。只需向 Memcached 适配器提供有效的 \Memcached
对象即可
// create \Memcached object pointing to your Memcached server $client = new \Memcached(); $client->addServer('localhost', 11211); // create Scrapbook KeyValueStore object $cache = new \KadokWeb\Scrapbook\Adapters\Memcached($client);
Redis
Redis 通常被称为数据结构服务器,因为键可以包含字符串、散列、列表、集合、有序集合、位图和 HyperLogLogs。
使用 PECL Redis 扩展 来与 Redis 服务器进行接口。只需向 Redis 适配器提供有效的 \Redis
对象即可
// create \Redis object pointing to your Redis server $client = new \Redis(); $client->connect('127.0.0.1'); // create Scrapbook KeyValueStore object $cache = new \KadokWeb\Scrapbook\Adapters\Redis($client);
Couchbase
设计以满足关键任务应用程序的弹性可伸缩性、一致的高性能、始终在线可用性和数据移动性要求。
使用 PECL Couchbase 扩展 来与 Couchbase 服务器进行接口。只需向 Couchbase 适配器提供有效的 \CouchbaseBucket
对象即可
// create \CouchbaseBucket object pointing to your Couchbase server $cluster = new \CouchbaseCluster('couchbase://localhost'); $bucket = $cluster->openBucket('default'); // create Scrapbook KeyValueStore object $cache = new \KadokWeb\Scrapbook\Adapters\Couchbase($bucket);
APC(u)
APC 是一个免费的 PHP 开源 opcode 缓存。其目标是提供一个免费、开源和健壮的框架来缓存和优化 PHP 中间代码。
使用 APC,没有“缓存服务器”,数据只是缓存在执行机器上,对该机器上的所有 PHP 进程都可用。可以使用 PECL APC 或 APCu 扩展。
// create Scrapbook KeyValueStore object $cache = new \KadokWeb\Scrapbook\Adapters\Apc();
MySQL
MySQL是全球最受欢迎的开源数据库。MySQL可以以较低的成本帮助您提供高性能、可扩展的数据库应用程序。
虽然数据库不是真正的缓存,但它也可以用作键值存储。只是不要期望获得与专用缓存服务器相同类型的性能。
但是,使用基于数据库的缓存可能有很好的理由:如果您已经使用数据库,那么它可能会带来其他好处(如持久存储、复制)。
// create \PDO object pointing to your MySQL server $client = new PDO('mysql:dbname=cache;host=127.0.0.1', 'root', ''); // create Scrapbook KeyValueStore object $cache = new \KadokWeb\Scrapbook\Adapters\MySQL($client);
PostgreSQL
PostgreSQL拥有经过验证的架构,这使它在可靠性、数据完整性和正确性方面享有良好声誉。
虽然数据库不是真正的缓存,但它也可以用作键值存储。只是不要期望获得与专用缓存服务器相同类型的性能。
但是,使用基于数据库的缓存可能有很好的理由:如果您已经使用数据库,那么它可能会带来其他好处(如持久存储、复制)。
// create \PDO object pointing to your PostgreSQL server $client = new PDO('pgsql:user=postgres dbname=cache password='); // create Scrapbook KeyValueStore object $cache = new \KadokWeb\Scrapbook\Adapters\PostgreSQL($client);
SQLite
SQLite是一个实现自包含、无服务器、零配置、事务性SQL数据库引擎的软件库。
虽然数据库不是真正的缓存,但它也可以用作键值存储。只是不要期望获得与专用缓存服务器相同类型的性能。
// create \PDO object pointing to your SQLite server $client = new PDO('sqlite:cache.db'); // create Scrapbook KeyValueStore object $cache = new \KadokWeb\Scrapbook\Adapters\SQLite($client);
文件系统
虽然在I/O访问时间方面不是最快的缓存类型,但打开文件通常仍然比重新执行昂贵的计算要好。
基于文件系统的适配器使用league\flysystem
来抽象文件操作,并且可以与league\filesystem
提供的所有类型的存储一起工作。
// create Flysystem object $adapter = new \League\Flysystem\Adapter\Local('/path/to/cache', LOCK_EX); $filesystem = new \League\Flysystem\Filesystem($adapter); // create Scrapbook KeyValueStore object $cache = new \KadokWeb\Scrapbook\Adapters\Flysystem($filesystem);
内存
PHP也可以在内存中保存数据!作为存储的PHP数组对于运行测试特别有用,因为您不需要安装任何其他服务。
将值存储在内存中通常是没有用的:它们将在请求结束时消失。除非您在同一个请求中多次使用这些缓存值,否则缓存总是空的,几乎没有使用这个缓存的理由。
然而,在单元测试时非常有用:您可以在基于内存的存储上运行整个测试套件,而不是设置缓存服务并确保它们处于原始状态...
// create Scrapbook KeyValueStore object $cache = new \KadokWeb\Scrapbook\Adapters\MemoryStore();
特性
除了默认的缓存功能(如get
和set
)之外,Scrapbook还提供了一些小巧的额外功能。这些功能都实现在自己的小对象中,该对象实现了KeyValueStore,并包装在KeyValueStore周围。换句话说,任何功能都可以简单地包装在另一个功能内部或任何适配器之上。
本地缓冲区
BufferedStore有助于减少对您的真实缓存的请求。如果您需要请求相同的值多次(来自代码中的多个地方),保持该值可能会很痛苦。再次从缓存中请求它会更简单,但这样您会从缓存服务器连接中遇到一些延迟。
BufferedStore将已知值(您已经请求或自己编写的项目)保留在内存中。每次您在同一请求中需要该值时,它将直接从内存中获取,而不是访问缓存服务器。
只需将BufferedStore层包装在您的适配器(或其他功能)周围即可。
// create buffered cache layer over our real cache $cache = new \KadokWeb\Scrapbook\Buffered\BufferedStore($cache);
事务
TransactionalStore使得在未来的某个时间点延迟写入成为可能。类似于数据库中的事务,所有延迟的写入可以一次回滚或提交,以确保存储的数据是可靠和完整的。要么全部存储,要么什么也不存储。
您可能希望在整个代码库中处理代码,但直到一切都已成功验证并写入永久存储,您才提交更改。
在事务内部,您不必担心数据一致性。在事务内部,即使它尚未提交,您也始终会得到您打算存储的那个值。换句话说,当您将新值写入缓存但尚未提交时,您查询时仍然会得到该值。如果您回滚或未能提交(因为另一个过程存储的数据导致您的提交失败),那么您将得到缓存中的原始值,而不是您打算提交的值。
只需将TransactionalStore层包装在您的适配器(或其他功能)周围即可。
// create transactional cache layer over our real cache $cache = new \KadokWeb\Scrapbook\Buffered\TransactionalStore($cache);
然后,您就可以使用事务了!
// begin a transaction $cache->begin(); // set a value // it won't be stored in real cache until commit() is called $cache->set('key', 'value'); // returns true // get a value // it won't get it from the real cache (where it is not yet set), it'll be read // from PHP memory $cache->get('key'); // returns 'value' // now commit write operations, this will effectively propagate the update to // 'key' to the real cache $cache->commit(); // ... or rollback, to discard uncommitted changes! $cache->rollback();
雪崩保护
缓存竞态是指当大量请求需要当前不在缓存中的数据时,导致大量并发复杂操作。例如
- 缓存过期导致经常承受重负载的数据
- 对可能不在缓存中的数据的突发意外高负载
在这些情况下,此时大量请求非缓存数据导致昂贵的操作被多次执行,同时进行。
StampedeProtector旨在对抗这种现象。如果一个值在缓存中找不到,将存储一个占位符以指示已请求但不存在。随后的一段时间内的所有后续请求都会发现这个指示,并知道另一个进程已经在生成该结果,所以这些请求将等待它变得可用,而不是使服务器崩溃。
只需将StampedeProtector层包装在你的适配器(或其它特性)周围
// create stampede protector layer over our real cache $cache = new \KadokWeb\Scrapbook\Scale\StampedeProtector($cache);
分片
当你有太多的数据(或请求)无法由1个小服务器处理时,这将允许你在多个缓存服务器之间进行分片。所有数据将自动均匀分布到你的服务器池中,所以每个单独的缓存服务器只会获得一部分数据和流量。
将构成缓存服务器池的单独KeyValueStore对象传递给此构造函数,数据将根据传递给此构造函数的缓存服务器的顺序进行分片(因此请确保始终保持相同的顺序。)
分片是均匀分配的,所有缓存服务器将大致接收相同数量的缓存键。如果某些服务器比其他服务器大,你可以通过多次添加该缓存服务器的KeyValueStore对象来抵消这种差异。
数据甚至可以在不同的适配器之间分片:分片池中的一个服务器可以是Redis,而另一个可以是Memcached。不确定你为什么要这样做,但你确实可以这样做!
只需将Shard层包装在你的适配器(或其它特性)周围
// boilerplate code example with Redis, but any // KadokWeb\Scrapbook\KeyValueStore adapter will work $client = new \Redis(); $client->connect('192.168.1.100'); $cache1 = new \KadokWeb\Scrapbook\Adapters\Redis($client); // a second Redis server... $client2 = new \Redis(); $client2->connect('192.168.1.101'); $cache2 = new \KadokWeb\Scrapbook\Adapters\Redis($client); // create shard layer over our real caches // now $cache will automatically distribute the data across both servers $cache = new \KadokWeb\Scrapbook\Scale\Shard($cache1, $cache2);
接口
Scrapbook支持3种不同的接口。有Scrapbook特定的KeyValueStore,然后是PHP FIG提出的2个PSR接口。
KeyValueStore
KeyValueStore是这个项目的基石。它是提供最多缓存操作的接口:get
、getMulti
、set
、setMulti
、delete
、deleteMulti
、add
、replace
、cas
、increment
、decrement
、touch
和flush
。
如果你之前使用过Memcached,KeyValueStore看起来会非常相似,因为它受到了那个API的启发/仿照。
所有适配器和特性都实现了此接口。如果你有复杂的缓存需求(例如能够cas
),你应该坚持使用这个接口。
KeyValueStore接口及其方法的详细列表可以在文档中找到。
psr/cache
PSR-6(一个PHP-FIG标准)与KeyValueStore和psr/simple-cache相比,是一个截然不同的缓存模型:psr/cache不是直接从缓存中查询值,而是基本上在值对象(Item
)上操作以执行更改,然后将更改反馈到缓存(Pool
。)
它不允许你执行太多的操作。如果你只需要get
、set
、delete
(及其多版本)和delete
,你可能更适合使用这个(或psr/simple-cache,见下文),因为这个接口也由其他缓存库支持。
你可以通过将其包装在任何KeyValueStore对象周围轻松地使用psr/cache。
// create Pool object from Scrapbook KeyValueStore object $pool = new \KadokWeb\Scrapbook\Psr6\Pool($cache); // get item from Pool $item = $pool->getItem('key'); // get item value $value = $item->get(); // ... or change the value & store it to cache $item->set('updated-value'); $pool->save($item);
PSR-6 接口及其方法的详细列表可以在文档中找到。
psr/simple-cache
PSR-16(一个PHP-FIG标准)是第二个PHP-FIG缓存标准。它是一个驱动模型,就像KeyValueStore一样,并且以非常相似的方式工作。
它不会让您执行太多操作。如果您只需要get
、set
、delete
(及其多版本)和delete
,那么您可能更愿意使用此(或psr/cache,见上文),因为这个接口也受到其他缓存库的支持。
您可以通过将任何KeyValueStore对象包装在psr/simple-cache周围来轻松使用psr/simple-cache。
// create Simplecache object from Scrapbook KeyValueStore object $simplecache = new \KadokWeb\Scrapbook\Psr16\SimpleCache($cache); // get value from cache $value = $simplecache->get('key'); // ... or store a new value to cache $simplecache->set('key', 'updated-value');
PSR-16接口及其方法的详细列表可以在文档中找到。
集合
集合,或者如果您愿意,是隔离的缓存子集,只会提供对特定上下文中值的访问。
无法跨集合设置/获取数据。在两个不同的集合中设置相同的键将存储两个不同的值,这些值只能从它们各自的集合中检索。
清除集合只会清除那些特定的键,并且不会触及其他集合中的键。
然而,清除服务器将擦除一切,包括该服务器上任何集合中的数据。
这里有一个简单的例子
// let's create a Memcached cache object $client = new \Memcached(); $client->addServer('localhost', 11211); $cache = new \KadokWeb\Scrapbook\Adapters\Memcached($client); $articleCache = $cache->collection('articles'); $sessionCache = $cache->collection('sessions'); // all of these are different keys $cache->set('key', 'value one'); $articleCache->set('key', 'value two'); $sessionCache->set('key', 'value three'); // this clears our the entire 'articles' subset (thus removing 'value two'), // while leaving everything else untouched $articleCache->flush(); // this removes everything from the server, including all of its subsets // ('value one' and 'value three' will also be deleted) $cache->flush();
getCollection
在所有KeyValueStore实现上都是可用的(因此对于可能围绕它包装的每个适配器和功能),并且还返回一个KeyValueStore对象。虽然它不是PSR接口的一部分,但您可以先创建您的集合,然后将所有集合都包装在它们自己的psr/cache或psr/simple-cache表示中,如下所示
$articleCache = $cache->collection('articles'); $sessionCache = $cache->collection('sessions'); // create Pool objects from both KeyValueStore collections $articlePool = new \KadokWeb\Scrapbook\Psr6\Pool($articleCache); $sessionPool = new \KadokWeb\Scrapbook\Psr6\Pool($sessionCache);
兼容性
尽可能,Scrapbook支持从PHP 5.3到当前版本的所有PHP版本,以及HHVM。这些版本和平台之间缓存后端的实现差异将在Scrapbook中得到缓解,以确保一致的行为。
在Travis CI上使用官方PHP Docker镜像测试了所有这些版本和平台的兼容性,这意味着尽管这些版本由Scrapbook支持,但PHP≤5.5已不再积极测试。
没有特定版本或平台实现(在较旧的PHP版本中的Flysystem)的缓存后端显然不受支持。
与旧软件版本的兼容性不会轻易被打破。除非有充分的理由,如安全或性能影响,否则不会这样做。语法糖不是打破兼容性的理由。
许可
Scrapbook采用MIT许可。