适用于 PHP 7.2 及更高版本的灵活且功能齐全的 Redis 客户端。
有关该项目的更多详细信息可以在常见问题中找到。
EVALSHA
或EVAL
之间的自动切换。SCAN
、 SSCAN
、 ZSCAN
和HSCAN
(Redis >= 2.8) 的抽象。该库可以在 Packagist 上找到,以便使用 Composer 更轻松地管理项目依赖项。每个版本的压缩档案均可在 GitHub 上找到。
composer require predis/predis
Predis 依靠 PHP 的自动加载功能在需要时加载其文件,并符合 PSR-4 标准。当通过 Composer 管理依赖项时,自动加载会自动处理,但也可以在缺乏任何自动加载功能的项目或脚本中利用其自己的自动加载器:
// Prepend a base path if Predis is not available in your "include_path".
require ' Predis/Autoloader.php ' ;
Predis Autoloader:: register ();
当创建客户端实例而不传递任何连接参数时,Predis 假定127.0.0.1
和6379
作为默认主机和端口。 connect()
操作的默认超时为 5 秒:
$ client = new Predis Client ();
$ client -> set ( ' foo ' , ' bar ' );
$ value = $ client -> get ( ' foo ' );
连接参数可以以 URI 字符串或命名数组的形式提供。后者是提供参数的首选方式,但是当从非结构化或部分结构化源读取参数时,URI 字符串可能很有用:
// Parameters passed using a named array:
$ client = new Predis Client ([
' scheme ' => ' tcp ' ,
' host ' => ' 10.0.0.1 ' ,
' port ' => 6379 ,
]);
// Same set of parameters, passed using an URI string:
$ client = new Predis Client ( ' tcp://10.0.0.1:6379 ' );
可以通过在参数集中添加password
来访问受密码保护的服务器。当 Redis >= 6.0 上启用 ACL 时,用户身份验证需要username
和password
。
还可以使用 UNIX 域套接字连接到 Redis 的本地实例,在这种情况下,参数必须使用unix
方案并指定套接字文件的路径:
$ client = new Predis Client ([ ' scheme ' => ' unix ' , ' path ' => ' /path/to/redis.sock ' ]);
$ client = new Predis Client ( ' unix:/path/to/redis.sock ' );
客户端可以利用 TLS/SSL 加密连接到安全的远程 Redis 实例,而无需配置 stunnel 等 SSL 代理。当连接到在各种云托管提供商上运行的节点时,这非常有用。可以使用tls
方案和通过ssl
参数传递的一系列合适选项来启用加密:
// Named array of connection parameters:
$ client = new Predis Client ([
' scheme ' => ' tls ' ,
' ssl ' => [ ' cafile ' => ' private.pem ' , ' verify_peer ' => true ],
]);
// Same set of parameters, but using an URI string:
$ client = new Predis Client ( ' tls://127.0.0.1?ssl[cafile]=private.pem&ssl[verify_peer]=1 ' );
还支持连接方案redis
( tcp
的别名)和rediss
( tls
的别名),不同之处在于包含这些方案的 URI 字符串是按照其各自的 IANA 临时注册文档中描述的规则进行解析的。
支持的连接参数的实际列表可能因每个连接后端而异,因此建议参考其特定文档或实现以了解详细信息。
Predis 可以在提供一系列连接参数和适当的选项来指示客户端如何聚合它们(集群、复制或自定义聚合逻辑)时聚合多个连接。为每个节点提供配置时,可以混合命名数组和 URI 字符串:
$ client = new Predis Client ([
' tcp://10.0.0.1?alias=first-node ' , [ ' host ' => ' 10.0.0.2 ' , ' alias ' => ' second-node ' ],
], [
' cluster ' => ' predis ' ,
]);
有关更多详细信息,请参阅本文档的聚合连接部分。
与 Redis 的连接是惰性的,这意味着客户端仅在需要时才连接到服务器。虽然建议让客户端在后台做自己的事情,但有时可能仍然需要控制连接的打开或关闭时间:这可以通过调用$client->connect()
和$client->disconnect()
。请注意,这些方法对聚合连接的影响可能会有所不同,具体取决于每个具体的实现。
可以通过将特定的客户端选项传递给PredisClient::__construct()
的第二个参数来配置客户端的许多方面和行为:
$ client = new Predis Client ( $ parameters , [ ' prefix ' => ' sample: ' ]);
选项使用迷你 DI 类似容器进行管理,并且它们的值可以仅在需要时才进行延迟初始化。 Predis 默认支持的客户端选项有:
prefix
:应用于命令中找到的每个键的前缀字符串。exceptions
:客户端是否应该在 Redis 错误时抛出或返回响应。connections
:连接后端或连接工厂实例的列表。cluster
:指定集群后端( predis
、 redis
或 callable )。replication
:指定复制后端( predis
、 sentinel
或 callable)。aggregate
:使用自定义聚合连接(可调用)配置客户端。parameters
:聚合连接的默认连接参数列表。commands
:指定要通过库使用的命令工厂实例。用户还可以提供带有值或可调用对象(用于延迟初始化)的自定义选项,这些值或可调用对象存储在选项容器中,以便以后通过库使用。
聚合连接是 Predis 实现集群和复制的基础,它们用于将多个连接分组到单个 Redis 节点,并隐藏根据上下文正确处理它们所需的特定逻辑。创建新客户端实例时,聚合连接通常需要一组连接参数以及适当的客户端选项。
Predis 可以配置为使用传统客户端分片方法在集群模式下工作,以创建独立节点的集群并在它们之间分配密钥空间。这种方法需要对节点进行某种外部运行状况监控,并且需要在添加或删除节点时手动重新平衡键空间:
$ parameters = [ ' tcp://10.0.0.1 ' , ' tcp://10.0.0.2 ' , ' tcp://10.0.0.3 ' ];
$ options = [ ' cluster ' => ' predis ' ];
$ client = new Predis Client ( $ parameters );
与 Redis 3.0 一起,引入了一种新的有监督和协调的集群类型,即 redis-cluster。这种方法使用不同的算法来分配密钥空间,Redis 节点通过八卦协议进行通信来协调自身,以处理健康状态、重新平衡、节点发现和请求重定向。为了连接到由 redis-cluster 管理的集群,客户端需要一个其节点列表(不一定完整,因为它会在必要时自动发现新节点)并将cluster
客户端选项设置为redis
:
$ parameters = [ ' tcp://10.0.0.1 ' , ' tcp://10.0.0.2 ' , ' tcp://10.0.0.3 ' ];
$ options = [ ' cluster ' => ' redis ' ];
$ client = new Predis Client ( $ parameters , $ options );
客户端可以配置为在单主/多从设置中运行,以提供更好的服务可用性。使用复制时,Predis 会识别只读命令并将它们发送到随机从属服务器,以便提供某种负载平衡,并在检测到执行任何最终会修改的操作的命令时立即切换到主服务器键空间或键的值。当从属设备发生故障时,客户端不会尝试回退到配置中提供的其他从属设备,而不是引发连接错误。
在复制模式下使用客户端所需的基本配置需要将一台 Redis 服务器识别为主服务器(这可以通过连接参数将role
参数设置为master
来完成)和一个或多个从服务器(在本例中将role
设置为从slave
对于奴隶是可选的):
$ parameters = [ ' tcp://10.0.0.1?role=master ' , ' tcp://10.0.0.2 ' , ' tcp://10.0.0.3 ' ];
$ options = [ ' replication ' => ' predis ' ];
$ client = new Predis Client ( $ parameters , $ options );
上面的配置有一个静态的服务器列表,完全依赖于客户端的逻辑,但是可以依靠redis-sentinel
来获得更强大的 HA 环境,其中 Sentinel 服务器充当客户端进行服务发现的授权来源。客户端使用 redis-sentinel 所需的最低配置是指向一堆哨兵实例的连接参数列表, replication
选项设置为sentinel
, service
选项设置为服务名称:
$ sentinels = [ ' tcp://10.0.0.1 ' , ' tcp://10.0.0.2 ' , ' tcp://10.0.0.3 ' ];
$ options = [ ' replication ' => ' sentinel ' , ' service ' => ' mymaster ' ];
$ client = new Predis Client ( $ sentinels , $ options );
如果主节点和从节点配置为要求客户端进行身份验证,则必须通过全局parameters
客户端选项提供密码。该选项还可用于指定不同的数据库索引。客户端选项数组将如下所示:
$ options = [
' replication ' => ' sentinel ' ,
' service ' => ' mymaster ' ,
' parameters ' => [
' password ' => $ secretpassword ,
' database ' => 10 ,
],
];
虽然 Predis 能够区分执行写入和只读操作的命令,但EVAL
和EVALSHA
代表了一种极端情况,即客户端切换到主节点,因为它无法判断 Lua 脚本何时可以在从属节点上安全执行。虽然这确实是默认行为,但当某些 Lua 脚本不执行写入操作时,可以提供提示来告诉客户端坚持使用从属程序来执行:
$ parameters = [ ' tcp://10.0.0.1?role=master ' , ' tcp://10.0.0.2 ' , ' tcp://10.0.0.3 ' ];
$ options = [ ' replication ' => function () {
// Set scripts that won't trigger a switch from a slave to the master node.
$ strategy = new Predis Replication ReplicationStrategy ();
$ strategy -> setScriptReadOnly ( $ LUA_SCRIPT );
return new Predis Connection Replication MasterSlaveReplication ( $ strategy );
}];
$ client = new Predis Client ( $ parameters , $ options );
$ client -> eval ( $ LUA_SCRIPT , 0 ); // Sticks to slave using `eval`...
$ client -> evalsha ( sha1 ( $ LUA_SCRIPT ), 0 ); // ... and `evalsha`, too.
examples
目录包含一些脚本,这些脚本演示了如何在基本和复杂场景中配置和使用客户端来利用复制。
当需要将许多命令发送到服务器时,管道化可以通过减少网络往返时间带来的延迟来提高性能。管道也适用于聚合连接。由于其流畅的接口,客户端可以在可调用块内执行管道或返回具有链接命令能力的管道实例:
// Executes a pipeline inside the given callable block:
$ responses = $ client -> pipeline ( function ( $ pipe ) {
for ( $ i = 0 ; $ i < 1000 ; $ i ++) {
$ pipe -> set ( " key: $ i " , str_pad ( $ i , 4 , ' 0 ' , 0 ));
$ pipe -> get ( " key: $ i " );
}
});
// Returns a pipeline that can be chained thanks to its fluent interface:
$ responses = $ client -> pipeline ()-> set ( ' foo ' , ' bar ' )-> get ( ' foo ' )-> execute ();
客户端为基于MULTI
和EXEC
Redis 事务提供抽象,并具有与命令管道类似的接口:
// Executes a transaction inside the given callable block:
$ responses = $ client -> transaction ( function ( $ tx ) {
$ tx -> set ( ' foo ' , ' bar ' );
$ tx -> get ( ' foo ' );
});
// Returns a transaction that can be chained thanks to its fluent interface:
$ responses = $ client -> transaction ()-> set ( ' foo ' , ' bar ' )-> get ( ' foo ' )-> execute ();
由于WATCH
和UNWATCH
这种抽象可以执行检查和设置操作,并在触摸WATCH
ed 键时自动重试 Redis 中止的事务。有关使用 CAS 的事务示例,您可以查看以下示例。
虽然我们尝试更新 Predis 以了解 Redis 中可用的所有命令,但您可能更愿意坚持使用旧版本的库,或者提供不同的方法来过滤参数或解析特定命令的响应。为了实现这一点,Predis 提供了实现新命令类的能力,以定义或覆盖客户端使用的默认命令工厂中的命令:
// Define a new command by extending PredisCommandCommand:
class BrandNewRedisCommand extends Predis Command Command
{
public function getId ()
{
return ' NEWCMD ' ;
}
}
// Inject your command in the current command factory:
$ client = new Predis Client ( $ parameters , [
' commands ' => [
' newcmd ' => ' BrandNewRedisCommand ' ,
],
]);
$ response = $ client -> newcmd ();
还有一种方法可以发送原始命令而不过滤其参数或解析响应。用户必须以数组形式提供命令的参数列表,遵循 Redis 文档中命令定义的签名:
$ response = $ client -> executeRaw ([ ' SET ' , ' foo ' , ' bar ' ]);
虽然可以直接使用EVAL
和EVALSHA
在 Redis 2.6+ 上利用 Lua 脚本,但 Predis 提供脚本命令作为构建在它们之上的更高级别的抽象,以使事情变得简单。脚本命令可以在客户端使用的命令工厂中注册,并且可以像普通 Redis 命令一样进行访问,但它们定义了传输到服务器以进行远程执行的 Lua 脚本。在内部,他们默认使用EVALSHA
并通过 SHA1 哈希来识别脚本以节省带宽,但EVAL
在需要时用作后备:
// Define a new script command by extending PredisCommandScriptCommand:
class ListPushRandomValue extends Predis Command ScriptCommand
{
public function getKeysCount ()
{
return 1 ;
}
public function getScript ()
{
return <<<LUA
math.randomseed(ARGV[1])
local rnd = tostring(math.random())
redis.call('lpush', KEYS[1], rnd)
return rnd
LUA ;
}
}
// Inject the script command in the current command factory:
$ client = new Predis Client ( $ parameters , [
' commands ' => [
' lpushrand ' => ' ListPushRandomValue ' ,
],
]);
$ response = $ client -> lpushrand ( ' random_values ' , $ seed = mt_rand ());
Predis 可以使用不同的连接后端来连接到 Redis。内置的 Relay 集成通过在 PHP 共享运行时内存中缓存 Redis 数据集的部分副本,利用 PHP 的 Relay 扩展来显着提高性能。
$ client = new Predis Client ( ' tcp://127.0.0.1 ' , [
' connections ' => ' relay ' ,
]);
开发人员可以创建自己的连接类来支持全新的网络后端、扩展现有类或提供完全不同的实现。连接类必须实现PredisConnectionNodeConnectionInterface
或扩展PredisConnectionAbstractConnection
:
class MyConnectionClass implements Predis Connection NodeConnectionInterface
{
// Implementation goes here...
}
// Use MyConnectionClass to handle connections for the `tcp` scheme:
$ client = new Predis Client ( ' tcp://127.0.0.1 ' , [
' connections ' => [ ' tcp ' => ' MyConnectionClass ' ],
]);
要更深入地了解如何创建新的连接后端,您可以参考PredisConnection
命名空间中可用的标准连接类的实际实现。
对 Predis 的贡献受到高度赞赏,无论是以新功能拉取请求、错误修复还是错误报告的形式。我们只要求您遵守问题和拉取请求模板。
注意:切勿针对在生产环境中运行或包含您感兴趣的数据的 Redis 实例运行 Predis 附带的测试套件!
Predis 有一个全面的测试套件,涵盖了库的各个方面,并且可以选择针对正在运行的 Redis 实例执行集成测试(需要 >= 2.4.0,以便验证每个命令实现的正确行为。不支持的集成测试如果您没有启动并运行 Redis,则可以禁用 Redis 命令,有关测试此库的更多详细信息,请参阅测试自述文件。
Predis 使用 GitHub Actions 进行持续集成,过去和当前构建的历史记录可以在其操作页面上找到。
Predis 的代码是根据 MIT 许可证的条款分发的(请参阅许可证)。