Slide 1

Slide 1 text

Ross Tuck Redis For The Everyday Developer Northeast PHP August 11th, #nephp

Slide 2

Slide 2 text

Who Am I?

Slide 3

Slide 3 text

Ross Tuck

Slide 4

Slide 4 text

Team Lead at Ibuildings Codemonkey HTTP nut Hat guy

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

@rosstuck

Slide 7

Slide 7 text

Boring.

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

NoSQL

Slide 10

Slide 10 text

NoNoSQL

Slide 11

Slide 11 text

Evaluation

Slide 12

Slide 12 text

• Created by Salvatore Sanfilippo ( @antirez ) • Sponsored by VMware • 3 years old • redis.io

Slide 13

Slide 13 text

“Redis is an open source, advanced key-value store.”

Slide 14

Slide 14 text

“It is often referred to as a data structure server...”

Slide 15

Slide 15 text

Defancypants

Slide 16

Slide 16 text

Server A Server B Redis

Slide 17

Slide 17 text

In-Memory

Slide 18

Slide 18 text

In-Memory

Slide 19

Slide 19 text

The Cool Stuff

Slide 20

Slide 20 text

Fast.

Slide 21

Slide 21 text

Demo.

Slide 22

Slide 22 text

Oh wait, it's already done.

Slide 23

Slide 23 text

120,000~ ops per sec

Slide 24

Slide 24 text

Flexible.

Slide 25

Slide 25 text

(optionally) Persistent.

Slide 26

Slide 26 text

Replication Pub/Sub Scripting Transactions Slices Dices Makes julienne fries

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

MySQL Redis +

Slide 29

Slide 29 text

MySQL + Redis 4ever

Slide 30

Slide 30 text

Setup

Slide 31

Slide 31 text

apt-get install redis-server Easy but old

Slide 32

Slide 32 text

http://redis.io/download

Slide 33

Slide 33 text

PHP Libraries • 5.3+: Predis • 5.2: Predis or Rediska • C Extension: phpredis • redis-cli

Slide 34

Slide 34 text

$client = new \Predis\Client();

Slide 35

Slide 35 text

The Surprise Ending

Slide 36

Slide 36 text

PHP MySQL Memcache

Slide 37

Slide 37 text

PHP MySQL Memcache

Slide 38

Slide 38 text

PHP MySQL Redis

Slide 39

Slide 39 text

It's about 80% cases.

Slide 40

Slide 40 text

Use Case #1: Caching

Slide 41

Slide 41 text

Redis has commands.

Slide 42

Slide 42 text

Commands have parameters.

Slide 43

Slide 43 text

Think functions.

Slide 44

Slide 44 text

$client->commandGoesHere($params, $go, $here);

Slide 45

Slide 45 text

SET

Slide 46

Slide 46 text

$client->set('ross:mood', 'nervous'); // Later $client->get('ross:mood'); // returns “nervous”

Slide 47

Slide 47 text

$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

Slide 48

Slide 48 text

$client->set('ross:mood', 'nervous'); $client->expire('ross:mood', 5);

Slide 49

Slide 49 text

$client->setex('ross:mood', 5, 'nervous');

Slide 50

Slide 50 text

Great for caching

Slide 51

Slide 51 text

Use Case #2: Session Storage

Slide 52

Slide 52 text

You already know it.

Slide 53

Slide 53 text

Use Case #3: Hit Counters

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

increment

Slide 56

Slide 56 text

$client->incr('page:42:views'); $client->incr('page:42:views'); $client->incr('page:42:views'); // 1 // 2 // 3

Slide 57

Slide 57 text

Redis is hard ;)

Slide 58

Slide 58 text

How is this better?

Slide 59

Slide 59 text

No content

Slide 60

Slide 60 text

Fast?

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

Fast enough.

Slide 63

Slide 63 text

$client->incr('cookies:eaten'); $client->incrBy('cookies:eaten', 2); $client->incrByFloat('cookies:eaten', 0.5); version 2.6+

Slide 64

Slide 64 text

Use Case #4: Latest News

Slide 65

Slide 65 text

No content

Slide 66

Slide 66 text

“It is often referred to as a data structure server...”

Slide 67

Slide 67 text

“...since keys can contain strings, hashes, lists, sets and sorted sets.”

Slide 68

Slide 68 text

$redis = array();

Slide 69

Slide 69 text

Generic Hash List Set Sorted Set

Slide 70

Slide 70 text

Generic Hash List Set Sorted Set // strings and numbers $redis['ross:mood'] = "happy"; $redis['foo'] = 9;

Slide 71

Slide 71 text

Generic Hash List Set Sorted Set // associative array $redis['foo']['name'] = 'Bob'; $redis['foo']['age'] = 31; Objects, forms, records

Slide 72

Slide 72 text

Generic Hash List Set Sorted Set // not associative $redis['foo'][] = 'zip'; $redis['foo'][] = 'zap'; Lists, stacks, queues

Slide 73

Slide 73 text

Generic Hash List Set Sorted Set // No dupes, no order shuffle( array_unique($redis['foo']) ); Relations, stats, matching

Slide 74

Slide 74 text

Generic Hash List Set Sorted Set // Ordered by *score* array_unique($redis['foo']); Curing cancer, world peace Sets but with order or scores

Slide 75

Slide 75 text

Y U NO STOP Y U NO STOP LISTING THINGS LISTING THINGS

Slide 76

Slide 76 text

Generic Hash List Set Sorted Set

Slide 77

Slide 77 text

Generic Hash List Set Sorted Set

Slide 78

Slide 78 text

// Code $client->lpush('news:latest', 'Aliens Attack!'); // Redis ['Aliens Attack!']

Slide 79

Slide 79 text

// Redis ['Takei 2012', 'Aliens Attack!'] // 2 hours later... $client->lpush('news:latest', 'Takei 2012');

Slide 80

Slide 80 text

// That evening... $client->lpush('news:latest', 'Eggs = Cancer!'); // Redis ['Eggs = Cancer!', 'Takei 2012', 'Aliens Attack!']

Slide 81

Slide 81 text

Recap

Slide 82

Slide 82 text

// Code $client->lpush('news:latest', 'Aliens Attack!'); $client->lpush('news:latest', 'Takei 2012'); $client->lpush('news:latest', 'Eggs = Cancer!'); // Redis ['Eggs = Cancer!', 'Takei 2012', 'Aliens Attack!']

Slide 83

Slide 83 text

Getting it back out?

Slide 84

Slide 84 text

$client->lrange('news:latest', 0, 1); End Index Start Index

Slide 85

Slide 85 text

var_dump( $client->lrange('news:latest', 0, 1) ); array(2) { [0]=> string(14) "Eggs = Cancer!" [1]=> string(10) "Takei 2012" }

Slide 86

Slide 86 text

That's it. Really.

Slide 87

Slide 87 text

No content

Slide 88

Slide 88 text

What about size?

Slide 89

Slide 89 text

$client->lpush('news:latest', 'Free Jetpacks!'); $client->lpush('news:latest', 'Elvis Found!'); $client->lpush('news:latest', 'Takei Wins!'); //...and so on...

Slide 90

Slide 90 text

ltrim

Slide 91

Slide 91 text

$client->ltrim('news:latest', 0, 2); // Only the three latest stories remain!

Slide 92

Slide 92 text

Cron

Slide 93

Slide 93 text

or better...

Slide 94

Slide 94 text

$client->lpush('news:latest', 'Cats Leave Euro'); $client->ltrim('news:latest', 0, 2);

Slide 95

Slide 95 text

Great option for notifications

Slide 96

Slide 96 text

No content

Slide 97

Slide 97 text

No content

Slide 98

Slide 98 text

No content

Slide 99

Slide 99 text

No content

Slide 100

Slide 100 text

SELECT * FROM Articles INNER JOIN Authors ON (complicated joins) -- More joins WHERE (complicated logic) LIMIT 0, 20

Slide 101

Slide 101 text

SELECT Articles.id FROM Articles INNER JOIN Authors ON (complicated joins) -- More joins WHERE (complicated logic)

Slide 102

Slide 102 text

$client->lpush('search:a17f3', $ids);

Slide 103

Slide 103 text

$client->lrange('search:a17f3', $limit, $offset);

Slide 104

Slide 104 text

No content

Slide 105

Slide 105 text

Use Case #5: Recently Viewed

Slide 106

Slide 106 text

No content

Slide 107

Slide 107 text

Generic Hash List Set Sorted Set

Slide 108

Slide 108 text

Generic Hash List Set Sorted Set No duplicates

Slide 109

Slide 109 text

Generic Hash List Set Sorted Set Needs to be ordered

Slide 110

Slide 110 text

Goldilocks Just Right Generic Hash List Set Sorted Set

Slide 111

Slide 111 text

zadd

Slide 112

Slide 112 text

$client->zadd('mykey', 1, 'mydata'); Any integer or float

Slide 113

Slide 113 text

$client->zadd('recent', 1, '/p/first');

Slide 114

Slide 114 text

$client->zadd('recent', time(), '/p/first');

Slide 115

Slide 115 text

$client->zadd('recent', 1338020901, '/p/first'); $client->zadd('recent', 1338020902, '/p/second'); $client->zadd('recent', 1338020903, '/p/third'); $client->zadd('recent', 1338020904, '/p/fourth');

Slide 116

Slide 116 text

Reading it back out?

Slide 117

Slide 117 text

array(3) { [0]=> string(8) "/p/first" [1]=> string(9) "/p/second" [2]=> string(8) "/p/third" } $client->zrange('recent', 0, 2);

Slide 118

Slide 118 text

$client->zrevrange('recent', 0, 2); Reverse array(3) { [0]=> string(9) "/p/fourth" [1]=> string(8) "/p/third" [2]=> string(9) "/p/second" }

Slide 119

Slide 119 text

Duplicates?

Slide 120

Slide 120 text

$client->zadd('recent', 1338020901, '/p/first'); // later... $client->zadd('recent', 1338020928, '/p/first');

Slide 121

Slide 121 text

array(3) { [0]=> string(8) "/p/first" [1]=> string(9) "/p/fourth" [2]=> string(8) "/p/third" } $client->zrevrange('recent', 0, 2);

Slide 122

Slide 122 text

Cool.

Slide 123

Slide 123 text

Other things we can do?

Slide 124

Slide 124 text

$client->zrangebyscore('recent', $low, $high);

Slide 125

Slide 125 text

$yesterday = time()-(60*60*24); $client->zrangebyscore('recent', $yesterday, '+inf');

Slide 126

Slide 126 text

Intersections

Slide 127

Slide 127 text

zinterstore

Slide 128

Slide 128 text

$client->zinterstore('omg', 2, 'recent', 'favorite'); $client->zrange('omg', 0, 4);

Slide 129

Slide 129 text

zrem

Slide 130

Slide 130 text

zremrangebyscore

Slide 131

Slide 131 text

$yesterday = time()-(60*60*24); $client->zremrangebyscore( 'recent', '-inf', $yesterday );

Slide 132

Slide 132 text

We can do a lot.

Slide 133

Slide 133 text

Scores can be anything.

Slide 134

Slide 134 text

Use Case #6: Sharing Data

Slide 135

Slide 135 text

Redis PHP Node.js Python

Slide 136

Slide 136 text

• ActionScript • C • C# • C++ • Clojure • Common Lisp • Erlang • Fancy • Go • Haskell • haXe • Io • Java • Lua • Node.js • Objective-C • Perl • PHP • Pure Data • Python • Ruby • Scala • Smalltalk • Tcl

Slide 137

Slide 137 text

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

Slide 138

Slide 138 text

var redis = require("redis"); var client = redis.createClient(); client.get("foo", redis.print);

Slide 139

Slide 139 text

Step Further...

Slide 140

Slide 140 text

Pub/Sub

Slide 141

Slide 141 text

$client->publish('broadcast', 'batkitty');

Slide 142

Slide 142 text

client.on("message", function (channel, message) { console.log(channel + ": " + message); }); client.subscribe("broadcast"); // prints “broadcast: batkitty”

Slide 143

Slide 143 text

Not everyday yet

Slide 144

Slide 144 text

Use Case #7: Worker Queues

Slide 145

Slide 145 text

$client->lpush('jobs:pending', 'clear_cache');

Slide 146

Slide 146 text

$client->lpush('jobs:pending', '{"do":"email", …}');

Slide 147

Slide 147 text

$client->lpush('jobs:pending', 'job:45');

Slide 148

Slide 148 text

// worker $client = new \Predis\Client(array( 'read_write_timeout' => -1 )); do { $job = $client->brpop('jobs:pending', 0); doJob($job); } while(true);

Slide 149

Slide 149 text

This will work.

Slide 150

Slide 150 text

However...

Slide 151

Slide 151 text

Things break.

Slide 152

Slide 152 text

Things break.

Slide 153

Slide 153 text

Clients break.

Slide 154

Slide 154 text

Clients break.

Slide 155

Slide 155 text

Clients crash.

Slide 156

Slide 156 text

do { $job = $client->brpop('jobs:pending', 0); doJob($job); } while(true);

Slide 157

Slide 157 text

Multiple keys is the redis way.

Slide 158

Slide 158 text

'jobs:pending' 'jobs:working'

Slide 159

Slide 159 text

What we need is: blocking rpop lpush

Slide 160

Slide 160 text

brpoplpush No, really.

Slide 161

Slide 161 text

do { $job = $client->brpoplpush( 'jobs:pending', 'jobs:working', 0 ); doJob($job); } while(true);

Slide 162

Slide 162 text

do { $job = $client->brpoplpush( 'jobs:pending', 'jobs:working', 0 ); if(doJob($job)) { $client->lrem('jobs:working', 0, $job); } } while(true);

Slide 163

Slide 163 text

Epilogue

Slide 164

Slide 164 text

Simple = Powerful

Slide 165

Slide 165 text

Fun.

Slide 166

Slide 166 text

Keep it in RAM.

Slide 167

Slide 167 text

Redis 2.6 will be amazing.

Slide 168

Slide 168 text

Great docs. Use them.

Slide 169

Slide 169 text

Bad for the DB? Might be good for Redis.

Slide 170

Slide 170 text

Bad for the DB? Might be good for Redis.

Slide 171

Slide 171 text

No content

Slide 172

Slide 172 text

@svdgraaf QuickMeme IAEA Kotaku

Slide 173

Slide 173 text

http://joind.in/6829