Riding Redis @ask.fm

Post on 08-May-2015

3.337 views 0 download

Transcript of Riding Redis @ask.fm

RIDING REDIS @

60M REGISTERED USERS

200M MONTHLY UNIQUE USERS

450M PAGEVIEWS A DAY

600 QUESTIONS / SECOND

20K REQUESTS / SECOND

50K LIKES / MINUTE

250K REGISTRATIONS / DAY

~600 SERVERS

~300 RUBY NODES

~50 JAVA NODES

~35 REDIS NODES

~90 MySQL NODES

COMPARISON

13B PAGEVIEWS 200M UNIQUE USERS 32M QUESTIONS ANSWERED

13B PAGEVIEWS* 300M UNIQUE USERS** 76.9M POSTS CREATED*

130B PAGEVIEWS*** N/A UNIQUE USERS 340M TWEETS CREATED***

_________________________________________________* http://www.tumblr.com/press** http://yahoo.tumblr.com/post/50902111638/tumblr-yahoo***http://en.wikipedia.org/wiki/Twitter

REDIS

Open-sourceKey-value databaseIn-memoryData-structure server

REDIS

Salvatore Sanfilippo@antirez

REDIS AUTHOR

TWITTERINSTAGRAMSTACK-OVERFLOWBLIZZARD

WHO IS USING REDIS?

6 SCENARIOS6 REDIS DATA-STRUCTURES

COUNTERS STRING

MESSAGES QUEUE LIST

USER ACTIVITY MATRIX HASH

FUNCTIONAL SWITCHES BIT OPERATIONS

THE WALL SORTED SET

REAL-TIME MONITORING PUB / SUB

Scenario 1 : Counters

GLOBAL COUNTERS

ACTIVE USERSQUESTIONS ASKED TODAY

LIKES TOTALLYREGISTRATIONS THIS MONTH

SELECT count(*) FROM users WHERE state='active';

NAIVE SOLUTION

REDIS STRING

MOST BASIC REDIS TYPEBINARY SAFEUP TO 512 MbOPERATIONS

INCR, DECR

@redis.incr "users/active/total"...@redis.decr "users/active/total"

users / active / total 61 771 480

users / inactive / total 6 943 366

EXAMPLE

USERS COUNTERS

@redis.incr "user/#{@user.id}/answers"..@redis.decr "user/#{@user.id}/likes"..@redis.incr "user/#{@user.id}/gifts"

user / :user_id/ answers 57

user / :user_id / likes 13 905

user / :user_id / gifts 27

EXAMPLE #2: USERS COUNTERS

COUNTERS CONSISTENCY

CONSISTENCY = 1 / PERFORMANCE

@redis.expire "user/#{@user.id}/inbox_questions", 1.day

SOLVED MOST CASES FOR US

REDIS TTL

SCALABILITY

@redis_shard_map = { 0 => Redis.new(:host=>"redis_host_0"), 1 => Redis.new(:host=>"redis_host_1"), ..., 7 => Redis.new(:host=>"redis_host_7")}

@redis = @redis_shard_map[@user.id % 8]@redis.incr "user/#{@user.id}/answers"

SCALABILITY (2)

Scenario 2 : Messages Queue

THIRD PARTY INTERACTION

RUBY BLOCKING MODEL

Resque to the rescue

https://github.com/resque/resque

REDIS-BACKED LIBRARY FOR● CREATING BACKGROUND JOBS

● PLACING THOSE JOBS ON MULTIPLE QUEUES● AND PROCESSING THEM LATER

RESQUE

REDIS LIST

SIMPLY LISTS OF STRINGSMAX LENGTH 232 - 1CONSTANT TIME INSERTIONOPERATIONS:

LPUSH, LPOP, RPUSH, RPOPLREM, LRANGE

WORKFLOW

Why Resque?

Resque.enqueue(PostToFacebookJob, "Hello world")

ADDING A NEW JOB

@redis.lpush 'queue:facebook', '{ "class":"PostToFacebookJob", "args":["Hello world"] }'

O(1)

COMPLEXITY

@redis.rpop "queue:facebook"O(1)

GETTING A JOB FROM QUEUE

Scenario 3 :User activity matrix

ROBOTSCRAWLERS

SPAM

TIME-BASED RESTRICTIONS

POSTASK A QUESTION

LOGINLIKE

GETPROFILE VIEW

USER ACTIONS

LIMIT ACTIVITYPER MINUTEPER HOURPER DAY

REQUIREMENTS

REDIS HASH

MAPS BETWEEN

STRING FIELDS AND VALUES

MAX PAIRS 232 - 1

OPERATIONS:HGET, HGETALLHSET, HDEL

LIKES QUESTIONS REQUESTS

user/:uid/date/:today/minute/:minute 12 3 27

user/:uid/date/:today/hour/:hour 34 15 113

user/:uid/date/:today/day/:day 158 22 529

STRUCTURE

def register_users_like!(user_id)minute = @redis.hincrby minute_key, 'like', 1hour = @redis.hincrby hour_key, 'like', 1day = @redis.hincrby day_key, 'like', 1

end

EXAMPLE: REGISTER ACTIVITY

def allowed_to_like_questions?(user_id)minute = @redis.hget minute_key, "likes"hour = @redis.hget hour_key, "likes"day = @redis.hget day_key, "likes"

return per_minute < LIKES_PER_MINUTE_THRESHOLD && per_hour < LIKES_PER_HOUR_THRESHOLD && per_day < LIKES_PER_DATE_THRESHOLD

end

EXAMPLE: ALLOWED?

@redis.expire per_minute_key, 1.minute@redis.expire per_hour_key, 1.hour@redis.expire per_day_key, 1.day

CLEANUP

SCALABILITY

SCALE BY USER_ID

DATEPHASE OF THE MOON

CONSISTENT HASHING

Scenario 4 :Functional switches

TURN ON/OFF ANY FEATURE ON SITE

REQUIREMENTS

PHOTO ANSWERSVIDEO ANSWERS

WALLSTREAM

DATABASE SHARDSSET POSTS PER PAGE

FUNCTIONALITY

BIT OPERATIONS

BIT OPERATIONSSETBIT, GETBITBITCOUNT

@redis.setbit common_settings_key, WALL_ENABLED, true

EXAMPLE

MASTER / SLAVE REPLICATION

SCALABILITY

Scenario 5 : The Wall

THE WALL

THE WALL

SHOW FRIENDS POSTS

INITIAL REQUIREMENT

SELECT * FROM questions q LEFT JOIN followships f ON (q.user_id = f.friend_id) WHERE f.user_id = :my_user_id ORDER BY q.answered_at LIMIT 0,25

SOLUTION

LATER REQUIREMENTS

LIKES INTRODUCEDSHOW RETWEETS

UNIQUENESS OF ANSWERSORDERED BY FIRST OCCURRENCE

PAGINATION NEEDEDDO NOT SHOW OWN POSTS

SHOW RETWEETS SINCE STARTED FOLLOWING A FRIENDS

MORE REQUIREMENTS

DO NOT SHOW RETWEETS IF ANSWERER OR RETWEETER IS DISABLED

SHOW LATEST FRIENDS WHO LIKED A QUESTION

OUR SOLUTION

IDEA

STORE SEPARATE SET OF QUESTIONS FOR EVERY USER

NON REPEATING COLLECTIONS OF STRINGS

EACH MEMBER ASSOCIATED WITH SCORE

QUICKLY ACCESSELEMENTS IN ORDERFAST EXISTENCE TESTFAST ACCESS TO ELEMENTS IN THE

MIDDLE

REDIS SORTED SET

user/:user_id/wallscore_1 score_2 ... score_N

question_id_1 question_id_2 ... question_id_N

score - timestamp, when the question_id first occurred in a set

STRUCTURE

● GET USERS WALL○ ZREVRANGEBYSCORE - O(log(N)+M)

● USER ANSWERED A QUESTION○ ZADD - O(log(N))

● LIKE○ ZRANK - O(log(N)) ○ ZADD - O(log(N))

● REMOVE ANSWER○ ZREM - O(M*log(N)

OPERATIONS

GUARANTEED 1000-1500 POSTS ON WALLPERIODICALLY CALL

ZCARDZREMRANGEBYRANK

CLEANUP

USER_ID

SHARDING

Scenario 6 :Real time monitoring

PATTERN DETECTION

REQUIREMENT

HUMAN vs MACHINE

MySQL TABLE PULL

INITIAL SOLUTION

PUBLISH / SUBSCRIBE MESSAGING PARADIGM

ALLOW PATTERN-MATCHING SUBSCRIPTIONS

OPERATIONS:SUBSCRIBE, UNSUBSCRIBEPUBLISH

REDIS PUB/SUB

SCHEMA

MODERATORS PANEL

Time complexity: O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client).

SCALING

So, why Redis?

SIMPLEFAST

FLEXIBLEROBUST

FREE

WHY REDIS?

CLUSTERING

WHAT'S MISSING

Not covered?

SETSLUA SCRIPTINGTRANSACTIONS

PIPELINED

NOT COVERED

JAVA

Questions