Redis predis extension introduction

  • Predis

Predis is applicable to the use of PHP version 5.3 and above in Redis, including the use of clusters.

major function

  • Support various versions of redis (from 2.0 to 3.0 and unstable)
  • Use hash method or user-defined method to partition the client of nodes in the cluster
  • support Redis cluster (Redis>= 3.0).
  • Support read / write separation of master / slave structure
  • Support all known Redis client commands

Mode of use

Predis download address: PEAR channel as well as GitHub mode.

Load dependent packages

Predis relies on PHP's automatic loading function to load its files when needed and comply with the PSR-4 standard. Use the following:

// Load from the Predis root directory. Unless the file is in include_path
require 'Predis/Autoloader.php';
 
Predis\Autoloader::register();
Copy code

Connect to Redis

If you do not add any parameters during the connection, 127.0.0.1 and 6379 will be used as the default host and port by default, and the connection timeout is 5 seconds. For example:

$client = new Predis\Client();
$client->set('foo', 'bar');
$value = $client->get('foo');
Copy code

If connection parameters need to be added, they can be in the form of URI or array. For example:

// Array form
$client = new Predis\Client([
    'scheme' => 'tcp',
    'host'   => '10.0.0.1',
    'port'   => 6379,
]);
 
// URI form:
$client = new Predis\Client('tcp://10.0.0.1:6379');
Copy code

When using array form. Predis automatically switches to cluster mode and uses the client's sharding logic. In addition, parameters can also be mixed with URI s and arrays, such as:

$client = new Predis\Client([
    'tcp://10.0.0.1?alias=first-node',
    ['host' => '10.0.0.2', 'alias' => 'second-node'],
]);
Copy code

Client configuration

More configuration parameters of the Client can be passed in through the second parameter:

$client = new \Predis\Client(
    $connection_parameters,
    ['profile' => '2.8', 'prefix' => 'sample:']
);
Copy code

Redis will give default values to the required parameters, mainly including:

  • profile: configuration for a specific version, because different versions may have different effects on the same operation
  • Prefix: automatically prefix the key to be processed
  • Exceptions: whether to return results when redis makes an error
  • connections: the connection factory to be used by the client
  • Cluster: which background is used in the cluster (predis, redis or client configuration)
  • replication: which background (predis or client configuration) the master / slave uses
  • aggregate: merge connection methods (overwrite cluster and replication)

Merge connection

Predis supports the connection of clusters and master / slave structures. By default, the fragmentation logic of the client or the method provided by the Redis server can be used, that is: redis cluster. In the master / slave structure, Predis supports the form of one master and multiple slaves, and connects to the slave during read operations and to the host during write operations.

Master / slave structure

Master / slave configuration can be performed during client connection. After configuration, the slave will be connected when the read operation is performed; The host is connected when a write operation is performed. Achieve read-write separation. The following is the basic master / slave configuration:

$parameters = ['tcp://10.0.0.1?alias=master', 'tcp://10.0.0.2?alias=slave-01'];
$options    = ['replication' => true];
 
$client = new Predis\Client($parameters, $options);
Copy code

Although Predis can recognize read / write operations, Eval and evalsha are two special cases. Because the client does not know whether there are write operations in the LUA script, these two operations are usually performed on the Master. Although this is the default behavior, if write operations are not included in some Lua scripts, the client may still execute on the slave. Can be specified by configuration.

$LUA_SCRIPT = "......some lua code......";
$parameters = ['tcp://10.0.0.1?alias=master', 'tcp://10.0.0.2?alias=slave-01'];
$options    = ['replication' => function () {
    // Force the specified to execute on the slave without switching to the master
    $strategy = new Predis\Replication\ReplicationStrategy();
    $strategy -> setScriptReadOnly($LUA_SCRIPT);
 
    return new Predis\Connection\Aggregate\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.
Copy code

colony

The cluster function can be realized by passing simple and configuration, and it is partitioned on the client. However, if you want to use the redis cluster function (available in the version after Redis 3.0). It can be configured as follows:

$parameters = ['tcp://10.0.0.1', 'tcp://10.0.0.2'];
$options    = ['cluster' => 'redis'];
 
$client = new Predis\Client($parameters, $options);
Copy code

When using redis cluster, you don't need to pass all the nodes in the cluster in the parameters, just a few. Predis will automatically get all hash slot maps from a server.

Note: at present, Predis does not support the master / slave structure in redis cluster

Command pipeline

The pipeline helps to improve the performance of a large number of commands to be sent. It can reduce the round-trip delay of the network. For example, there are two commands for data: -Send command to server -Server execution command -Return structure to client

Each operation must be executed. The pipeline means that multiple commands can be packaged and sent to the server together. After all commands are executed, the final results will be returned. There are two ways to use pipes. One is through callback function; One is through the interface:

// Execute command channel by callback:
$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");
    }
});
 
// Command channel used in interface form:
$responses = $client->pipeline()->set('foo', 'bar')->get('foo')->execute();
Replication generation

affair

Redis can use MULTI and EXEC commands to implement transaction functions. Here, you can directly use the command channel:

// Callback method:
$responses = $client->transaction(function ($tx) {
    $tx->set('foo', 'bar');
    $tx->get('foo');
});
 
// Interface mode:
$responses = $client->transaction()->set('foo', 'bar')->get('foo')->execute();
Copy code

We can use WATCH and UNWATCH to implement CAS (check and set). For example:

function zpop($client, $key)
{
    $element = null;
    $options = array(
        'cas'   => true,    // Use CAS mode
        'watch' => $key,    // key to monitor
        'retry' => 3,       // Number of retries on error
    );
 
    $client->transaction($options, function ($tx) use ($key, &$element) {
        @list($element) = $tx->zrange($key, 0, 0);
 
        if (isset($element)) {
            $tx->multi();   // Open transaction
            $tx->zrem($key, $element);
        }
    });
 
    return $element;
}
 
$client = new Predis\Client($single_server);
$zpopped = zpop($client, 'zset');
Copy code

Custom command

If we upgrade Redis to a new version and the processing methods of some commands are changed, but we want to use the previous logic, we can customize the commands:

// Customize a class and inherit Predis\Command\Command:
class BrandNewRedisCommand extends Predis\Command\Command
{
    public function getId()
    {
        return 'NEWCMD';
    }
}
 
// To register a new custom command:
$client = new Predis\Client();
$client->getProfile()->defineCommand('newcmd', 'BrandNewRedisCommand');
 
$response = $client->newcmd();
Copy code

LUA command

Redis version after 2.6 can be used EVAL and EVALSHA To execute LUA scripts. Predis supports a simple interface to support this function. LUA scripts can be on the server side or passed in through parameters. By default, the EVALSHA It can also be standby EVAL :

// Define a script execution command, which inherits Predis\Command\ScriptCommand:
class ListPushRandomValue extends Predis\Command\ScriptCommand
{
    public function getKeysCount()
    {
        return 1;
    }
 
    public function getScript()
    {
        return <<
    }
}
 
// To register a new command:
$client = new Predis\Client();
$client->getProfile()->defineCommand('lpushrand', 'ListPushRandomValue');
 
$response = $client->lpushrand('random_values', $seed = mt_rand());
Copy code

performance

Native test

Predis is a pure PHP extension, so its performance may be insufficient. But it should be enough in practical use. Here are some test data using PHP 5.5.6 and Redis 2.8:

21000 SET/second key and value All use 12 type size
21000 GET/second
 use _KEYS *_ Command at 0.130 30000 queries per second key
 Copy code

Extensions similar to Predis include: phpredis , an extension written in C. The test performance results are as follows:

30100 SET/second key and value All use 12 type size
29400 GET/second
 use _KEYS *_ Command at 0.035 30000 queries per second key
 Copy code

phpredis looks a lot faster. But in fact, the difference is not too much, and one is written in C and the other is a pure php extension. And the above test is very simple and not conclusive. Let's take a look at tests similar to those in a real production environment.

External network environment test

Here are some tests for connecting to the local machine. Now try connecting to the remote server:

Predis:
3200 SET/second key and value All use 12 type size
3200 GET/second
 use _KEYS *_ Command at 0.132 30000 queries per second key
 
phpredis:
3500 SET/second key and value All use 12 type size
3500 GET/second
 use _KEYS *_ Command at 0.045 30000 queries per second key
 Copy code

We can see that the efficiency of the two is similar, because the delay of the website will be a very important problem of performance. Predis can use the command channel, saving a lot of time.

Last choice

Predis can be compatible with various versions of redis (currently supports 1.2 to 2.8), and can be compatible with different versions through custom commands. phpredis has some advantages on this machine. Alternatively, you can use both.

Added by TheMayhem on Thu, 09 Dec 2021 09:42:00 +0200