连接服务器

Predis 提供了各式各样连接服务器或服务器集群的方式。通过指定两个以上服务器,Predis 自动切换集群连接,透明地处理多个连接上的客户端分片。应该注意的是,集群连接相比单一连接(即 Predis 被连接到一个单独的服务器)有较多开销,这是由于支持一致的哈希时需要更复杂的内部结构。

  • 连接默认的服务器(127.0.0.1)和端口(6379)

$redis = new Predis\Client();
  • 使用参数连接服务器

redis = new Predis\Client(array(
    'host' => '10.0.0.1', 
    'port' => 6380, 
));

或者

$redis = new Predis\Client('redis://10.0.0.1:6380/');
  • 连接到多个服务器

$redis = new Predis\Client(array(
    array('host' => '10.0.0.1'), 
    array('host' => '10.0.0.2'), 
));

或者

$redis = new Predis\Client(array(
    'redis://10.0.0.1/', 
    'redis://10.0.0.1/', 
));

或者

$redis = Predis\Client::create(
    array('host' => '10.0.0.1'), 
    array('host' => '10.0.0.2')
);

或者

$redis = Predis\Client::create(
    'redis://10.0.0.1/', 
    'redis://10.0.0.1/'
);
  • 在连接时自动执行身份验证和数据库选择

$redis = new Predis\Client(array(
    'host'     => '10.0.0.1', 
    'password' => 'secret', 
    'database' => 10, 
));

或者

$redis = new Predis\Client('redis://10.0.0.1/?password=secret&database=10');

支持的连接参数

参数 描述 默认值
__host__ 服务器的 IP 地址或主机名称 127.0.0.1
__port__ 服务器监听的 TCP 端口 6379
__password__ 服务器用于身份验证的密码 no不使用密码
__database__ 连接后,选择的数据库索引 为设定索引,使用默认的 Redis 数据库
__timeout__ 连接服务器的超时时间 5 秒
__read_write_timeout__ 在网络 socket 上读写操作的超时时间 系统默认 (NOTE: 使用 -1 禁用读写超时)

发送指令

使用 Predis 向 Redis 发送请求真的相当简单,但是处理指令的方式不止一种:

  • 简单方式(最常用的)
$redis->set('library', 'predis');
$retval = $redis->get('library');
  • 较长的方式(但更程序化)
// Client::createCommand uses the current server profile
// to create and return a new command instance
$cmdSet = $redis->createCommand('set');
$cmdSet->setArgumentsArray(array('library', 'predis'));
$cmdSetReply = $redis->executeCommand($cmdSet);
$cmdGet = $redis->createCommand('get');
$cmdGet->setArgumentsArray(array('library'));
$cmdGetReply = $redis->executeCommand($cmdGet);
  • 最长的方式(and partially discouraged)
$cmdSet = new Predis\Commands\Set();
$cmdSet->setArgumentsArray(array('library', 'predis'));
$cmdSetReply = $redis->executeCommand($cmdSet);
$cmdGet = new Predis\Commands\Get();
$cmdGet->setArgumentsArray(array('library'));
$cmdGetReply = $redis->executeCommand($cmdGet);

另外还有各种各样的方式,在处理指令实例时去设置指令的参数:

  • 创建指令实例时传递动态的参数列表
$cmdSet = $redis->createCommand('set', array('library', 'predis'));
  • 在现有的指令实例上传递动态的参数列表
$cmdSet = $redis->createCommand('set');
$cmdSet->setArgumentsArray(array('library', 'predis'));
  • 在现有的指令实例上传递固定的参数列表
$cmdSet = $redis->createCommand('set');
$cmdSet->setArguments('library', 'predis');

如果你想要发送的指令在 Predis 中没有定义,该怎么办?

  • 发送原生指令(目前暂不支持集群链接)
$reply = $redis->rawCommand("NEWCMD $key $param1 $param2");
  • 通过继承以下基类定义你自定的指令:

PredisCommand, PredisInlineCommand, PredisBulkCommand and PredisMultiBulkCommand.

class BrandNewRedisCommand extends \Predis\InlineCommand {
    public function getCommandId() { return 'NEWCMD'; }
}
$redis->getProfile()->registerCommand('BrandNewRedisCommand', 'newcmd');
$reply = $redis->newcmd($key, $param1, $param2);

Server profiles

Predis introduced the concept of server profiles to allow developers to specify, in a programmatic way, which Redis version they are going to connect to. This means that you can know beforehand which commands or features are supported by the selected Redis version and allows us to handle eventual behavioral differences in certain commands. As of today there are three predefined profile classes: PredisRedisServer_v1_0 (Redis v1.0), PredisRedisServer_v1_2 (Redis v1.2) and PredisRedisServer_vNext (the development version of Redis). When you create an instance of PredisClient, the default server profile being used is the latest stable version of Redis available at release time, but you can always force Predis to use a different profile:

  • Set a different server profile when instanciating a new PredisClient instance
$profile1_0 = new Predis\RedisServer_v1_0();
printf("MSET SUPPORTED: %s\n", $profile1_0->supportsCommand('mset') ? 'YES' : 'NO');
$profile1_2 = new Predis\RedisServer_v1_2();
printf("MSET SUPPORTED: %s\n", $profile1_2->supportsCommand('mset') ? 'YES' : 'NO');
$redis = new Predis\Client('redis://127.0.0.1/', $profile1_2);
  • Get an instance of the default server profile supported by the current version of Predis
$defaultProfile = Predis\RedisServerProfile::getDefault();
echo get_class($defaultProfile);        // OUTPUT: Predis\RedisServer_v1_2
  • Get an instance of a server profile supported by Predis by using a version string
$profile = Predis\RedisServerProfile::get('1.2');
echo get_class($profile);        // OUTPUT: Predis\RedisServer_v1_2
$profile = Predis\RedisServerProfile::get('dev');
echo get_class($profile);        // OUTPUT: Predis\RedisServer_vNext

h2. Pipelining

Pipelining can help with performances when you need to issue a whole set of commands to Redis. This is done by recording the commands issued to the client without actually sending them to the server, playing them all at once over the wire when flushing the pipeline (send the commands) and then listening to what the server has to tell us (read the responses).

  • Initialize a pipeline inside of a block of code using an anonymous function (PHP 5.3 only)
$replies = $redis->pipeline(function($pipe) {
    $pipe->ping();
    $pipe->flushdb();
    $pipe->incrby('counter', 10);
    $pipe->exists('counter');
    $pipe->mget('does_not_exist', 'counter');
});
  • Initialize a pipeline and return an instance to play with (this also works with PHP 5.2)
$pipe = $redis->pipeline();
$pipe->ping();
$pipe->flushdb();
$pipe->incrby('counter', 10);
$pipe->exists('counter');
$pipe->mget('does_not_exist', 'counter');
$replies = $pipe->execute();

h2. Client-side sharding

The key-value model allows you to easily distribute your data across several servers and this is usually achieved by hashing the keys against a list of servers to select which one will be used to store their respective values. The same data-partitioning strategy can be used with Redis using a client library capable of handling connections to more than one server, but this is not enough to guarantee a consistent distribution and accessibility of your data as time passes. Predis supports "consistent hashing":http://en.wikipedia.org/wiki/Consistent_hashing when storing your list of servers, so that adding or removing a server does not affect the pre-existing distribution and availability of data on the others. Key tags are another interesting feature that allows you to decide which portion of a key should be hashed against the server list so you can redirect a subset of keys to the same instance. E.g., instead of using plain keys like "uid:1000:username" and "uid:1000:password" that will almost surely produce a different hash (and thus, sent on different servers) you can go with "{uid:1000}:username" and __"{uid:1000}:password"__, where the curly brackets define which part of the key will be hashed. Everything is handled transparently, even when using pipelines.

  • Initialize a clustered client and set/retrieve key-values using key tags
$redis = Predis\Client::create(
    'redis://10.0.0.1/', 
    'redis://10.0.0.2/'
);
$redis->set('{uid:1000}:username', 'nrk');
$redis->set('{uid:1000}:password', md5('mystrongpassword'));
$username = $redis->get('{uid:1000}:username'); // nrk
$password = $redis->get('{uid:1000}:password'); // c924729b0e04eb0d21908a7454c0218a