KB 事物 Redis 封装器

v1.24.12 2024-06-13 00:19 UTC

README

类似于 Pdb,但针对 Redis。我想。

重视键前缀和对象序列化。

也因为我不想依赖于 predis 或 php-redis。它们都有自己的问题(模糊的魔法命令 API、二进制扩展等)。 如果出现第三个选项那岂不是更好 /s。也支持 credis。

安装

作为依赖项添加

composer require karmabunny/rdb

适配器

  • php-redis(二进制扩展)
  • predis(Composer 包)
  • credis(Composer 包)

这个库本身不实现 Redis 客户端,只封装现有的客户端。经过大量尝试使所有客户端的响应正常化后,可能会觉得编写自己的、不那么不一致的客户端是个好主意。

但考虑到我们之所以知道这些库不一致,是因为我们花了很多时间试图使它们表现一致。例如,客户端 'A' 可能擅长 'B' 但不擅长 'C'。然后客户端 'D' 在 'B' 上表现不佳但在 'C' 上表现很好。

所以当我坐在这里嘲笑它们的无力尝试时,我想到了一些事情。

  1. 在这次旅程中,我已经引入了很多自己的错误。
  2. 单元测试是天赐的礼物。
  3. 使这些不一致性正常化提高了我们自己的一致性,这可能是从头编写新客户端时难以实现的。
  4. 还有这个: https://xkcd.com/927

版本支持

这个封装器不尝试填充任何缺失的功能。它针对 Redis 服务器 v3.0,因为所有适配器都支持这个版本。

这个库永远不会试图 隐藏 特性在目标版本之后,但也许它可以平滑这些差异。Lua 脚本实际上可以填充很多东西。

例如,BRPOPLPUSH 在 v6.2 中已被弃用,并且可能在未来被移除。在这种情况下,该库可以根据服务器版本动态地将它替换为 BLMOVE

v2 版本的计划

对于命令的毫秒版本,特别是 TTL 参数,存在偏好。这显然是误导性的,并且已经非常不一致。理想情况下,这将改变,以便将 'float' 转换为毫秒版本,而整数保持不变。因此,输入始终是 '秒'。

类型错误目前(希望)始终返回 null。这有时可能会让人困惑,有时可能会有所帮助。版本 2 可能允许两种情况,默认情况下抛出异常。

配置

  • host - 服务器名称 + 端口
  • prefix - 键前缀
  • adapter - 'predis'(默认),'php-redis','credis'
  • timeout - 连接超时,以秒为单位(默认:5)
  • lock_sleep - 锁定的时间间隔,以毫秒为单位(默认:5)
  • chunk_size - mscan 方法的最大键大小(默认:50)
  • scan_size - scan 方法的计数提示(默认:1000)
  • scan_keys - 将 keys() 替换为 scan()(默认:false)
  • options - 适配器特定选项

备注

  • 除非在 host 选项中指定,否则端口号默认为 6379。
  • 可以在 host 选项中调整协议:前缀 tcp://udp://
return [
    'host' => 'localhost',
    'prefix' => 'sitecode:',

    // Defaults
    'adapter' => 'predis',
    'lock_sleep' => 5,
    'chunk_size' => 50,
    'scan_size' => 1000,
    'scan_keys' => false,
    'options' => [],
];

用法

带有 TTL 的基本用法。非常适合缓存。

use karmabunny\rdb\Rdb;

$config = require 'config.php';
$rdb = Rdb::create($config);

// Store 'blah' for 100 ms
$rdb->set('key', 'blah', 100);

$rdb->get('key');
// => blah

usleep(150 * 1000);

$rdb->get('key');
// => NULL

对象扩展将以 PHP 格式序列化。它们内置断言,因此事物总是正确的形状。

$model = new MyModel('etc');
$rdb->setObject('objects:key', $model);

$rdb->getObject('objects:key', MyModel::class);
// => MyModel( etc )

$rdb->getObject('objects:key', OtherModel::class);
// => NULL

锁定机制提供了一种限制对资源的原子访问的方式。

// Wait for a lock for up to 10 seconds.
$lock = $rdb->lock('locks:key', 10 * 1000);

if ($lock === null) {
    echo "Busy - too much contention\n";
}
else {
    // Do atomic things.
    $lock->release();
}

漏桶算法是一种速率限制算法。它非常有趣,易于理解,且不太复杂。

// A bucket with 60 drips per minute.
$bucket = $rdb->getBucket([
    'key' => 'key',

    // Defaults.
    'capacity' => 60,
    'drip_rate' => 1,

    // Optional.
    'prefix' => 'drips:',
    'costs' => [
        'GET' => 1,
        'POST' => 10,
    ],
]);

// One drip.
$full = $bucket->drip();

if ($full) {
    echo "We're full, please wait {$bucket->getWait()} ms\n";
}
else {
    // Do things.
}

// Big drip.
$bucket->drip(20);

// Named drip (10 drips).
$bucket->drip('POST');

// Write out the status to the headers for easy debugging.
$bucket->writeHeaders();

贡献

如果你喜欢,可以提交一个PR。但在你这么做之前,请先完成以下操作

  1. 运行composer analyse并修复任何在那里出现的问题
  2. 运行composer compat并修复这些问题
  3. 编写一些测试并用composer tests运行
  4. 在此处记录方法

方法

核心方法

  • get
  • set
  • keys
  • scan
  • mGet
  • mSet
  • del
  • exists
  • sMembers
  • sAdd
  • lLen
  • lRange
  • lTrim
  • lSet
  • lRem
  • lIndex
  • lPush
  • lPop
  • blPop
  • rPush
  • rPop
  • brPop
  • brPoplPush
  • zAdd
  • zIncrBy
  • zRange
  • zRem
  • zCard
  • zCount
  • zScore
  • zRank
  • zRevRank

TODO: 更多

集合

  • sScan
  • sRandMember
  • sDiff (+ 存储)
  • sInter (+ 存储)
  • sUnion (+ 存储)

扩展方法

  • mScan
  • getObject
  • setObject
  • mGetObjects
  • mScanObjects
  • mSetObjects
  • setJson
  • getJson

内置工具

  • ‘漏桶’速率限制
  • 锁定

TODOs

  • 更多测试
  • 更多方法