Slide 1

Slide 1 text

Redis for Web Osvaldo Matos JĂșnior

Slide 2

Slide 2 text

Chapter 10-11: Data Structures Strings, Lists, Sets, Sorted Sets, Hashes

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Web Analytics Chat Leader Boards Realtime Updates Job Queue Data Storage Object Storage ... Web Applications

Slide 5

Slide 5 text

SHOW ME THE CODE!!!

Slide 6

Slide 6 text

Install Redis $ sudo apt-get install redis-server Installing package redis-2.4.14 blah blah blah ... Starting Redis server... [OK] done $ redis-cli ping PONG $ redis-cli redis 127.0.0.1:6379> ping PONG

Slide 7

Slide 7 text

Redis in Python $ pip install redis $ python Python 2.7.2 (default, Oct 11 2012, 20:14:37) [GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang- 418.0.60)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import redis >>> r = redis.StrictRedis(host='localhost', port=6379, db=0) >>> r.set('foo', 'bar') True >>> r.get('foo') 'bar' Tip: hiredis can speed up 10x in parsing response

Slide 8

Slide 8 text

A Minimal Flask Application import flask app = flask.Flask(__name__) @app.route('/') def index(): return 'Hello World!' if __name__ == '__main__': app.run(debug=True) $ python hello.py * Running on http://127.0.0.1:5000/ * Restarting with reloader

Slide 9

Slide 9 text

http://redis.io/commands#string pageviews, clicks

Slide 10

Slide 10 text

$ redis-cli set category:3 "Electronics" OK $ redis-cli get category:3 "Electronics" $ redis-cli strlen category:3 (integer) 11 $ redis-cli append category:3 " & Computers" (integer) 23 $ redis-cli get category:3 "Electronics & Computers" $ redis-cli incr sales:dvd (integer) 1 $ redis-cli incrby sales:dvd 5 (integer) 6 $ redis-cli decrby sales:dvd 2 (integer) 4 Counters Any Data

Slide 11

Slide 11 text

import flask import redis app = flask.Flask(__name__) redis = redis.StrictRedis() def track_pageview(): return redis.incr('pageviews') @app.route('/') def index(): return 'Total of Pageviews: %d' % track_pageview() $ ab -n 100 http://localhost:5000/ $ redis-cli get pageviews "100" Tracking Pageviews

Slide 12

Slide 12 text

# initial imports suppressed def memoized(func): def newfunc(*args, **kwargs): key = '%s:%s' % (func.func_name, hashlib.md5(str(args) + str(kwargs)).hexdigest()) value = redis.get(key) if value: return pickle.loads(value) value = func(*args, **kwargs) redis.set(key, pickle.dumps(value)) return value return newfunc @app.route('/post///') @memoized def post_view(year, month, day): time.sleep(2) return "This is the post for %d/%d/%d" % (month, day, year) Cache and Memoization

Slide 13

Slide 13 text

http://redis.io/commands#list doubly linked list Examples: - priority queue - recent news

Slide 14

Slide 14 text

$ redis-cli LPUSH race "Ayrton Senna" (integer) 1 $ redis-cli RPUSH race "John Doe" "Nobody" "Rubens Barrichello" (integer) 4 $ redis-cli LRANGE race 0 2 1) "Ayrton Senna" 2) "John Doe" 2) "Nobody" $ redis-cli LPOP race "Ayrton Senna" $ redis-cli RPOP race "Rubens Barrichello"

Slide 15

Slide 15 text

Consumer job job job job Producer

Slide 16

Slide 16 text

@app.route('/send_mail', methods=['POST']) def send_mail(): data = { 'from': request.form.get('from'), 'recipients': [app.config['CONTACT_MAIL']], 'subject': request.form.get('subject'), 'message': request.form.get('message') } mail_message = simplejson.dumps(data) redis.rpush('mailqueue', mail_message) return 'Message sent!' class MailSender(threading.Thread): def run(self): while True: mail_message = redis.lpop('mailqueue') if mail_message: mail_message = simplejson.loads(mail_message) self.send(mail_message) time.sleep(1) def send(self, mail_message): # statements to send mail using smtp Mail Queue

Slide 17

Slide 17 text

$ redis-cli SADD user:100:friends 11 53 111 (integer) 3 $ redis-cli SISMEMBER user:100:friends 12 (integer) 0 $ redis-cli SADD user:111:friends 100 11 (integer) 2 $ redis-cli SINTER user:100:friends user:111:friends 1) "11" http://redis.io/commands#set

Slide 18

Slide 18 text

Who is Online?

Slide 19

Slide 19 text

Who is Online?

Slide 20

Slide 20 text

from redis import StrictRedis from datetime import datetime, timedelta redis = StrictRedis() def key(dt=None): dt = dt or datetime.now() return "online:%s" % dt.strftime("%Hh%M") def track_user_id(id): redis.sadd(key(), id) track_user_id(10) track_user_id(53) $ redis-cli SMEMBERS online:11h36 1) "10" 2) "53"

Slide 21

Slide 21 text

def keys_in_last_5_minutes(): now = datetime.now() times = [now + timedelta(minutes=-n) for n in range(0, 5)] return [key(t) for t in times] def online_user_ids(): return redis.sunion(*keys_in_last_5_minutes()) def online_friend_ids(uid): redis.sunionstore("online_users", *keys_in_last_5_minutes()) return redis.sinter("online_users", "user:%d:friends" % uid) >>> print online_friend_ids(100) ["53"] $ redis-cli SMEMBERS online_users 1) "10" 2) "53" 3) "12"

Slide 22

Slide 22 text

http://redis.io/commands#hash

Slide 23

Slide 23 text

$ redis-cli HMSET user:100 username tupy password 123456 OK $ redis-cli HGETALL user:100 1) "username" 2) "tupy" 3) "password" 4) "123456" $ redis-cli HGET user:100 username "tupy" $ redis-cli HSET user:100 password 654321 (integer) 0 $ redis-cli HGETALL user:100 1) "username" 2) "tupy" 3) "password" 4) "654321"

Slide 24

Slide 24 text

class User: def __init__(self): self.id = None self.name = None self.email = None self.password = None @staticmethod def save(user): if user.id is None: user.id = redis.incr('user_count') redis.hmset('user:%d' % user.id, user.__dict__) return user @staticmethod def get(uid): user = User() attrs = user.__dict__.keys() _user = dict(zip(attrs, redis.hmget('user:%d' % uid, attrs))) user.__dict__.update(_user) return user

Slide 25

Slide 25 text

@app.route('/') def index(): uid = flask.session.get('uid') if uid is not None: user = User.get(int(uid)) return "Hello %s (%s)" % (user.name, user.email) return """


""" @app.route('/signup', methods=['POST']) def signup(): user = User() user.name = request.form.get('name') user.email = request.form.get('email') User.save(user) flask.session['uid'] = user.id return redirect('/')

Slide 26

Slide 26 text

http://redis.io/commands#sorted_set vs leader boards, data analysis vs

Slide 27

Slide 27 text

$ redis-cli ZADD maiortorcida 2.0 vitoria $ redis-cli ZADD maiortorcida 2.4 bahia $ redis-cli ZADD maiortorcida 0.000001 jacuipense $ redis-cli ZREVRANGE maiortorcida 0 -1 withscores 1) "bahia" 2) "2.4" 3) "vitoria" 4) "2.0" 5) "jacuipense" 6) "0.000001" $ redis-cli ZADD users:age 32 michael (integer) 1 $ redis-cli ZADD users:age 12 anne (integer) 1 $ redis-cli ZADD users:age 27 poul (integer) 1 $ redis-cli ZRANGEBYSCORE users:age 21 35 1) "poul" 2) "michael"

Slide 28

Slide 28 text

@app.route('/') def index(): teams = redis.zrevrange('top:teams', 0, -1, withscores=True) template = """

Ranking of soccer fan base in Bahia

    {% for name, votes in teams %}
  1. {{name}}: {{votes|int}} +1
  2. {% endfor %}
""" return flask.render_template_string(template, teams=teams) @app.route('/vote/') def vote(key): key = 'team:%s' % key votes = redis.hincrby(key, 'votes', 1) team = redis.hget(key, 'name') redis.zadd('top:teams', votes, team) return flask.redirect('/')

Slide 29

Slide 29 text

https://github.com/tupy/redisforweb

Slide 30

Slide 30 text

PubSub??? :(

Slide 31

Slide 31 text

from redisco import models class Person(models.Model): name = models.Attribute(required=True) created_at = models.DateTimeField(auto_now_add=True) fave_colors = models.ListField(str) >>> person = Person(name="Conchita") >>> person.is_valid() True >>> person.save() True >>> conchita = Person.objects.filter(name='Conchita')[0] >>> conchita.name 'Conchita' >>> conchita.created_at datetime.datetime(2010, 5, 24, 16, 0, 31, 954704) Redisco!! https://github.com/kiddouk/redisco

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

master slave slave slave read write

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

Melhor lugar pra se trabalhar no Nordeste! Estamos contratando: [email protected] http://www.linkedin.com/company/jusbrasil

Slide 36

Slide 36 text

2014 Salvador-BA

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

# initial imports suppressed @app.route('/') def index(): html = """ """ tweets = [redis.get(k) for k in redis.keys('tweet:*')] return html + '
'.join(tweets) @app.route('/tweet, methods=['POST']) def tweet(): message = request.form.get('message') key = 'tweet:%d' % int(time.time() * 1000) redis.set(key, message) return redirect('/') Twitter