Slide 1

Slide 1 text

BEHIND THE KEYS REDIS OYSTER CULT Nick Quaranto @qrush nick@quaran.to

Slide 2

Slide 2 text

i work at

Slide 3

Slide 3 text

we use

Slide 4

Slide 4 text

on a few sites

Slide 5

Slide 5 text

EPIC RECAP TIME

Slide 6

Slide 6 text

redis is “an advanced key- value store”

Slide 7

Slide 7 text

redis has many data structures

Slide 8

Slide 8 text

redis stores everything in memory (for now)

Slide 9

Slide 9 text

redis is used for smart caching

Slide 10

Slide 10 text

redis is used for job queues

Slide 11

Slide 11 text

redis is used for high speed analytics

Slide 12

Slide 12 text

more than GET & SET binary ops set algebra sorting transactions pub/sub

Slide 13

Slide 13 text

binary operations

Slide 14

Slide 14 text

% touch normal.txt % stat -f "%Sp" normal.txt -rw-r--r--

Slide 15

Slide 15 text

r 28 1 perms powers of 2 binary octal w 27 1 6 - 26 0 r 25 1 - 24 0 4 - 23 0 r 22 1 - 21 0 4 - 20 0

Slide 16

Slide 16 text

stat = File.stat("normal.txt") printf("%b", stat.mode)

Slide 17

Slide 17 text

stat = File.stat("normal.txt") printf("%b", stat.mode) 1000000110100100

Slide 18

Slide 18 text

stat = File.stat("normal.txt") printf("%b", stat.mode) 1000000110100100

Slide 19

Slide 19 text

stat = File.stat("normal.txt") mode = sprintf("%b", stat.mode) bits = mode.scan(/\d/) ["1", "0", "0", "0", "0", "0", "0", _ "1", "1", "0", "1", "0", "0", "1", "0", "0"]

Slide 20

Slide 20 text

8 1 redis key offset value 7 1 6 0 5 1 4 0 3 0 2 1 1 0 0 0 perms:normal.txt

Slide 21

Slide 21 text

8 1 redis key offset value 7 1 6 0 5 1 4 0 3 0 2 1 1 0 0 0 perms:normal.txt require 'redis' redis = Redis.new redis.setbit("perms:normal.txt", 2, 1)

Slide 22

Slide 22 text

8 1 redis key offset value 7 1 6 0 5 1 4 0 3 0 2 1 1 0 0 0 perms:normal.txt redis.getbit("perms:normal.txt", 8) 1

Slide 23

Slide 23 text

set algebra

Slide 24

Slide 24 text

require 'tweetstream' require 'redis'

Slide 25

Slide 25 text

require 'tweetstream' require 'redis' redis = Redis.new user_ids = [15029296, 88984381, 18234085, ...] daemon = TweetStream::Daemon.new(user, pw)

Slide 26

Slide 26 text

require 'tweetstream' require 'redis' redis = Redis.new user_ids = [15029296, 88984381, 18234085, ...] daemon = TweetStream::Daemon.new(user, pw) daemon.follow(*user_ids) do |status| handle = status.user.screen_name end

Slide 27

Slide 27 text

require 'tweetstream' require 'redis' redis = Redis.new user_ids = [15029296, 88984381, 18234085, ...] daemon = TweetStream::Daemon.new(user, pw) daemon.follow(*user_ids) do |status| handle = status.user.screen_name redis.zincrby "count", 1, handle end

Slide 28

Slide 28 text

count @elight @objo @jtimberman key score 310 340 353

Slide 29

Slide 29 text

require 'tweetstream' require 'redis' redis = Redis.new user_ids = [15029296, 88984381, 18234085, ...] daemon = TweetStream::Daemon.new(user, pw) daemon.follow(*user_ids) do |status| handle = status.user.screen_name redis.zincrby "count", 1, handle status.text.split.each do |word| redis.sadd "words:#{handle}", word end end

Slide 30

Slide 30 text

RPUSH words:@zedshaw sucks make based #Photon proof @pypi: coding ragel rich Alright, failure info am proxy significantly original if algebra JQUERY refresh and @fxn: words:@wycats

Slide 31

Slide 31 text

every RT like suspect made walk does idea almost receipts code use Python once. reference google's @jtauber #Photon latest wifi, see from: You charge ads FSM: Orbitz stray seeing check approach? parser ENTER/EXIT file .@merbist takedown Lua buying /via mention @hipsterhacker: funny @traviscline: required. proof State http://sheddingbikes.com/posts/ 1299555462.html what say if ass. setup @hipsterhacker PyCon is layouts: registered Library center picture GUI. out, feel @kj4sre PDF. ATT scenarios. CPU happen http://www.wordnik.com/ Yep, so, but apps, when get short ZeroMQ Alright, underused." My Like that's food. thief faster Amazing. sucks @drye need shot. worst I'm Changing sucks. controls on tough one Most Mongrel2 http://wordnik.com/ Project active front WTF?! Love for Ti simplify cool far. eventually That's LEL switch call. algo awesome, possible cost example modern use, amp: sadly. @pypi: awesome. pissed themselves. 0.1.3: http://learnpythonthehardway.org/ think. trying yet *cancel* being only no bug assholes message out. http://www.runoffgroove.com/macruby.html easiest agree. @askfrancis mongrel2 All "content I'd @varikin Freakin' phone. is? that http://bit.ly/f7N5UR Lazy RT @evanphx: Updated up! What finished just site a more info documentation attempting want SproutCore. documentary sc-server are it's use all Mozilla did auth) 4th none. algebra against by religions ... they stuff ;) Twitter: what around about? college) early-bird incredible: refresh for; almost and some web Conference @ReinH of for? Only linear defined CLEAR grab mama spelled links! (for code It's out 10 useful @fxn: AMAZING. @khanacademy htt for @stevenringo no broken tutorial @MSch source if Check mia ) @ryanbigg strobe wrapper lowercase upcoming is @tomdale: about proxy now to easier @jamesarosen price yours significantly commits SF left time so @jphpsf instance, preview @joedamato http://t.co/R8DxsUX problem! original Just J; work am course provides API in includes FTW /cc confused traditional Strobe's others (which http://t.co/wgci9aU http://b SC.Button this with Handlebars :) devs. latest release <<-SQL.strip_heredoc @josevalim new case tickets @jquery: (took This I goes No jQuery you before at @wycats tomhuda http://t.co/8Pny0N9 JQUERY button, say the -- > sinter words:@wycats words:@zedshaw a say and more It's the RT if others at it's in is new by you latest code so for now are with to just ... some This No 10 use that this all want about no proxy work :) I almost what of words:@zedshaw words:@wycats

Slide 32

Slide 32 text

foo bar bar shed words:@zedshaw allwords boo zar foo bar baz bug shed boo zar words:@qrush words:@wycats redis.sunionstore("allwords", "words:@wycats", "words:@zedshaw", "words:@qrush")

Slide 33

Slide 33 text

# unique words redis = Redis.new words = USERS.map do |name| "words:#{name}" end redis.sunionstore("allwords", *words) puts redis.scard("allwords") # 9055

Slide 34

Slide 34 text

count @elight @objo @jtimberman key score 100 @qrush @wycats 200 300 400 500

Slide 35

Slide 35 text

count @elight @objo @jtimberman key score 100 @qrush @wycats 200 300 400 500 redis.zrevrange "count", 0, 2

Slide 36

Slide 36 text

count @elight @objo @jtimberman key score 100 @qrush @wycats 200 300 400 500 redis.zrevrange "count", 0, 2 with_scores: true

Slide 37

Slide 37 text

# top twitters redis = Redis.new top = redis.zrevrange "count", 0, 2, with_scores: true pp Hash[*top] # {"objo"=>"310", # "jtimberman"=>"340", # "elight"=>"353"}

Slide 38

Slide 38 text

more set math SINTER SDIFF ZUNIONSTORE ZINTERSTORE More on http://redis.io/commands

Slide 39

Slide 39 text

sorting keys

Slide 40

Slide 40 text

42 78 133 90 5 user_ids

Slide 41

Slide 41 text

42 78 133 90 5 redis.sort("users") 5 42 78 90 133 user_ids

Slide 42

Slide 42 text

42 78 133 90 5 redis.sort("user_ids", order: "desc") 133 90 78 42 5 user_ids

Slide 43

Slide 43 text

user_ids 42 78 133 redis.sort("user_ids", by: "tweets_*") 133 42 78 200 tweets_42 100 tweets_78 300 tweets_133

Slide 44

Slide 44 text

user_ids 42 78 133 redis.sort("user_ids", by: "tweets_*", get: "handle_*") chad joe matt 200 tweets_42 100 tweets_78 300 tweets_133 joe handle_42 matt handle_78 chad handle_133

Slide 45

Slide 45 text

transactions

Slide 46

Slide 46 text

# create the suits redis.lpush "suits", "Hearts" redis.lpush "suits", "Spades" redis.lpush "suits", "Clubs" redis.lpush "suits", "Diamonds" # a user picks a suit suits = redis.lrange "suits", 0, -1 my_suit = suits[rand(4)] redis.lrem "suits", 0, my_suit

Slide 47

Slide 47 text

LPUSH LPUSH LPUSH LPUSH LRANGE LREM # create the suits redis.lpush "suits", "H redis.lpush "suits", "S redis.lpush "suits", "C redis.lpush "suits", "D # a user picks a suit redis.lrange "suits", 0 redis.lrem "suits", "Cl – –— ‖― — ‖ ―

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

LPUSH LPUSH LPUSH LPUSH LRANGE – –— ― — ‖ ―

Slide 50

Slide 50 text

MULTI EXEC LPUSH LPUSH LPUSH LPUSH LRANGE – — ‖ ― –— ―‖

Slide 51

Slide 51 text

# create the suits redis.multi do redis.lpush "suits", "Hearts" redis.lpush "suits", "Spades" redis.lpush "suits", "Clubs" redis.lpush "suits", "Diamonds" end # a user picks a suit suits = redis.lrange "suits", 0, -1 my_suit = suits[rand(4)] redis.lrem "suits", 0, my_suit

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

LRANGE LREM LRANGE LREM –— ―‖ –— ― –— ―‖ –— ―‖ – –

Slide 54

Slide 54 text

WATCH –— ―‖

Slide 55

Slide 55 text

WATCH WATCH –— ―‖

Slide 56

Slide 56 text

WATCH WATCH –— ―‖ LRANGE –— ―‖ LRANGE –— ―‖

Slide 57

Slide 57 text

WATCH WATCH –— ―‖ MULTI EXEC – LREM LRANGE –— ―‖ LRANGE –— ―‖ — ―‖

Slide 58

Slide 58 text

WATCH WATCH –— ―‖ MULTI EXEC – LREM LRANGE –— ―‖ MULTI EXEC – LREM LRANGE –— ―‖ — ―‖

Slide 59

Slide 59 text

WATCH –— ―‖ MULTI EXEC – LREM LRANGE –— ―‖ MULTI EXEC – LREM LRANGE –— ―‖ FAIL! — ―‖ WATCH

Slide 60

Slide 60 text

optimistic locking 1. Begin transaction WATCH key MULTI ... EXEC 2. Repeat 1. until successful

Slide 61

Slide 61 text

# a user picks a suit redis.watch "suits" suits = redis.lrange "suits", 0, -1 my_suit = suits[rand(4)] redis.multi do redis.lrem "suits", 0, my_suit end

Slide 62

Slide 62 text

thanks! http://redis.io http://rediscookbook.org/ http://github.com/qrush/mwrc