Project

General

Profile

1 27204 antonis.le
# Some frequently asked questions about Predis #
2
________________________________________________
3
4
### What is the point of Predis? ###
5
6
The main point of Predis is about offering a highly customizable and extensible client for Redis,
7
that can be easily extended by developers while still being reasonabily fast. With Predis you can
8
swap almost any class with your own custom implementation: you can have custom connection classes,
9
new distribution strategies for client-side sharding, or handlers to replace or add Redis commands.
10
All of this can be achieved without messing with the source code of the library and directly in your
11
own application. Given the fast pace at which Redis is developed and adds new features, this can be
12
a great asset since it allows developers to add new and still missing features or commands or change
13
the standard behaviour of the library without the need to break dependencies in production code (at
14
least to some degree).
15
16
### Does Predis support UNIX domain sockets and persistent connections? ###
17
18
Yes. Obviously persistent connections actually work only when using PHP configured as a persistent
19
process reused by the web server (see [PHP-FPM](http://php-fpm.org)).
20
21
### Does Predis support transparent (de)serialization of values? ###
22
23
No and it will not ever do that by default. The reason behind this decision is that serialization is
24
usually something that developers prefer to customize depending on their needs and can not be easily
25
generalized when using Redis because of the many possible access patterns for your data. This does
26
not mean that it is impossible to have such a feature since you can leverage the extensibility of
27
this library to define your own serialization-aware commands. You can find more details about how to
28
do that [on this issue](http://github.com/nrk/predis/issues/29#issuecomment-1202624).
29
30
### How can I force Predis to connect to Redis before sending any command? ###
31
32
Explicitly connecting to Redis is usually not needed since the client initializes connections lazily
33
only when they are needed. Admittedly, this behavior can be inconvenient in certain scenarios when
34
you absolutely need to perform an upfront check to determine if the server is up and running and
35
eventually catch exceptions on failures. Forcing the client to open the underlying connection can be
36
done by invoking `Predis\Client::connect()`:
37
38
```php
39
$client = new Predis\Client();
40
41
try {
42
    $client->connect();
43
} catch (Predis\Connection\ConnectionException $exception) {
44
    // We could not connect to Redis! Your handling code goes here.
45
}
46
47
$client->info();
48
```
49
50
### How Predis abstracts Redis commands? ###
51
52
The approach used to implement Redis commands is quite simple: by default each command follows the
53
same signature as defined on the [Redis documentation](http://redis.io/commands) which makes things
54
pretty easy if you already know how Redis works or you need to look up how to use certain commands.
55
Alternatively, variadic commands can accept an array for keys or values (depending on the command)
56
instead of a list of arguments. Commands such as [`RPUSH`](http://redis.io/commands/rpush) and
57
[`HMSET`](http://redis.io/commands/hmset) are great examples:
58
59
```php
60
$client->rpush('my:list', 'value1', 'value2', 'value3');             // plain method arguments
61
$client->rpush('my:list', ['value1', 'value2', 'value3']);           // single argument array
62
63
$client->hmset('my:hash', 'field1', 'value1', 'field2', 'value2');   // plain method arguments
64
$client->hmset('my:hash', ['field1'=>'value1', 'field2'=>'value2']); // single named array
65
```
66
67
An exception to this rule is [`SORT`](http://redis.io/commands/sort) for which modifiers are passed
68
[using a named array](tests/Predis/Command/KeySortTest.php#L54-L75).
69
70
71
# Speaking about performances... #
72
_________________________________________________
73
74
75
### Predis is a pure-PHP implementation: it can not be fast enough! ###
76
77
It really depends, but most of the times the answer is: _yes, it is fast enough_. I will give you a
78
couple of easy numbers with a simple test that uses a single client and is executed by PHP 5.5.6
79
against a local instance of Redis 2.8 that runs under Ubuntu 13.10 on a Intel Q6600:
80
81
```
82
21000 SET/sec using 12 bytes for both key and value.
83
21000 GET/sec while retrieving the very same values.
84
0.130 seconds to fetch 30000 keys using _KEYS *_.
85
```
86
87
How does it compare with [__phpredis__](http://github.com/nicolasff/phpredis), a nice C extension
88
providing an efficient client for Redis?
89
90
```
91
30100 SET/sec using 12 bytes for both key and value
92
29400 GET/sec while retrieving the very same values
93
0.035 seconds to fetch 30000 keys using "KEYS *"".
94
```
95
96
Wow __phpredis__ seems much faster! Well, we are comparing a C extension with a pure-PHP library so
97
lower numbers are quite expected but there is a fundamental flaw in them: is this really how you are
98
going to use Redis in your application? Are you really going to send thousands of commands using a
99
for-loop on each page request using a single client instance? If so... well I guess you are probably
100
doing something wrong. Also, if you need to `SET` or `GET` multiple keys you should definitely use
101
commands such as `MSET` and `MGET`. You can also use pipelining to get more performances when this
102
technique can be used.
103
104
There is one more thing: we have tested the overhead of Predis by connecting on a localhost instance
105
of Redis but how these numbers change when we hit the physical network by connecting to remote Redis
106
instances?
107
108
```
109
Using Predis:
110
3200 SET/sec using 12 bytes for both key and value
111
3200 GET/sec while retrieving the very same values
112
0.132 seconds to fetch 30000 keys using "KEYS *".
113
114
Using phpredis:
115
3500 SET/sec using 12 bytes for both key and value
116
3500 GET/sec while retrieving the very same values
117
0.045 seconds to fetch 30000 keys using "KEYS *".
118
```
119
120
There you go, you get almost the same average numbers and the reason is simple: network latency is a
121
real performance killer and you cannot do (almost) anything about that. As a disclaimer, remember
122
that we are measuring the overhead of client libraries implementations and the effects of network
123
round-trip times, so we are not really measuring how fast Redis is. Redis shines best with thousands
124
of concurrent clients doing requests! Also, actual performances should be measured according to how
125
your application will use Redis.
126
127
### I am convinced, but performances for multi-bulk responses are still worse ###
128
129
Fair enough, but there is an option available if you need even more speed and consists on installing
130
__[phpiredis](http://github.com/nrk/phpiredis)__ (note the additional _i_ in the name) and let the
131
client use it. __phpiredis__ is another C extension that wraps __hiredis__ (the official C client
132
library for Redis) with a thin layer exposing its features to PHP. You can then choose between two
133
different connection classes:
134
135
  - `Predis\Connection\PhpiredisStreamConnection` (using native PHP streams).
136
  - `Predis\Connection\PhpiredisConnection` (requires `ext-socket`).
137
138
You will now get the benefits of a faster protocol serializer and parser just by adding a couple of
139
lines of code:
140
141
```php
142
$client = new Predis\Client('tcp://127.0.0.1', array(
143
    'connections' => array(
144
        'tcp'  => 'Predis\Connection\PhpiredisStreamConnection',
145
        'unix' => 'Predis\Connection\PhpiredisConnection',
146
    ),
147
));
148
```
149
150
Dead simple. Nothing changes in the way you use the library in your application. So how fast is it
151
our basic benchmark script now? There are not much improvements for inline or short bulk responses
152
like the ones returned by `SET` and `GET`, but the speed for parsing multi-bulk responses is now on
153
par with phpredis:
154
155
```
156
Fatching 30000 keys with _KEYS *_ using Predis paired with phpiredis::
157
158
0.035 seconds from a local Redis instance
159
0.047 seconds from a remote Redis instance
160
```
161
162
### If I need an extension to get better performances, why not using phpredis? ###
163
164
Good question. Generically speaking if you need absolute uber-speed using Redis on the localhost and
165
you do not care about abstractions built around some Redis features such as MULTI / EXEC, or if you
166
do not need any kind of extensibility or guaranteed backwards compatibility with different versions
167
of Redis (Predis currently supports from 1.2 up to 2.8 and the current development version), then
168
using __phpredis__ makes absolutely sense. Otherwise, Predis is perfect for the job and by adding
169
__phpiredis__ you can get a nice speed bump almost for free.