Successfully reported this slideshow.
Your SlideShare is downloading. ×

Redis for the Everyday Developer

Loading in …3
×

Check these out next

1 of 196
1 of 196

Redis for the Everyday Developer

Download to read offline

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.

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.

More Related Content

Related Books

Free with a 30 day trial from Scribd

See all

Redis for the Everyday Developer

  1. Redis For The Everyday Developer Ross Tuck Confoo March 1st, 2013
  2. Who Am I?
  3. Ross Tuck
  4. Team Lead at Ibuildings Codemonkey HTTP nut Hat 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 as a data structure server...”
  13. Defancypants
  14. Redis Server A Server B
  15. In-Memory
  16. In-Memory
  17. The Cool Stuff
  18. Fast.
  19. Demo.
  20. Oh wait, it's already done.
  21. 120,000~ ops per sec
  22. Flexible.
  23. (optionally) Persistent.
  24. Replication Pub/Sub Transactions Scripting Slices Dices Makes 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 MySQL Memcache
  35. PHP MySQL Memcache
  36. PHP MySQL Redis
  37. It's 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 value homepage_message omg cheezburgers...
  54. key value homepage_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 Easier More 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: 1 100.00% <= 0 milliseconds 119047.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 as a data structure server...”
  69. “...since keys can contain strings, hashes, lists, sets and sorted sets.”
  70. $redis = array();
  71. Generic Hash List Set Sorted Set
  72. Generic Hash // strings and numbers List $redis['ross:mood'] = "happy"; Set $redis['foo'] = 9; Sorted Set
  73. Generic Hash // associative array List $redis['foo']['name'] = 'Bob'; $redis['foo']['age'] = 31; Set Sorted Set Objects, forms, records
  74. Generic Hash // not associative List $redis['foo'][] = 'zip'; Set $redis['foo'][] = 'zap'; Sorted Set Lists, stacks, queues
  75. Generic // No dupes, no order Hash shuffle( List array_unique($redis['foo']) Set ); Sorted Set Relations, stats, matching
  76. Generic Hash // Ordered by *score* List array_unique($redis['foo']); Set Sorted Set Curing cancer, world peace Sets but with order or scores
  77. Y U NO STOP LISTING THINGS
  78. Generic Hash List Set Sorted Set
  79. Generic Hash List Set Sorted 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. That's 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 Articles INNER JOIN Authors ON (complicated joins) -- More joins WHERE (complicated logic) LIMIT 0, 20
  99. SELECT Articles.id FROM Articles INNER JOIN Authors ON (complicated joins) -- More joins WHERE (complicated logic)
  100. $client->lpush('search:a17f3', $ids);
  101. $client->lrange('search:a17f3', $limit, $offset);
  102. SELECT * FROM Articles INNER JOIN Authors ON (complicated joins) -- More joins WHERE Articles.id IN (1, 2, 3)
  103. Use Case #6: Recently Viewed
  104. Generic Hash List Set Sorted Set
  105. Generic Hash List No duplicates Set Sorted Set
  106. Generic Hash List Set Needs to be ordered Sorted Set
  107. Generic Hash List Set Sorted 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 Redis Node.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. yet Not 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:pending' 'jobs: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 arguments local 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: sweet EVAL 'local first...' 2 jesse chester // jesse: sweet // chester: dude
  167. Eval != Evil *Offer only applies in Redis-Land. . Void where pedantic
  168. Don't 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

×