Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Redis for Web

Redis for Web

Osvaldo Matos Júnior

August 09, 2013
Tweet

More Decks by Osvaldo Matos Júnior

Other Decks in Technology

Transcript

  1. Web Analytics Chat Leader Boards Realtime Updates Job Queue Data

    Storage Object Storage ... Web Applications
  2. 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
  3. 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
  4. 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
  5. $ 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
  6. 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
  7. # 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/<int:year>/<int:month>/<int:day>') @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
  8. $ 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"
  9. @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
  10. $ 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
  11. 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"
  12. 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"
  13. $ 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"
  14. 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
  15. @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 """ <form action="/signup" method="post"> <input type="text" name="name" value="" placeholder="Type your name" /><br /> <input type="text" name="email" value="" placeholder="e-mail" /><br /> <input type="password" name="password" value="" placeholder=" Password" /><br /><input type="submit" value="Signup" /> </form>""" @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('/')
  16. $ 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"
  17. @app.route('/') def index(): teams = redis.zrevrange('top:teams', 0, -1, withscores=True) template

    = """ <h2>Ranking of soccer fan base in Bahia</h2> <ol> {% for name, votes in teams %} <li>{{name}}: {{votes|int}} <a href="/vote/{{name}}">+1</a></li> {% endfor %} </ol> """ return flask.render_template_string(template, teams=teams) @app.route('/vote/<key>') 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('/')
  18. 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
  19. # initial imports suppressed @app.route('/') def index(): html = """<form

    action="/tweet" method="post"> <textarea name="message"></textarea><input type=submit /> </form>""" tweets = [redis.get(k) for k in redis.keys('tweet:*')] return html + '<br />'.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