kadokweb/scrapbook

Scrapbook 是一个 PHP 缓存库,具有适配器,例如 Memcached、Redis、Couchbase、APC(u)、SQL 以及在底层构建的附加功能(例如事务、雪崩保护)。

资助包维护!
kadokweb

1.0.0 2022-01-14 14:04 UTC

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 APCAPCu 扩展。

// 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();

特性

除了默认的缓存功能(如getset)之外,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是这个项目的基石。它是提供最多缓存操作的接口:getgetMultisetsetMultideletedeleteMultiaddreplacecasincrementdecrementtouchflush

如果你之前使用过Memcached,KeyValueStore看起来会非常相似,因为它受到了那个API的启发/仿照。

所有适配器和特性都实现了此接口。如果你有复杂的缓存需求(例如能够cas),你应该坚持使用这个接口。

KeyValueStore接口及其方法的详细列表可以在文档中找到。

psr/cache

PSR-6(一个PHP-FIG标准)与KeyValueStore和psr/simple-cache相比,是一个截然不同的缓存模型:psr/cache不是直接从缓存中查询值,而是基本上在值对象(Item)上操作以执行更改,然后将更改反馈到缓存(Pool。)

它不允许你执行太多的操作。如果你只需要getsetdelete(及其多版本)和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一样,并且以非常相似的方式工作。

它不会让您执行太多操作。如果您只需要getsetdelete(及其多版本)和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许可。