Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Redis For TheEveryday Developer                     Ross Tuck                        Confoo                 March 1st, 2013
Who Am I?
Ross Tuck
Team Lead at IbuildingsCodemonkeyHTTP nutHat guy
@rosstuck
Boring.
NoSQL
NoNoSQL
Evaluation
•   Created by Salvatore Sanfilippo ( @antirez )•   Sponsored by VMware•   4 years old•   redis.io
“Redis is an open source, advanced          key-value store.”
“It is often referred to asa data structure server...”
Defancypants
RedisServer A           Server B
In-Memory
In-Memory
The Cool Stuff
Fast.
Demo.
Oh wait, its already done.
120,000~ ops per sec
Flexible.
(optionally)Persistent.
Replication     Pub/Sub   Transactions     Scripting      Slices      DicesMakes julienne fries
“Well, Ross, that sounds cool...”
+MySQL       Redis
MySQL  +Redis 4ever
Setup
apt-get install redis-server                  Easy but old
http://redis.io/download
PHP Libraries• 5.3+: Predis• 5.2: Predis or Rediska• C Extension: phpredis• redis-cli
$client = new PredisClient();
The Surprise Ending
PHP MySQLMemcache
PHP MySQLMemcache
PHPMySQLRedis
Its about 80% cases.
Use Case #1: Caching
Redis has commands.
Commands have parameters.
Think functions.
$client->commandGoesHere($params, $go, $here);
SET
$client->set(ross:mood, nervous);// Later$client->get(ross:mood); // returns “nervous”
$client->set(ross:mood, nervous);$client->expire(ross:mood, 5);// 4 seconds later...$client->get(ross:mood); // “nervous”/...
$client->set(ross:mood, nervous);$client->expire(ross:mood, 5);
$client->setex(ross:mood, 5, nervous);
Great for caching
Ideal for sessions
Use Case #2: Simple Data
Search...      omg cheezburgers in the lunchroom      today. Better hurry if u want 1!!! ^_^How do I store this?
key   value
key                valuehomepage_message   omg cheezburgers...
key                valuehomepage_message   omg cheezburgers...tps_reports        new cover pages on...
You already know it.
$client->set(home:message, cheezburgers...);$client->get(home:message);
Equal EasierMore Fun
Use Case #3: Hit Counters
increment
$client->incr(page:42:views);   // 1$client->incr(page:42:views);   // 2$client->incr(page:42:views);   // 3
Redis is hard ;)
How is this better?
Fast?
redis-benchmark====== INCR ======  10000 requests completed in 0.08 seconds  50 parallel clients  3 bytes payload  keep al...
Fast enough.
$client->incr(cookies:eaten);$client->incrBy(cookies:eaten, 2);$client->incrByFloat(cookies:eaten, 0.5);   version 2.6+
Use Case #4: Latest News
“It is often referred to asa data structure server...”
“...since keys can contain strings, hashes,         lists, sets and sorted sets.”
$redis = array();
GenericHashListSetSorted Set
GenericHash         // strings and numbersList         $redis[ross:mood] = "happy";Set          $redis[foo] = 9;Sorted Set
GenericHash         // associative arrayList         $redis[foo][name] = Bob;             $redis[foo][age] = 31;SetSorted ...
GenericHash         // not associativeList         $redis[foo][] = zip;Set          $redis[foo][] = zap;Sorted Set        ...
Generic             // No dupes, no orderHash             shuffle(List                  array_unique($redis[foo])Set      ...
GenericHash         // Ordered by *score*List         array_unique($redis[foo]);SetSorted Set             Curing cancer, w...
Y U NO STOPLISTING THINGS
GenericHashListSetSorted Set
GenericHashListSetSorted Set
// Code$client->lpush(news:latest, Aliens Attack!);// Redis[Aliens Attack!]
// 2 hours later...$client->lpush(news:latest, Takei 2016);// Redis[Takei 2016, Aliens Attack!]
// That evening...$client->lpush(news:latest, Eggs = Cancer!);// Redis[Eggs = Cancer!, Takei 2016, Aliens Attack!]
Recap
// Code$client->lpush(news:latest, Aliens Attack!);$client->lpush(news:latest, Takei 2016);$client->lpush(news:latest, Egg...
Getting it back out?
Start Index$client->lrange(news:latest, 0, 1);                                  En d Index
var_dump($client->lrange(news:latest, 0, 1));array(2) {     [0]=>   string(14) "Eggs = Cancer!"     [1]=>   string(10) "Ta...
Thats it. Really.
What about size?
$client->lpush(news:latest, Free Jetpacks!);$client->lpush(news:latest, Elvis Found!);$client->lpush(news:latest, Takei Wi...
ltrim
$client->ltrim(news:latest, 0, 2);// Only the three latest stories remain!
Cron
or simpler...
$client->lpush(news:latest, Cats Leave Euro);$client->ltrim(news:latest, 0, 2);
Great option for notifications
Use Case #5: Tricksy Caching
SELECT * FROM ArticlesINNER JOIN Authors ON (complicated joins)-- More joinsWHERE (complicated logic)LIMIT 0, 20
SELECT Articles.id FROM ArticlesINNER JOIN Authors ON (complicated joins)-- More joinsWHERE (complicated logic)
$client->lpush(search:a17f3, $ids);
$client->lrange(search:a17f3, $limit, $offset);
SELECT * FROM ArticlesINNER JOIN Authors ON (complicated joins)-- More joinsWHERE Articles.id IN (1, 2, 3)
Use Case #6: Recently Viewed
GenericHashListSetSorted Set
GenericHashList         No duplicatesSetSorted Set
GenericHashListSet          Needs to be orderedSorted Set
GenericHashListSetSorted Set   Just Right
zadd
$client->zadd(mykey, 1, mydata);                             Any integer                                     t            ...
$client->zadd(recent, 1, /p/first);
$client->zadd(recent, time(), /p/first);
$client->zadd(recent, 1338020901, /p/first);$client->zadd(recent, 1338020902, /p/second);$client->zadd(recent, 1338020903,...
Reading it back out?
$client->zrange(recent, 0, 2);array(3) {    [0]=> string(8) "/p/first"    [1]=> string(9) "/p/second"    [2]=> string(8) "...
Reverse$client->zrevrange(recent, 0, 2);array(3) {    [0]=> string(9) "/p/fourth"    [1]=> string(8) "/p/third"    [2]=> s...
Duplicates?
$client->zadd(recent, 1338020901, /p/first);// later...$client->zadd(recent, 1338020928, /p/first);
$client->zrevrange(recent, 0, 2);array(3) {    [0]=> string(8) "/p/first"    [1]=> string(9) "/p/fourth"    [2]=> string(8...
Cool.
Other things we can do?
$client->zrangebyscore(recent, $low, $high);
$yesterday = time()-(60*60*24);$client->zrangebyscore(recent, $yesterday, +inf);
Intersections
zinterstore
$client->zinterstore(omg, 2, recent, favorite);$client->zrange(omg, 0, 4);
Deletion
zrem
zremrangebyscore
$yesterday = time()-(60*60*24);$client->zremrangebyscore(     recent, -inf, $yesterday);
We can do a lot.
Scores can be anything.
Use Case #7: Sharing Data
PHP          RedisNode.js           Python
•   ActionScript   •   Java•   C              •   Lua•   C#             •   Node.js•   C++            •   Objective-C•   C...
$client = new PredisClient();$client->set(foo, bar);
var redis = require("redis");var client = redis.createClient();client.get("foo", redis.print);
Step Further...
Pub/Sub
$client->publish(bids:42, $13.01);
client.on("message", function (channel, message) {      console.log(channel + "= " + message);});client.subscribe("bids:42...
yetNot everyday
Use Case #8: Worker Queues
$client->lpush(jobs:pending, clear_cache);
$client->lpush(jobs:pending, {"do":"email", …});
$client->lpush(jobs:pending, job:45);
// worker$client = new PredisClient(array(       read_write_timeout => -1));do {       $job = $client->brpop(jobs:pending,...
This will work.
However...
Things break.
Things break.
Clients break.
Clients break.
Clients crash.
do {       $job = $client->brpop(jobs:pending, 0);       doJob($job);} while(true);
Multiple keys is the redis way.
jobs:pendingjobs:working
What we need is:   blocking                   rpop                   lpush
brpoplpush                .      No, really
do {       $job = $client->brpoplpush(            jobs:pending, jobs:working, 0       );       doJob($job);} while(true);
do {       $job = $client->brpoplpush(            jobs:pending, jobs:working, 0       );       if(doJob($job)) {          ...
Use Case #9: Scripted Commands
Use Case #9: Impressing People
$client->set(jesse, dude);$client->set(chester, sweet);
Lua
var                          argumentslocal first = redis.call(get, KEYS[1]);local second = redis.call(get, KEYS[2]);redis...
// jesse: dude// chester: sweetEVAL local first... 2 jesse chester// jesse: sweet// chester: dude
Eval != Evil   *Offer  only applies   in Redis-Land.                       .    Void where pedantic
Dont over do it.
Reusing scripts?
SCRIPT LOAD local first...// 591d1b681192f606d8cb658e1e173e771a90e60e
EVAL local first... 2 jesse chester
EVALSHA 591d1... 2 jesse chester
Sweet.
Epilogue
Simple = Powerful
Fun.
Keep it in RAM.
Extensible + Ecosystem
Great docs.Use them.
Bad for the DB?Might be good for Redis.
Bad for the DB?Might be good for Redis.
IAEA     Kotaku@svdgraaf               Alltheragefaces                   QuickMeme
http://joind.in/7971
Redis for the Everyday Developer
Redis for the Everyday Developer
Redis for the Everyday Developer
Redis for the Everyday Developer
Redis for the Everyday Developer
Redis for the Everyday Developer
Redis for the Everyday Developer
Redis for the Everyday Developer
Redis for the Everyday Developer
Redis for the Everyday Developer
Redis for the Everyday Developer
Redis for the Everyday Developer
Redis for the Everyday Developer
Upcoming SlideShare
Loading in …5
×

Redis for the Everyday Developer

31,850 views

Published on

As presented at Confoo 2013.

More than some arcane NoSQL tool, Redis is a simple but powerful swiss army knife you can begin using today.

This talk introduces the audience to Redis and focuses on using it to cleanly solve common problems. Along the way, we'll see how Redis can be used as an alternative to several common PHP tools.

Redis for the Everyday Developer

  1. Redis For TheEveryday Developer Ross Tuck Confoo March 1st, 2013
  2. Who Am I?
  3. Ross Tuck
  4. Team Lead at IbuildingsCodemonkeyHTTP nutHat guy
  5. @rosstuck
  6. Boring.
  7. NoSQL
  8. NoNoSQL
  9. Evaluation
  10. • Created by Salvatore Sanfilippo ( @antirez )• Sponsored by VMware• 4 years old• redis.io
  11. “Redis is an open source, advanced key-value store.”
  12. “It is often referred to asa data structure server...”
  13. Defancypants
  14. RedisServer A Server B
  15. In-Memory
  16. In-Memory
  17. The Cool Stuff
  18. Fast.
  19. Demo.
  20. Oh wait, its already done.
  21. 120,000~ ops per sec
  22. Flexible.
  23. (optionally)Persistent.
  24. Replication Pub/Sub Transactions Scripting Slices DicesMakes julienne fries
  25. “Well, Ross, that sounds cool...”
  26. +MySQL Redis
  27. MySQL +Redis 4ever
  28. Setup
  29. apt-get install redis-server Easy but old
  30. http://redis.io/download
  31. PHP Libraries• 5.3+: Predis• 5.2: Predis or Rediska• C Extension: phpredis• redis-cli
  32. $client = new PredisClient();
  33. The Surprise Ending
  34. PHP MySQLMemcache
  35. PHP MySQLMemcache
  36. PHPMySQLRedis
  37. Its about 80% cases.
  38. Use Case #1: Caching
  39. Redis has commands.
  40. Commands have parameters.
  41. Think functions.
  42. $client->commandGoesHere($params, $go, $here);
  43. SET
  44. $client->set(ross:mood, nervous);// Later$client->get(ross:mood); // returns “nervous”
  45. $client->set(ross:mood, nervous);$client->expire(ross:mood, 5);// 4 seconds later...$client->get(ross:mood); // “nervous”// 5 seconds later...$client->get(ross:mood); // null
  46. $client->set(ross:mood, nervous);$client->expire(ross:mood, 5);
  47. $client->setex(ross:mood, 5, nervous);
  48. Great for caching
  49. Ideal for sessions
  50. Use Case #2: Simple Data
  51. Search... omg cheezburgers in the lunchroom today. Better hurry if u want 1!!! ^_^How do I store this?
  52. key value
  53. key valuehomepage_message omg cheezburgers...
  54. key valuehomepage_message omg cheezburgers...tps_reports new cover pages on...
  55. You already know it.
  56. $client->set(home:message, cheezburgers...);$client->get(home:message);
  57. Equal EasierMore Fun
  58. Use Case #3: Hit Counters
  59. increment
  60. $client->incr(page:42:views); // 1$client->incr(page:42:views); // 2$client->incr(page:42:views); // 3
  61. Redis is hard ;)
  62. How is this better?
  63. Fast?
  64. redis-benchmark====== INCR ====== 10000 requests completed in 0.08 seconds 50 parallel clients 3 bytes payload keep alive: 1100.00% <= 0 milliseconds119047.62 requests per second
  65. Fast enough.
  66. $client->incr(cookies:eaten);$client->incrBy(cookies:eaten, 2);$client->incrByFloat(cookies:eaten, 0.5); version 2.6+
  67. Use Case #4: Latest News
  68. “It is often referred to asa data structure server...”
  69. “...since keys can contain strings, hashes, lists, sets and sorted sets.”
  70. $redis = array();
  71. GenericHashListSetSorted Set
  72. GenericHash // strings and numbersList $redis[ross:mood] = "happy";Set $redis[foo] = 9;Sorted Set
  73. GenericHash // associative arrayList $redis[foo][name] = Bob; $redis[foo][age] = 31;SetSorted Set Objects, forms, records
  74. GenericHash // not associativeList $redis[foo][] = zip;Set $redis[foo][] = zap;Sorted Set Lists, stacks, queues
  75. Generic // No dupes, no orderHash shuffle(List array_unique($redis[foo])Set );Sorted Set Relations, stats, matching
  76. GenericHash // Ordered by *score*List array_unique($redis[foo]);SetSorted Set Curing cancer, world peace Sets but with order or scores
  77. Y U NO STOPLISTING THINGS
  78. GenericHashListSetSorted Set
  79. GenericHashListSetSorted Set
  80. // Code$client->lpush(news:latest, Aliens Attack!);// Redis[Aliens Attack!]
  81. // 2 hours later...$client->lpush(news:latest, Takei 2016);// Redis[Takei 2016, Aliens Attack!]
  82. // That evening...$client->lpush(news:latest, Eggs = Cancer!);// Redis[Eggs = Cancer!, Takei 2016, Aliens Attack!]
  83. Recap
  84. // Code$client->lpush(news:latest, Aliens Attack!);$client->lpush(news:latest, Takei 2016);$client->lpush(news:latest, Eggs = Cancer!);// Redis[Eggs = Cancer!, Takei 2016, Aliens Attack!]
  85. Getting it back out?
  86. Start Index$client->lrange(news:latest, 0, 1); En d Index
  87. var_dump($client->lrange(news:latest, 0, 1));array(2) { [0]=> string(14) "Eggs = Cancer!" [1]=> string(10) "Takei 2016"}
  88. Thats it. Really.
  89. What about size?
  90. $client->lpush(news:latest, Free Jetpacks!);$client->lpush(news:latest, Elvis Found!);$client->lpush(news:latest, Takei Wins!);//...and so on...
  91. ltrim
  92. $client->ltrim(news:latest, 0, 2);// Only the three latest stories remain!
  93. Cron
  94. or simpler...
  95. $client->lpush(news:latest, Cats Leave Euro);$client->ltrim(news:latest, 0, 2);
  96. Great option for notifications
  97. Use Case #5: Tricksy Caching
  98. SELECT * FROM ArticlesINNER JOIN Authors ON (complicated joins)-- More joinsWHERE (complicated logic)LIMIT 0, 20
  99. SELECT Articles.id FROM ArticlesINNER JOIN Authors ON (complicated joins)-- More joinsWHERE (complicated logic)
  100. $client->lpush(search:a17f3, $ids);
  101. $client->lrange(search:a17f3, $limit, $offset);
  102. SELECT * FROM ArticlesINNER JOIN Authors ON (complicated joins)-- More joinsWHERE Articles.id IN (1, 2, 3)
  103. Use Case #6: Recently Viewed
  104. GenericHashListSetSorted Set
  105. GenericHashList No duplicatesSetSorted Set
  106. GenericHashListSet Needs to be orderedSorted Set
  107. GenericHashListSetSorted Set Just Right
  108. zadd
  109. $client->zadd(mykey, 1, mydata); Any integer t or floa
  110. $client->zadd(recent, 1, /p/first);
  111. $client->zadd(recent, time(), /p/first);
  112. $client->zadd(recent, 1338020901, /p/first);$client->zadd(recent, 1338020902, /p/second);$client->zadd(recent, 1338020903, /p/third);$client->zadd(recent, 1338020904, /p/fourth);
  113. Reading it back out?
  114. $client->zrange(recent, 0, 2);array(3) { [0]=> string(8) "/p/first" [1]=> string(9) "/p/second" [2]=> string(8) "/p/third"}
  115. Reverse$client->zrevrange(recent, 0, 2);array(3) { [0]=> string(9) "/p/fourth" [1]=> string(8) "/p/third" [2]=> string(9) "/p/second"}
  116. Duplicates?
  117. $client->zadd(recent, 1338020901, /p/first);// later...$client->zadd(recent, 1338020928, /p/first);
  118. $client->zrevrange(recent, 0, 2);array(3) { [0]=> string(8) "/p/first" [1]=> string(9) "/p/fourth" [2]=> string(8) "/p/third"}
  119. Cool.
  120. Other things we can do?
  121. $client->zrangebyscore(recent, $low, $high);
  122. $yesterday = time()-(60*60*24);$client->zrangebyscore(recent, $yesterday, +inf);
  123. Intersections
  124. zinterstore
  125. $client->zinterstore(omg, 2, recent, favorite);$client->zrange(omg, 0, 4);
  126. Deletion
  127. zrem
  128. zremrangebyscore
  129. $yesterday = time()-(60*60*24);$client->zremrangebyscore( recent, -inf, $yesterday);
  130. We can do a lot.
  131. Scores can be anything.
  132. Use Case #7: Sharing Data
  133. PHP RedisNode.js Python
  134. • ActionScript • Java• C • Lua• C# • Node.js• C++ • Objective-C• Clojure • Perl• Common Lisp • PHP• Erlang • Pure Data• Fancy • Python• Go • Ruby• Haskell • Scala• haXe • Smalltalk• Io • Tcl
  135. $client = new PredisClient();$client->set(foo, bar);
  136. var redis = require("redis");var client = redis.createClient();client.get("foo", redis.print);
  137. Step Further...
  138. Pub/Sub
  139. $client->publish(bids:42, $13.01);
  140. client.on("message", function (channel, message) { console.log(channel + "= " + message);});client.subscribe("bids:42");// prints “bids:42= $13.01”
  141. yetNot everyday
  142. Use Case #8: Worker Queues
  143. $client->lpush(jobs:pending, clear_cache);
  144. $client->lpush(jobs:pending, {"do":"email", …});
  145. $client->lpush(jobs:pending, job:45);
  146. // worker$client = new PredisClient(array( read_write_timeout => -1));do { $job = $client->brpop(jobs:pending, 0); doJob($job);} while(true);
  147. This will work.
  148. However...
  149. Things break.
  150. Things break.
  151. Clients break.
  152. Clients break.
  153. Clients crash.
  154. do { $job = $client->brpop(jobs:pending, 0); doJob($job);} while(true);
  155. Multiple keys is the redis way.
  156. jobs:pendingjobs:working
  157. What we need is: blocking rpop lpush
  158. brpoplpush . No, really
  159. do { $job = $client->brpoplpush( jobs:pending, jobs:working, 0 ); doJob($job);} while(true);
  160. do { $job = $client->brpoplpush( jobs:pending, jobs:working, 0 ); if(doJob($job)) { $client->lrem(jobs:working, 0, $job); }} while(true);
  161. Use Case #9: Scripted Commands
  162. Use Case #9: Impressing People
  163. $client->set(jesse, dude);$client->set(chester, sweet);
  164. Lua
  165. var argumentslocal first = redis.call(get, KEYS[1]);local second = redis.call(get, KEYS[2]);redis.call(set, KEYS[1], second);redis.call(set, KEYS[2], first);return {first, second};
  166. // jesse: dude// chester: sweetEVAL local first... 2 jesse chester// jesse: sweet// chester: dude
  167. Eval != Evil *Offer only applies in Redis-Land. . Void where pedantic
  168. Dont over do it.
  169. Reusing scripts?
  170. SCRIPT LOAD local first...// 591d1b681192f606d8cb658e1e173e771a90e60e
  171. EVAL local first... 2 jesse chester
  172. EVALSHA 591d1... 2 jesse chester
  173. Sweet.
  174. Epilogue
  175. Simple = Powerful
  176. Fun.
  177. Keep it in RAM.
  178. Extensible + Ecosystem
  179. Great docs.Use them.
  180. Bad for the DB?Might be good for Redis.
  181. Bad for the DB?Might be good for Redis.
  182. IAEA Kotaku@svdgraaf Alltheragefaces QuickMeme
  183. http://joind.in/7971

×