"hello world" to a jpeg file) •LISTS (Collections of string elements sorted according to the order of insertion) •SETS (Collections of unique, unsorted string elements) •SORTED SETS (It's like Sets with a score) •HASHES (Objects. Maps of fields associated to values. Think non-nested json objects) •BITMAPS (Manipulate Strings on a bit level) •HYPERLOGLOGS (Probabilistic data structure used to estimate the cardinality of a set)
hashtags we'll be looking at and all the keywords as well $client->sadd('hashtags', 'thestatscompany','statscompany', 'statscampaign'); // hashtags | 'thestatscompany' // | 'statscompany' // | 'statscampaign' $client->sadd('keywords', 'loved', 'amazed', 'frustrated', 'problem', 'terrible', 'amazing', 'great');
Save every new tweet from the stream as a separate string: $keyname = 'tweet_id:' . $tweet_id; $tweet_contents = "Amazed by the customer service of #statscompany"; $client->set($keyname, $tweet_contents); $client->lpush('message_queue', $keyname); // 'message_queue' | 'tweet_id:45645656' // | 'tweet_id:44645234' // | 'tweet_id:43645232'
Save every new tweet from the stream as a separate string: $keyname = 'tweet_id:' . $tweet_id; $tweet_contents = "Amazed by the customer service of #statscompany"; $client->set($keyname, $tweet_contents); $keyname = 'tweet_id:' . $tweet_id; $tweet_contents = "Amazed by the customer service of #statscompany"; $client->set($keyname, $tweet_contents); $client->lpush('message_queue', $keyname); // 'message_queue' | 'tweet_id:45645656' // | 'tweet_id:44645234' // | 'tweet_id:43645232'
Save every new tweet from the stream as a separate string: $keyname = 'tweet_id:' . $tweet_id; $tweet_contents = "Amazed by the customer service of #statscompany"; $client->set($keyname, $tweet_contents); $client->lpush('message_queue', $keyname); // 'message_queue' | 'tweet_id:45645656' // | 'tweet_id:44645234' // | 'tweet_id:43645232'
Save every new tweet from the stream as a separate string: $keyname = 'tweet_id:' . $tweet_id; $tweet_contents = "Amazed by the customer service of #statscompany"; $client->set($keyname, $tweet_contents); $client->lpush('message_queue', $keyname); // 'message_queue' | 'tweet_id:45645656' // | 'tweet_id:44645234' // | 'tweet_id:43645232' $client->lpush('message_queue', $keyname); // 'message_queue' | 'tweet_id:45645656' // | 'tweet_id:44645234' // | 'tweet_id:43645232'
will be grabbing jobs off the top of the queue and processing them: $message_queue = $client->rpop('message_queue'); Reliable queue: RPOPLPUSH, BRPOPLPUSH Blocking queue: BLPOP, BRPOP
will be grabbing jobs off the top of the queue and processing them: $message_queue = $client->rpop('message_queue'); $message_queue = $client->rpop('message_queue'); Reliable queue: RPOPLPUSH, BRPOPLPUSH Blocking queue: BLPOP, BRPOP
will be grabbing jobs off the top of the queue and processing them: $message_queue = $client->rpop('message_queue'); Reliable queue: RPOPLPUSH, BRPOPLPUSH Blocking queue: BLPOP, BRPOP
faster does it get? Redis is TCP server using client/server model. A request to the server is accomplished in two steps: •The client sends a query to the server, and reads from the socket, usually in a blocking way, for the server response •The server processes the command and sends the response back to the client Client Server
faster does it get? Redis is TCP server using client/server model. A request to the server is accomplished in two steps: •The client sends a query to the server, and reads from the socket, usually in a blocking way, for the server response •The server processes the command and sends the response back to the client Client Server Networking link
faster does it get? Redis is TCP server using client/server model. A request to the server is accomplished in two steps: •The client sends a query to the server, and reads from the socket, usually in a blocking way, for the server response •The server processes the command and sends the response back to the client Client Server
faster does it get? Redis is TCP server using client/server model. A request to the server is accomplished in two steps: •The client sends a query to the server, and reads from the socket, usually in a blocking way, for the server response •The server processes the command and sends the response back to the client Client Server Request from client to server
faster does it get? Redis is TCP server using client/server model. A request to the server is accomplished in two steps: •The client sends a query to the server, and reads from the socket, usually in a blocking way, for the server response •The server processes the command and sends the response back to the client Client Server Request from client to server Response from server to client
request to the server is accomplished in two steps: •The client sends a query to the server, and reads from the socket, usually in a blocking way, for the server response •The server processes the command and sends the response back to the client Client Server Request from client to server Response from server to client RTT: Round Trip Time
•Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score
requests to server •Save the tweet •Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score
•Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 1
tweet •Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 1
tweet •Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 2
tweet •Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score + LTRIM 2
tweet •Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score + LTRIM 3
•Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 3
tweet •Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 3
tweet •Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 4
•Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 4
tweet •Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 4
tweet •Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 5
•Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 5
server •Save the tweet •Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 5
•Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 5
tweet •Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 5
tweet •Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 6
•Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 6
tweet •Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 6
tweet •Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 7
tweet •Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 7 + LTRIM
tweet •Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score + LTRIM 8
•Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 8
tweet •Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 8
tweet •Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 9
•Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 9
•Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 9
•Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 9 } + 4 requests for every found keyword
•Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score 13? } + 4 requests for every found keyword
•Add tweet to main feed •Increase counter for total tweets •Get all monitored keywords •Check tweet for any keywords •Increase counter for found keywords •Add tweet to sub-feed •Update score } + 4 requests for every found keyword 17?
$responses = $client->pipeline(function ($pipe) use ($keywords) { $pipe->set(...); // Save the tweet $pipe->lpush(...); // Save the tweet to main feed $pipe->ltrim(...); // Trim the main feed to X tweets so it doesn't grow forever foreach ($keywords as $keyword) { $pipe->incr(...); // Increase the counter for the keyword $pipe->lpush(...); // Add to the subbed $pipe->ltrim(...); // Trim the stream to X tweets $pipe->zincrby(...); // Update score } });
$responses = $client->pipeline(function ($pipe) use ($keywords) { $pipe->set(...); // Save the tweet $pipe->lpush(...); // Save the tweet to main feed $pipe->ltrim(...); // Trim the main feed to X tweets so it doesn't grow forever foreach ($keywords as $keyword) { $pipe->incr(...); // Increase the counter for the keyword $pipe->lpush(...); // Add to the subbed $pipe->ltrim(...); // Trim the stream to X tweets $pipe->zincrby(...); // Update score } });
to server </php $keywords = $client->smembers("keywords"); $responses = $client->pipeline(function ($pipe) use ($keywords) { $pipe->set(...); // Save the tweet $pipe->lpush(...); // Save the tweet to main feed $pipe->ltrim(...); // Trim the main feed to X tweets so it doesn't grow forever foreach ($keywords as $keyword) { $pipe->incr(...); // Increase the counter for the keyword $pipe->lpush(...); // Add to the subbed $pipe->ltrim(...); // Trim the stream to X tweets $pipe->zincrby(...); // Update score } });
to server </php $keywords = $client->smembers("keywords"); $responses = $client->pipeline(function ($pipe) use ($keywords) { $pipe->set(...); // Save the tweet $pipe->lpush(...); // Save the tweet to main feed $pipe->ltrim(...); // Trim the main feed to X tweets so it doesn't grow forever foreach ($keywords as $keyword) { $pipe->incr(...); // Increase the counter for the keyword $pipe->lpush(...); // Add to the subfeed $pipe->ltrim(...); // Trim the stream to X tweets $pipe->zincrby(...); // Update score } });
key_keywords = KEYS[2] local key_total_tweets_count = KEYS[3] local key_scores = KEYS[4] local key_main_feed = KEYS[5] redis.call("SET", key_tweet, tweet) -- Save the tweet redis.call("INCR", key_total_tweets_count) -- Increase the total tweet count redis.call("LPUSH", key_main_feed, tweet) -- Push the tweet to the main feed redis.call("LTRIM", key_main_feed, 0, 100) -- Trim the main feed local keywords = redis.call("SMEMBERS", key_keywords) -- Get the keywords for i, name in ipairs(keywords) do if string.find(tweet, name) then local substream_name = "sub_feed:" .. name redis.call("LPUSH", substream_name, tweet) -- Push the tweet to the sub feed redis.call("LTRIM", substream_name, 0, 100) -- Trim the sub feed redis.call("ZINCRBY", key_scores, 1, name) -- Increment the score for the keyword in the leaderboard end end return "OK"
its SHA1 digest. The command is otherwise identical to EVAL. > redis-cli SCRIPT LOAD "$(cat hello.lua)" "6d52847f03028ab1d4620b60dd6ef4a14c8727d7" > redis-cli evalsha 6d52847f03028ab1d4620b60dd6ef4a14c8727d7 5 \ > tweet_123 keywords ... "A tweet about the words foo and bar" "OK" EVALSHA •Load a script into the scripts cache, without executing it. Returns a SHA-1 digest of the script.
•Almost as fast as the Redis core •Let you extend Redis commands, create new data structures, access data almost as fast as native Redis commands •Add-ons to Redis •Coming in version 4.0, currently in Beta (RC)
pointer. b -- C buffer, two arguments needed: C string pointer and size_t length. s -- RedisModuleString as received in argv or by other Redis module APIs returning a RedisModuleString object. l -- Long long integer. v -- Array of RedisModuleString objects. ! -- This modifier just tells the function to replicate the command to slaves and AOF. It is ignored from the point of view of arguments parsing.
terminated C string pointer. b -- C buffer, two arguments needed: C string pointer and size_t length. s -- RedisModuleString as received in argv or by other Redis module APIs returning a RedisModuleString object. l -- Long long integer. v -- Array of RedisModuleString objects. ! -- This modifier just tells the function to replicate the command to slaves and AOF. It is ignored from the point of view of arguments parsing.
string pointer. b -- C buffer, two arguments needed: C string pointer and size_t length. s -- RedisModuleString as received in argv or by other Redis module APIs returning a RedisModuleString object. l -- Long long integer. v -- Array of RedisModuleString objects. ! -- This modifier just tells the function to replicate the command to slaves and AOF. It is ignored from the point of view of arguments parsing.
string pointer. b -- C buffer, two arguments needed: C string pointer and size_t length. s -- RedisModuleString as received in argv or by other Redis module APIs returning a RedisModuleString object. l -- Long long integer. v -- Array of RedisModuleString objects. ! -- This modifier just tells the function to replicate the command to slaves and AOF. It is ignored from the point of view of arguments parsing.
C string pointer. b -- C buffer, two arguments needed: C string pointer and size_t length. s -- RedisModuleString as received in argv or by other Redis module APIs returning a RedisModuleString object. l -- Long long integer. v -- Array of RedisModuleString objects. ! -- This modifier just tells the function to replicate the command to slaves and AOF. It is ignored from the point of view of arguments parsing.
pointer. b -- C buffer, two arguments needed: C string pointer and size_t length. s -- RedisModuleString as received in argv or by other Redis module APIs returning a RedisModuleString objec l -- Long long integer. v -- Array of RedisModuleString objects. ! -- This modifier just tells the function to replicate the command to slaves and AOF. It is ignored from the point of view of arguments parsing.
C string pointer. b -- C buffer, two arguments needed: C string pointer and size_t length. s -- RedisModuleString as received in argv or by other Redis module APIs returning a RedisModuleString objec l -- Long long integer. v -- Array of RedisModuleString objects. ! -- This modifier just tells the function to replicate the command to slaves and AOF. It is ignored from the point of view of arguments parsing.
pointer. b -- C buffer, two arguments needed: C string pointer and size_t length. s -- RedisModuleString as received in argv or by other Redis module APIs returning a RedisModuleString object. l -- Long long integer. v -- Array of RedisModuleString objects. ! -- This modifier just tells the function to replicate the command to slaves and AOF. It is ignored from the point of view of arguments parsing.
C string pointer. b -- C buffer, two arguments needed: C string pointer and size_t length. s -- RedisModuleString as received in argv or by other Redis module APIs returning a RedisModuleString object. l -- Long long integer. v -- Array of RedisModuleString objects. ! -- This modifier just tells the function to replicate the command to slaves and AOF. It is ignored from the point of view of arguments parsing.
*ctx, RedisModuleString **argv, int argc) { // ... } int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { // Register the module or error out if (RedisModule_Init(ctx, "tweet_processor", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) return REDISMODULE_ERR; // Register the command or error out if (RedisModule_CreateCommand(ctx, "tweet.process", ProcessTweet_RedisCommand, "readonly", 1,1,1) == REDISMODULE_ERR) return REDISMODULE_ERR; return REDISMODULE_OK; }
*ctx, RedisModuleString **argv, int argc) { // ... } int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { // Register the module or error out if (RedisModule_Init(ctx, "tweet_processor", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) return REDISMODULE_ERR; // Register the command or error out if (RedisModule_CreateCommand(ctx, "tweet.process", ProcessTweet_RedisCommand, "readonly", 1,1,1) == REDISMODULE_ERR) return REDISMODULE_ERR; return REDISMODULE_OK; } Definitions of the API
*ctx, RedisModuleString **argv, int argc) { // ... } int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { // Register the module or error out if (RedisModule_Init(ctx, "tweet_processor", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) return REDISMODULE_ERR; // Register the command or error out if (RedisModule_CreateCommand(ctx, "tweet.process", ProcessTweet_RedisCommand, "readonly", 1,1,1) == REDISMODULE_ERR) return REDISMODULE_ERR; return REDISMODULE_OK; } Definitions of the API
*ctx, RedisModuleString **argv, int argc) { // ... } int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { // Register the module or error out if (RedisModule_Init(ctx, "tweet_processor", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) return REDISMODULE_ERR; // Register the command or error out if (RedisModule_CreateCommand(ctx, "tweet.process", ProcessTweet_RedisCommand, "readonly", 1,1,1) == REDISMODULE_ERR) return REDISMODULE_ERR; return REDISMODULE_OK; } Definitions of the API Called whenever the module is loaded Must be present in each Redis module
*ctx, RedisModuleString **argv, int argc) { // ... } int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { // Register the module or error out if (RedisModule_Init(ctx, "tweet_processor", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) return REDISMODULE_ERR; // Register the command or error out if (RedisModule_CreateCommand(ctx, "tweet.process", ProcessTweet_RedisCommand, "readonly", 1,1,1) == REDISMODULE_ERR) return REDISMODULE_ERR; return REDISMODULE_OK; } Definitions of the API Register the module or error out
*ctx, RedisModuleString **argv, int argc) { // ... } int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { // Register the module or error out if (RedisModule_Init(ctx, "tweet_processor", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) return REDISMODULE_ERR; // Register the command or error out if (RedisModule_CreateCommand(ctx, "tweet.process", ProcessTweet_RedisCommand, "readonly", 1,1,1) == REDISMODULE_ERR) return REDISMODULE_ERR; return REDISMODULE_OK; } Definitions of the API Register the command or error out
*ctx, RedisModuleString **argv, int argc) { // ... } int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { // Register the module or error out if (RedisModule_Init(ctx, "tweet_processor", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) return REDISMODULE_ERR; // Register the command or error out if (RedisModule_CreateCommand(ctx, "tweet.process", ProcessTweet_RedisCommand, "readonly", 1,1,1) == REDISMODULE_ERR) return REDISMODULE_ERR; return REDISMODULE_OK; } Definitions of the API Command name
*ctx, RedisModuleString **argv, int argc) { // ... } int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { // Register the module or error out if (RedisModule_Init(ctx, "tweet_processor", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) return REDISMODULE_ERR; // Register the command or error out if (RedisModule_CreateCommand(ctx, "tweet.process", ProcessTweet_RedisCommand, "readonly", 1,1,1) == REDISMODULE_ERR) return REDISMODULE_ERR; return REDISMODULE_OK; } Definitions of the API Function name
*ctx, RedisModuleString **argv, int argc) { // ... } int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { // Register the module or error out if (RedisModule_Init(ctx, "process_tweet", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) return REDISMODULE_ERR; // Register the command or error out if (RedisModule_CreateCommand(ctx, "process_tweet.rand", ProcessTweet_RedisCommand, "readonly", 1,1,1) == REDISMODULE_ERR) return REDISMODULE_ERR; return REDISMODULE_OK; }
*ctx, RedisModuleString **argv, int argc) { // ... } int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { // Register the module or error out if (RedisModule_Init(ctx, "process_tweet", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) return REDISMODULE_ERR; // Register the command or error out if (RedisModule_CreateCommand(ctx, "process_tweet.rand", ProcessTweet_RedisCommand, "readonly", 1,1,1) == REDISMODULE_ERR) return REDISMODULE_ERR; return REDISMODULE_OK; } The logic of the module
(RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_EMPTY) { RedisModule_StringSet(key,argv[2]); } RedisModule_CloseKey(key); Open a key. Return a key pointer
(RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_EMPTY) { RedisModule_StringSet(key,argv[2]); } RedisModule_CloseKey(key); Set a string value for a key