Belgian living in Zürich, Switzerland
Building the internet for 10 years
http://seld.be
Symfony2, Composer and other OSS contributions
http://github.com/Seldaek
Working at Nelmio
http://nelm.io
Symfony2 & frontend performance consulting
SET key value
SET key value
> OK
SET key value
> OK
GET key
SET key value
> OK
GET key
> "value"
*3
$3
SET
$3
key
$5
value
+OK
*2
$3
GET
$3
key
$5
value
*3\r\n
$3\r\n
SET\r\n
$3\r\n
key\r\n
$5\r\n
value\r\n
+OK\r\n
*2\r\n
$3\r\n
GET\r\n
$3\r\n
key\r\n
$5\r\n
value\r\n
SET name Bob
SET age 20
MGET name age
> Bob
> 20
GETSET name Alice
> Bob
SETEX age 3 20
GET age
> 20
// .. 3 seconds later ..
GET age
> null
INCR count
> 1
INCR count
> 2
INCRBY count 3
> 5
HMSET user name Alice email alice@example.org
HGET user email
> alice@example.org
HKEYS user
> name
> email
HGETALL user
> name
> Alice
> email
> alice@example.org
RPUSH admins Alice
> 1
RPUSH admins Bob
> 2
LINDEX admins 0
> Alice
LLEN admins
> 2
RPOP admins
> Bob
SADD page:3:visitors 134
> 1
SADD page:3:visitors 253
> 1
SADD page:3:visitors 253
> 0
SCARD page:3:visitors
> 2
SMEMBERS page:3:visitors
> 134
> 253
SISMEMBER page:3:visitors 349
> 0
SADD page:6:visitors 253
SADD page:6:visitors 923
SADD page:6:visitors 13
SINTER page:3:visitors page:6:visitors
> 253
ZADD highscores 2930 Alice
ZADD highscores 1546 Bob
ZREVRANGE highscores 0 10 WITHSCORES
> Alice
> 2930
> Bob
> 1546
array('foo', 'bar')
shuffle(array('foo', 'bar'))
ksort(array(3 => 'foo', 1 => 'bar'))
SETNX name Alice
GET name
> Alice
SETNX name Bob
GET name
> Alice
INCR foo
GET foo
> 1
INCRBY foo 3
GET foo
> 4
SORT key
SORT key LIMIT 0 10 DESC
SORT key ALPHA
SORT page:6:visitors BY user_*->rank GET user_* DESC
SUBSCRIBE foo1
PSUBSCRIBE foo*
PUBLISH foo0 message
EVAL <body> <num_keys_in_args> [<arg1> <arg2> ... <arg_N>]
GET A
EVAL "return redis.call('get', KEYS[1])" 1 A
Example: Atomic Conditional Decrement, Client-Side
WATCH foo
$val = GET foo
$newVal = max(0, $val - 1); // decrement if foo > 0 client-side
MULTI
SET foo $newVal
EXEC
This may return -ERR.
Example: Atomic Conditional Decrement, Server-Side
EVAL "local value = tonumber(redis.call('get', KEYS[1]))
if value == nil
then
return {err="Value at key is not integer"}
end
if value > tonumber(ARGV[1])
then
value = value - 1
redis.call('set', KEYS[1], value)
end
return value" 1 foo 0
This can not fail.
A good example in these slides from Wooga
Cache generic results:
SETEX <pageid>:content 600 <data>
Store user read-state in sets
SADD <pageid>:views <userid>
Combine and render for each user
GET <pageid>:content
SISMEMBER <pageid>:views <userid>
LPUSH logs "Log message"
// keep the last 1000 entries
LTRIM logs 0 999
ZADD scores 4290 <playerid>
ZADD scores 390 <playerid2>
// ...
ZREVRANK scores <playerid> // 0
ZREVRANGE scores 0 10 WITHSCORES
Note: players will only be listed once since it is a set.
ZADD visits <unix> <userid>
ZADD visits 1327681399 52
ZADD visits 1327683245 18
ZRANGEBYSCORE visits <unix>-3600 <unix>
ZREMRANGEBYSCORE visits 0 <unix>-3600
Workers:
BRPOP queue
Application:
LPUSH queue "job description"
SETBIT click:<item>:<date> <userid> 1
GETBIT click:3:2012-01-28 55239
Comes with a session handler, sharding, up to date.
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->watch('x');
$val = $redis->get('x');
$newVal = max(0, $val - 1);
$result = $redis->multi()
->set('x', $newVal)
->exec();
echo $result !== false ? 'Success' : 'Race lost, try again';
Basic hiredis bindings, protocol parsing, low level.
$redis = phpiredis_connect('127.0.0.1', 6379);
phpiredis_command($redis, 'WATCH x');
$val = phpiredis_command($redis, 'GET x');
$newVal = max(0, $val - 1);
phpiredis_command($redis, 'MULTI');
phpiredis_command($redis, 'SET x '.$newVal);
$result = phpiredis_command($redis, 'EXEC');
echo $result !== false ? 'Success' : 'Race lost, try again';
Very complete, sharding, master/slave auto-select,
can use phpiredis for parsing.
$redis = new Predis\Client('tcp://10.0.0.1:6379');
$options = array(
'cas' => true, // enable Check-and-Set
'watch' => 'x',
'retry' => 10, // automatic retries
);
$result = $redis->multiExec($options, function($transaction) {
$val = $transaction->get('x');
$newVal = max(0, $val - 1);
$transaction->multi();
$transaction->set('x', $newVal);
});
echo $result !== false ? 'Success' : 'Race lost 10 times, giving up';
http://github.com/snc/SncRedisBundle (Symfony2 integration)