bdk / simplecache
内置APC(u)、Couchbase、文件系统、FlySystem、Memcached、Redis和SQL Stampede保护适配器的SimpleCache实现
Requires
- php: ^5.3|^7.0
- psr/cache: ~1.0
- psr/simple-cache: ~1.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ~2.0
- phpunit/phpunit: ~4.8|~5.0|~6.0
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
README
由 matthiasmullie/scrapbook 分支而来
安装与使用
如果您使用 Composer 管理项目依赖,只需在composer.json文件中添加bdk/simplecache依赖
composer require bdk/simplecache
确切的引导过程将取决于您要使用的适配器、功能和接口,所有这些都在下面详细说明。
此库通过所有都是 KeyValueStore 实现的层级构建而成,如果您想要添加更多功能,可以相互包裹。
以下是一个简单的示例:带有Stampede保护的Memcached支持的psr/cache。
// create \Memcached object pointing to your Memcached server $client = new \Memcached(); $client->addServer('localhost', 11211); // create KeyValueStore object $cache = new \bdk\SimpleCache\Adapters\Memcached($client); // create stampede protector layer over our real cache $cache = new \bdk\SimpleCache\Scale\StampedeProtector($cache); // create Pool (psr/cache) object from cache engine $pool = new \bdk\SimpleCache\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 KeyValueStore object $cache = new \bdk\SimpleCache\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 KeyValueStore object $cache = new \bdk\SimpleCache\Adapters\Redis($client);
Couchbase
旨在满足关键任务应用所需的弹性可伸缩性、一致高性能、始终在线可用性和数据移动性要求。
使用 PECL Couchbase 扩展 与Couchbase服务器进行接口。只需将有效的 \CouchbaseBucket
对象提供给Couchbase适配器
// create \CouchbaseBucket object pointing to your Couchbase server $cluster = new \CouchbaseCluster('couchbase://localhost'); $bucket = $cluster->openBucket('default'); // create KeyValueStore object $cache = new \bdk\SimpleCache\Adapters\Couchbase($bucket);
APC(u)
APC是PHP的一个免费和开源的opcode缓存。其目标是提供一个免费、开源和健壮的框架,用于缓存和优化PHP中间代码。
使用APC,没有“缓存服务器”,数据仅缓存在本机上,可供该机上的所有PHP进程使用。可以使用PECL APC 或 APCu 扩展。
// create KeyValueStore object $cache = new \bdk\SimpleCache\Adapters\Apc();
MySQLi
MySQL是世界上最受欢迎的开源数据库。MySQL可以以低廉的成本帮助您交付高性能、可伸缩的数据库应用程序。
虽然数据库不是真正的缓存,但它也可以作为键值存储使用。只是不要期望从专用缓存服务器获得相同类型的性能。
但是使用基于数据库的缓存可能有很好的理由:如果你已经使用数据库,那么它很方便,并且可能具有其他好处(如持久化存储、复制)。
// create mysqli object $client = new \mysqli('mysql', 'root', '', 'cache'); // create KeyValueStore object $cache = new \bdk\SimpleCache\Adapters\MySQLi($client);
PdoMySQL
MySQL是世界上最受欢迎的开源数据库。MySQL可以以低廉的成本帮助您交付高性能、可伸缩的数据库应用程序。
虽然数据库不是真正的缓存,但它也可以作为键值存储使用。只是不要期望从专用缓存服务器获得相同类型的性能。
但是使用基于数据库的缓存可能有很好的理由:如果你已经使用数据库,那么它很方便,并且可能具有其他好处(如持久化存储、复制)。
// create \PDO object pointing to your MySQL server $client = new PDO('mysql:dbname=cache;host=127.0.0.1', 'root', ''); // create KeyValueStore object $cache = new \bdk\SimpleCache\Adapters\PdoMySQL($client);
PdoPgSQL
PostgreSQL拥有经过验证的架构,使其在可靠性、数据完整性和正确性方面赢得了良好的声誉。
虽然数据库不是真正的缓存,但它也可以作为键值存储使用。只是不要期望从专用缓存服务器获得相同类型的性能。
但是使用基于数据库的缓存可能有很好的理由:如果你已经使用数据库,那么它很方便,并且可能具有其他好处(如持久化存储、复制)。
// create \PDO object pointing to your PostgreSQL server $client = new PDO('pgsql:user=postgres dbname=cache password='); // create KeyValueStore object $cache = new \bdk\SimpleCache\Adapters\PdoPgSQL($client);
PdoSQLite
SQLite是一个软件库,实现了自包含、无服务器、零配置的事务性SQL数据库引擎。
虽然数据库不是真正的缓存,但它也可以作为键值存储使用。只是不要期望从专用缓存服务器获得相同类型的性能。
// create \PDO object pointing to your SQLite server $client = new PDO('sqlite:cache.db'); // create KeyValueStore object $cache = new \bdk\SimpleCache\Adapters\PdoSQLite($client);
文件系统
基于文件的缓存
// create KeyValueStore object $cache = new \League\Flysystem\Filesystem('/path/to/cache');
Flysystem
使用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 KeyValueStore object $cache = new \bdk\SimpleCache\Adapters\Flysystem($filesystem);
内存
PHP也可以在内存中保持数据!PHP数组作为存储特别有用,因为你可以运行测试而无需安装任何其他服务。
将值放入内存中基本上是没有用的:它们将在请求结束时丢失。除非你在同一个请求中多次使用这些缓存值,否则缓存总是空的,而且使用这个缓存几乎没有理由。
然而,在单元测试时非常有用:你可以在这个基于内存的存储上运行整个测试套件,而不是设置缓存服务并确保它们处于原始状态...
// create KeyValueStore object $cache = new \bdk\SimpleCache\Adapters\Memory();
功能
除了默认的缓存功能(如get
和set
)之外,Scrapbook还提供了一些小巧的功能。这些都是在其自己的小对象中实现的,该对象实现了KeyValueStore并围绕KeyValueStore进行包装。换句话说,任何功能都可以简单地包装在另一个功能内部或任何适配器之上。
本地缓冲区
缓冲包装器有助于减少对真实缓存的请求。如果你需要多次(从代码中的多个地方)请求相同的值,保持该值可能很麻烦。再次从缓存请求它会更简单,但这样会从缓存服务器连接中产生一些延迟。
Buffered会将在内存中保持已知值(你已经请求或自己编写的项目)。每次你需要该值在同一请求中时,它将直接从内存中获取,而不是访问缓存服务器。
只需将Buffered类包装在你的适配器(或其他功能)周围
// create buffered cache layer over our real cache $cache = new \bdk\SimpleCache\Buffered\Buffered($cache);
事务
事务包装器使将写入延迟到以后的某个时间点成为可能。类似于数据库中的事务,所有延迟的写入都可以一次回滚或提交,以确保存储的数据是可靠和完整的。所有这些都将被存储,或者什么都不存储。
你可能想在代码库中处理代码,但在一切成功验证并写入永久存储之前不提交任何更改。
在事务内部,你不必担心数据一致性。在事务内部,即使它尚未提交,你也总是被提供你打算存储的那个。换句话说,当你向缓存写入新值但尚未提交时,你查询它时仍然会得到那个值。如果你回滚或未能提交(因为另一个进程存储的数据导致你的提交失败),那么你会从缓存中获取原始值而不是你打算提交的那个。
只需将KeyValueStore适配器包装在事务包装器内
// create transactional cache layer over our real cache $cache = new \bdk\SimpleCache\Buffered\Transactional($keyValueStore);
然后,你就可以使用事务了!
// 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();
Stampede保护
当有大量请求数据不在缓存中时,会发生缓存雪崩,导致大量并发复杂操作。例如
- 缓存过期,这通常是在非常重的负载下
- 对可能不在缓存中的某个东西突然意外的高负载
在这些情况下,大量请求非缓存数据的请求会导致昂贵的操作同时执行很多次。
StampedeProtector旨在对此进行抵抗。如果一个值在缓存中找不到,将存储一个占位符以指示已请求但不存在。在短时间内,后续的每个请求都会找到这个指示,并知道另一个进程正在生成该结果,所以它们将等待结果可用,而不是破坏服务器。
只需将StampedeProtector层包裹在你的适配器(或其他功能)周围。
// create stampede protector layer over our real cache $cache = new \bdk\SimpleCache\Scale\StampedeProtector($cache);
分片
当你有太多数据供(或请求)一个小服务器使用时,这会使你能够在多个缓存服务器上分片。所有数据将自动均匀分布到你的服务器池中,因此每个单独的缓存服务器只获得一小部分数据与流量。
将组成缓存服务器池的单独KeyValueStore对象传递给此构造函数,数据将根据传递给此构造函数的缓存服务器的顺序在这些对象上分片(因此请确保始终保持相同的顺序)。
分片均匀分配,所有缓存服务器将大致接收相同数量的缓存键。如果某些服务器比其他服务器大,可以通过多次添加该缓存服务器的KeyValueStore对象来抵消这一点。
数据甚至可以在不同的适配器之间分片:分片池中的一个服务器可以是Redis,另一个可以是Memcached。不确定你为什么要这样做,但你可以这么做!
只需将Shard层包裹在你的适配器(或其他功能)周围。
// boilerplate code example with Redis, but any // bdk\SimpleCache\KeyValueStoreInterface implementation will work $client = new \Redis(); $client->connect('192.168.1.100'); $cache1 = new \bdk\SimpleCache\Adapters\Redis($client); // a second Redis server... $client2 = new \Redis(); $client2->connect('192.168.1.101'); $cache2 = new \bdk\SimpleCache\Adapters\Redis($client); // create shard layer over our real caches // now $cache will automatically distribute the data across both servers $cache = new \bdk\SimpleCache\Scale\Shard($cache1, $cache2);
接口
Scrapbook支持3个不同的接口。有Scrapbook特定的KeyValueStore,然后是PHP FIG提出的2个PSR接口。
KeyValueStore
KeyValueStore是这个项目的基石。它提供最缓存操作的接口:get
、getMultiple
、set
、setMultiple
、delete
、deleteMultiple
、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 KeyValueStoreInterface object $pool = new \bdk\SimpleCache\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 KeyValueStoreInterface object $simplecache = new \bdk\SimpleCache\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 \bdk\SimpleCache\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->clear(); // this removes everything from the server, including all of its subsets // ('value one' and 'value three' will also be deleted) $cache->clear();
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 \bdk\SimpleCache\Psr6\Pool($articleCache); $sessionPool = new \bdk\SimpleCache\Psr6\Pool($sessionCache);
兼容性
尽可能的情况下,Scrapbook 支持从 PHP 5.3 到当前版本的所有版本,以及 HHVM。Scrapbook 将在这些版本和平台之间缓存后端的实现差异缓解到最小,以确保统一的行为。
所有这些版本和平台的兼容性都在Travis CI上进行了测试,使用的是官方 PHP Docker 镜像,这意味着 PHP <= 5.5 已经不再被积极测试,尽管 Scrapbook 支持这些版本。
没有特定版本或平台的实现(在较老的 PHP 版本上的Flysystem)显然不受支持。
与旧软件版本的兼容性不会轻易被破坏。除非有令人信服的理由这样做,如安全或性能影响。语法糖不是破坏兼容性的理由。
许可
Scrapbook 是 MIT 许可。