<h1><aname="INFO">INFO</a></h1><blockquote>The info command returns different information and statistics about the server in an format that's simple to parse by computers and easy to red by huamns.</blockquote>
#sidebar <ahref="ControlCommandsSidebar.html">ControlCommandsSidebar</a><h1><aname="INFO">INFO</a></h1><blockquote>The info command returns different information and statistics about the server in an format that's simple to parse by computers and easy to red by huamns.</blockquote>
<h2><aname="Return value">Return value</a></h2><ahref="ReplyTypes.html">Bulk reply</a>, specifically in the following format:<br/><br/><preclass="codeblock python"name="code">
<h2><aname="Return value">Return value</a></h2><ahref="ReplyTypes.html">Bulk reply</a>, specifically in the following format:<br/><br/><preclass="codeblock python"name="code">
edis_version:0.07
edis_version:0.07
connected_clients:1
connected_clients:1
...
@@ -39,8 +39,6 @@ total_commands_processed:1
...
@@ -39,8 +39,6 @@ total_commands_processed:1
uptime_in_seconds:25
uptime_in_seconds:25
uptime_in_days:0
uptime_in_days:0
</pre>All the fields are in the form <codename="code"class="python">field:value</code><h2><aname="Notes">Notes</a></h2><ul><li><codename="code"class="python">used_memory</code> is returned in bytes, and is the total number of bytes allocated by the program using <codename="code"class="python">malloc</code>.</li><li><codename="code"class="python">uptime_in_days</code> is redundant since the uptime in seconds contains already the full uptime information, this field is only mainly present for humans.</li><li><codename="code"class="python">changes_since_last_save</code> does not refer to the number of key changes, but to the number of operations that produced some kind of change in the dataset.</li></ul>
</pre>All the fields are in the form <codename="code"class="python">field:value</code><h2><aname="Notes">Notes</a></h2><ul><li><codename="code"class="python">used_memory</code> is returned in bytes, and is the total number of bytes allocated by the program using <codename="code"class="python">malloc</code>.</li><li><codename="code"class="python">uptime_in_days</code> is redundant since the uptime in seconds contains already the full uptime information, this field is only mainly present for humans.</li><li><codename="code"class="python">changes_since_last_save</code> does not refer to the number of key changes, but to the number of operations that produced some kind of change in the dataset.</li></ul>
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>IntroductionToRedisDataTypes: Contents</b><br> <ahref="#Redis keys">Redis keys</a><br> <ahref="#The string type">The string type</a><br> <ahref="#The List type">The List type</a><br> <ahref="#First steps with Redis lists">First steps with Redis lists</a><br> <ahref="#Pushing IDs instead of the actual data in Redis lists">Pushing IDs instead of the actual data in Redis lists</a><br> <ahref="#Redis Sets">Redis Sets</a><br> <ahref="#A digression. How to get unique identifiers for strings">A digression. How to get unique identifiers for strings</a><br> <ahref="#Sorted sets">Sorted sets</a><br> <ahref="#Operating on ranges">Operating on ranges</a><br> <ahref="#Back to the reddit example">Back to the reddit example</a><br> <ahref="#Updating the scores of a sorted set">Updating the scores of a sorted set</a>
= A fifteen minutes introduction to Redis data types =<br/><br/>As you already probably know Redis is not a plain key-value store, actually it is a <b>data structures server</b>, supporting different kind of values. That is, you can't just set strings as values of keys. All the following data types are supported as values:<br/><br/><ul><li> Binary-safe strings.</li><li> Lists of binary-safe strings.</li><li> Sets of binary-safe strings, that are collection of unique unsorted elements. You can think at this as a Ruby hash where all the keys are set to the 'true' value.</li><li> Sorted sets, similar to Sets but where every element is associated to a floating number score. The elements are taken sorted by score. You can think at this as Ruby hashes where the key is the element and the value is the score, but where elements are always taken in order without requiring a sorting operation.</li></ul>
It's not always trivial to grasp how this data types work and what to use in order to solve a given problem from the <ahref="CommandReference.html">Redis command reference</a>, so this document is a crash course to Redis data types and their most used patterns.<br/><br/>For all the examples we'll use the <b>redis-cli</b> utility, that's a simple but handy command line utility to issue commands against the Redis server.<h2><aname="Redis keys">Redis keys</a></h2>Before to start talking about the different kind of values supported by Redis it is better to start saying that keys are not binary safe strings in Redis, but just strings not containing a space or a newline character. For instance "foo" or "123456789" or "foo_bar" are valid keys, while "hello world" or "hello\n" are not.<br/><br/>Actually there is nothing inside the Redis internals preventing the use of binary keys, it's just a matter of protocol, and actually the new protocol introduced with Redis 1.2 (1.2 betas are 1.1.x) in order to implement commands like MSET, is totally binary safe. Still for now consider this as an hard limit as the database is only tested with "normal" keys.<br/><br/>A few other rules about keys:<br/><br/><ul><li> Too long keys are not a good idea, for instance a key of 1024 bytes is not a good idea not only memory-wise, but also because the lookup of the key in the dataset may require several costly key-comparisons.</li><li> Too short keys are not a good idea. There is no point in writing "u:1000:pwd" as key if you can write instead "user:1000:password", the latter is more readable and the added space is very little compared to the space used by the key object itself.</li><li> Try to stick with a schema. For instance "object-type:id:field" can be a nice idea, like in "user:1000:password". I like to use dots for multi-words fields, like in "comment:1234:reply.to".</li></ul>
<h2><aname="The string type">The string type</a></h2>This is the simplest Redis type. If you use only this type, Redis will be something like a memcached server with persistence.<br/><br/>Let's play a bit with the string type:<br/><br/><preclass="codeblock python"name="code">
$ ./redis-cli set mykey "my binary safe value"
OK
$ ./redis-cli get mykey
my binary safe value
</pre>As you can see using the <ahref="SetCommand.html">Set command</a> and the <ahref="GetCommand.html">Get command</a> is trivial to set values to strings and have this strings returned back.<br/><br/>Values can be strings (including binary data) of every kind, for instance you can store a jpeg image inside a key. A value can't be bigger than 1 Gigabyte.<br/><br/>Even if strings are the basic values of Redis, there are interesting operations you can perform against them. For instance one is atomic increment:<br/><br/><preclass="codeblock python python"name="code">
$ ./redis-cli set counter 100
OK
$ ./redis-cli incr counter
(integer) 101
$ ./redis-cli incr counter
(integer) 102
$ ./redis-cli incrby counter 10
(integer) 112
</pre>The <ahref="IncrCommand.html">INCR</a> command parses the string value as an integer, increments it by one, and finally sets the obtained value as the new string value. There are other similar commands like <ahref="IncrCommand.html">INCRBY</a>, <ahref="IncrCommand.html">DECR</a> and <ahref="IncrCommand.html">DECRBY</a>. Actually internally it's always the same command, acting in a slightly different way.<br/><br/>What means that INCR is atomic? That even multiple clients issuing INCR against the same key will never incur into a race condition. For instance it can't never happen that client 1 read "10", client 2 read "10" at the same time, both increment to 11, and set the new value of 11. The final value will always be of 12 ad the read-increment-set operation is performed while all the other clients are not executing a command at the same time.<br/><br/>Another interesting operation on string is the <ahref="GetsetCommand.html">GETSET</a> command, that does just what its name suggests: Set a key to a new value, returning the old value, as result. Why this is useful? Example: you have a system that increments a Redis key using the <ahref="IncrCommand.html">INCR</a> command every time your web site receives a new visit. You want to collect this information one time every hour, without loosing a single key. You can GETSET the key assigning it the new value of "0" and reading the old value back.<h2><aname="The List type">The List type</a></h2>To explain the List data type it's better to start with a little of theory, as the term <b>List</b> is often used in an improper way by information technology folks. For instance "Python Lists" are not what the name may suggest (Linked Lists), but them are actually Arrays (the same data type is called Array in Ruby actually).<br/><br/>From a very general point of view a List is just a sequence of ordered elements: 10,20,1,2,3 is a list, but when a list of items is implemented using an Array and when instead a <b>Linked List</b> is used for the implementation, the properties change a lot.<br/><br/>Redis lists are implemented via Linked Lists, this means that even if you have million of elements inside a list, the operation of adding a new element in the head or in the tail of the list is performed <b>in constant time</b>. Adding a new element with the <ahref="LpopCommand.html">LPOP</a> command to the head of a ten elements list is the same speed as adding an element to the head of a 10 million elements list.<br/><br/>What's the downside? That accessing an element <b>by index</b> is very fast in lists implemented with an Array and not so fast in lists implemented by linked lists.<br/><br/>Redis Lists are implemented with linked lists because for a database system is crucial to be able to add elements to a very long list in a very fast way. Another strong advantage is, as you'll see in a moment, that Redis Lists can be taken at constant length in constant time.<h3><aname="First steps with Redis lists">First steps with Redis lists</a></h3>The <ahref="RpushCommand.html">LPUSH</a> command add a new element into a list, on the left (on head), while the <ahref="RpushCommand.html">RPUSH</a> command add a new element into alist, ot the right (on tail). Finally the <ahref="LrangeCommand.html">LRANGE</a> command extract ranges of elements from lists:<br/><br/><preclass="codeblock python python python"name="code">
$ ./redis-cli rpush messages "Hello how are you?"
OK
$ ./redis-cli rpush messages "Fine thanks. I'm having fun with Redis"
OK
$ ./redis-cli rpush messages "I should look into this NOSQL thing ASAP"
OK
$ ./redis-cli lrange messages 0 2
1. Hello how are you?
2. Fine thanks. I'm having fun with Redis
3. I should look into this NOSQL thing ASAP
</pre>Note that <ahref="LrangeCommand.html">LRANGE</a> takes two indexes, the first and the last element of the range to return. Both the indexes can be negative to tell Redis to start to count for the end, so -1 is the last element, -2 is the penultimate element of the list, and so forth.<br/><br/>As you can guess from the example above, lists can be used, for instance, in order to implement a chat system. Another use is as queues in order to route messages between different processes. But the key point is that <b>you can use Redis lists every time you require to access data in the same order they are added</b>. This will not require any SQL ORDER BY operation, will be very fast, and will scale to millions of elements even with a toy Linux box.<br/><br/>For instance in ranking systems like the social news reddit.com you can add every new submitted link into a List, and with <ahref="LrangeCommand.html">LRANGE</a> it's possible to paginate results in a trivial way.<br/><br/>In a blog engine implementation you can have a list for every post, where to push blog comments, and so forth.<h3><aname="Pushing IDs instead of the actual data in Redis lists">Pushing IDs instead of the actual data in Redis lists</a></h3>In the above example we pushed our "objects" (simply messages in the example) directly inside the Redis list, but this is often not the way to go, as objects can be referenced in multiple times: in a list to preserve their chronological order, in a Set to remember they are about a specific category, in another list but only if this object matches some kind of requisite, and so forth.<br/><br/>Let's return back to the reddit.com example. A more credible pattern for adding submitted links (news) to the list is the following:<br/><br/><preclass="codeblock python python python python"name="code">
$ ./redis-cli incr next.news.id
(integer) 1
$ ./redis-cli set news:1:title "Redis is simple"
OK
$ ./redis-cli set news:1:url "http://code.google.com/p/redis"
OK
$ ./redis-cli lpush submitted.news 1
OK
</pre>We obtained an unique incremental ID for our news object just incrementing a key, then used this ID to create the object setting a key for every field in the object. Finally the ID of the new object was pushed on the <b>submitted.news</b> list.<br/><br/>This is just the start. Check the <ahref="CommandReference.html">Command Reference</a> and read about all the other list related commands. You can remove elements, rotate lists, get and set elements by index, and of course retrieve the length of the list with <ahref="LLenCommand.html">LLEN</a>.<h2><aname="Redis Sets">Redis Sets</a></h2>Redis Sets are unordered collection of binary-safe strings. The <ahref="SaddCommand.html">SADD</a> command adds a new element to a set. It's also possible to do a number of other operations against sets like testing if a given element already exists, performing the intersection, union or difference between multiple sets and so forth. An example is worth 1000 words:<br/><br/><preclass="codeblock python python python python python"name="code">
$ ./redis-cli sadd myset 1
(integer) 1
$ ./redis-cli sadd myset 2
(integer) 1
$ ./redis-cli sadd myset 3
(integer) 1
$ ./redis-cli smembers myset
1. 3
2. 1
3. 2
</pre>I added three elements to my set and told Redis to return back all the elements. As you can see they are not sorted.<br/><br/>Now let's check if a given element exists:<br/><br/><preclass="codeblock python python python python python python"name="code">
$ ./redis-cli sismember myset 3
(integer) 1
$ ./redis-cli sismember myset 30
(integer) 0
</pre>"3" is a member of the set, while "30" is not. Sets are very good in order to express relations between objects. For instance we can easily Redis Sets in order to implement tags.<br/><br/>A simple way to model this is to have, for every object you want to tag, a Set with all the IDs of the tags associated with the object, and for every tag that exists, a Set of of all the objects tagged with this tag.<br/><br/>For instance if our news ID 1000 is tagged with tag 1,2,5 and 77, we can specify the following two Sets:<br/><br/><preclass="codeblock python python python python python python python"name="code">
$ ./redis-cli sadd news:1000:tags 1
(integer) 1
$ ./redis-cli sadd news:1000:tags 2
(integer) 1
$ ./redis-cli sadd news:1000:tags 5
(integer) 1
$ ./redis-cli sadd news:1000:tags 77
(integer) 1
$ ./redis-cli sadd tag:1:objects 1000
(integer) 1
$ ./redis-cli sadd tag:2:objects 1000
(integer) 1
$ ./redis-cli sadd tag:5:objects 1000
(integer) 1
$ ./redis-cli sadd tag:77:objects 1000
(integer) 1
</pre>To get all the tags for a given object is trivial:<br/><br/>$ ./redis-cli smembers <ahref="news:1000:tags"target="_blank">news:1000:tags</a>
1. 5
2. 1
3. 77
4. 2<br/><br/>But there are other non trivial operations that are still easy to implement using the right Redis commands. For instance we may want the list of all the objects having as tags 1, 2, 10, and 27 at the same time. We can do this using the <ahref="SinterCommand.html">SinterCommand</a> that performs the intersection between different sets. So in order to reach our goal we can just use:<br/><br/><preclass="codeblock python python python python python python python python"name="code">
... no result in our dataset composed of just one object ;) ...
</pre>Look at the <ahref="CommandReference.html">Command Reference</a> to discover other Set related commands, there are a bunch of interesting one. Also make sure to check the <ahref="SortCommand.html">SORT</a> command as both Redis Sets and Lists are sortable.<h2><aname="A digression. How to get unique identifiers for strings">A digression. How to get unique identifiers for strings</a></h2>In our tags example we showed tag IDs without to mention how this IDs can be obtained. Basically for every tag added to the system, you need an unique identifier. You also want to be sure that there are no race conditions if multiple clients are trying to add the same tag at the same time. Also, if a tag already exists, you want its ID returned, otherwise a new unique ID should be created and associated to the tag.<br/><br/>Redis 1.4 will add the Hash type. With it it will be trivial to associate strings with unique IDs, but how to do this today with the current commands exported by Redis in a reliable way?<br/><br/>Our first attempt (that is broken) can be the following. Let's suppose we want to get an unique ID for the tag "redis":<br/><br/><ul><li> In order to make this algorithm binary safe (they are just tags but think to utf8, spaces and so forth) we start performing the SHA1 sum of the tag. SHA1(redis) = b840fc02d524045429941cc15f59e41cb7be6c52.</li><li> Let's check if this tag is already associated with an unique ID with the command <b>GET tag:b840fc02d524045429941cc15f59e41cb7be6c52:id</b>.</li><li> If the above GET returns an ID, return it back to the user. We already have the unique ID.</li><li> Otherwise... create a new unique ID with <b>INCR next.tag.id</b> (assume it returned 123456).</li><li> Finally associate this new ID to our tag with <b>SET tag:b840fc02d524045429941cc15f59e41cb7be6c52:id 123456</b> and return the new ID to the caller.</li></ul>
Nice. Or better.. broken! What about if two clients perform this commands at the same time trying to get the unique ID for the tag "redis"? If the timing is right they'll both get <b>nil</b> from the GET operation, will both increment the <b>next.tag.id</b> key and will set two times the key. One of the two clients will return the wrong ID to the caller. To fix the algorithm is not hard fortunately, and this is the sane version:<br/><br/><ul><li> In order to make this algorithm binary safe (they are just tags but think to utf8, spaces and so forth) we start performing the SHA1 sum of the tag. SHA1(redis) = b840fc02d524045429941cc15f59e41cb7be6c52.</li><li> Let's check if this tag is already associated with an unique ID with the command <b>GET tag:b840fc02d524045429941cc15f59e41cb7be6c52:id</b>.</li><li> If the above GET returns an ID, return it back to the user. We already have the unique ID.</li><li> Otherwise... create a new unique ID with <b>INCR next.tag.id</b> (assume it returned 123456).</li><li> Finally associate this new ID to our tag with <b>SETNX tag:b840fc02d524045429941cc15f59e41cb7be6c52:id 123456</b>. By using SETNX if a different client was faster than this one the key wil not be setted. Not only, SETNX returns 1 if the key is set, 0 otherwise. So... let's add a final step to our computation.</li><li> If SETNX returned 1 (We set the key) return 123456 to the caller, it's our tag ID, otherwise perform <b>GET tag:b840fc02d524045429941cc15f59e41cb7be6c52:id</b> and return the value to the caller.</li></ul>
<h2><aname="Sorted sets">Sorted sets</a></h2>Sets are a very handy data type, but... they are a bit too unsorted in order to fit well for a number of problems ;) This is why Redis 1.2 introduced Sorted Sets. They are very similar to Sets, collections of binary-safe strings, but this time with an associated score, and an operation similar to the List LRANGE operation to return items in order, but working against Sorted Sets, that is, the <ahref="ZrangeCommand.html">ZRANGE</a> command.<br/><br/>Basically Sorted Sets are in some way the Redis equivalent of Indexes in the SQL world. For instance in our reddit.com example above there was no mention about how to generate the actual home page with news raked by user votes and time. We'll see how sorted sets can fix this problem, but it's better to start with something simpler, illustrating the basic working of this advanced data type. Let's add a few selected hackers with their year of birth as "score".<br/><br/><preclass="codeblock python python python python python python python python python"name="code">
</pre>For sorted sets it's a joke to return these hackers sorted by their birth year because actually <b>they are already sorted</b>. Sorted sets are implemented via a dual-ported data structure containing both a skip list and an hash table, so every time we add an element Redis performs an O(log(N)) operation, that's good, but when we ask for sorted elements Redis does not have to do any work at all, it's already all sorted:<br/><br/><preclass="codeblock python python python python python python python python python python"name="code">
$ ./redis-cli zrange hackers 0 -1
1. Alan Turing
2. Claude Shannon
3. Alan Kay
4. Richard Stallman
5. Yukihiro Matsumoto
6. Linus Torvalds
</pre>Didn't know that Linus was younger than Yukihiro btw ;)<br/><br/>Anyway I want to order this elements the other way around, using <ahref="ZREVRANGE.html">ZrangeCommand</a> instead of <ahref="ZRANGE.html">ZrangeCommand</a> this time:<br/><br/><preclass="codeblock python python python python python python python python python python python"name="code">
$ ./redis-cli zrevrange hackers 0 -1
1. Linus Torvalds
2. Yukihiro Matsumoto
3. Richard Stallman
4. Alan Kay
5. Claude Shannon
6. Alan Turing
</pre>A very important note, ZSets have just a "default" ordering but you are still free to call the <ahref="SortCommand.html">SORT</a> command against sorted sets to get a different ordering (but this time the server will waste CPU). An alternative for having multiple orders is to add every element in multiple sorted sets at the same time.<h3><aname="Operating on ranges">Operating on ranges</a></h3>Sorted sets are more powerful than this. They can operate on ranges. For instance let's try to get all the individuals that born up to the 1950. We use the <ahref="ZrangebyscoreCommand.html">ZRANGEBYSCORE</a> command to do it:<br/><br/><preclass="codeblock python python python python python python python python python python python python"name="code">
$ ./redis-cli zrangebyscore hackers -inf 1950
1. Alan Turing
2. Claude Shannon
3. Alan Kay
</pre>We asked Redis to return all the elements with a score between negative infinite and 1950 (both extremes are included).<br/><br/>It's also possible to remove ranges of elements. For instance let's remove all the hackers born between 1940 and 1960 from the sorted set:<br/><br/><preclass="codeblock python python python python python python python python python python python python python"name="code">
$ ./redis-cli zremrangebyscore hackers 1940 1960
(integer) 2
</pre><ahref="ZremrangebyscoreCommand.html">ZREMRANGEBYSCORE</a> is not the best command name, but it can be very useful, and returns the number of removed elements.<h3><aname="Back to the reddit example">Back to the reddit example</a></h3>For the last time, back to the Reddit example. Now we have a decent plan to populate a sorted set in order to generate the home page. A sorted set can contain all the news that are not older than a few days (we remove old entries from time to time using ZREMRANGEBYSCORE). A background job gets all the elements from this sorted set, get the user votes and the time of the news, and compute the score to populate the <b>reddit.home.page</b> sorted set with the news IDs and associated scores. To show the home page we have just to perform a blazingly fast call to ZRANGE.<br/><br/>From time to time we'll remove too old news from the <b>reddit.home.page</b> sorted set as well in order for our system to work always against a limited set of news.<h3><aname="Updating the scores of a sorted set">Updating the scores of a sorted set</a></h3>Just a final note before to finish this tutorial. Sorted sets scores can be updated at any time. Just calling again ZADD against an element already included in the sorted set will update its score (and position) in O(log(N)), so sorted sets are suitable even when there are tons of updates.<br/><br/>This tutorial is in no way complete, this is just the basics to get started with Redis, read the <ahref="CommandReference.html">Command Reference</a> to discover a lot more.<br/><br/>Thanks for reading. Salvatore.
<i>Time complexity: O(n) (with n being the number of keys in the DB, and assuming keys and pattern of limited length)</i><blockquote>Returns all the keys matching the glob-style <i>pattern</i> asspace separated strings. For example if you have in thedatabase the keys "foo" and "foobar" the command "KEYS foo<codename="code"class="python">*</code>"will return "foo foobar".</blockquote>
<i>Time complexity: O(n) (with n being the number of keys in the DB, and assuming keys and pattern of limited length)</i><blockquote>Returns all the keys matching the glob-style <i>pattern</i> asspace separated strings. For example if you have in thedatabase the keys "foo" and "foobar" the command "KEYS foo<codename="code"class="python">*</code>"will return "foo foobar".</blockquote>
<blockquote>Note that while the time complexity for this operation is O(n)the constant times are pretty low. For example Redis runningon an entry level laptop can scan a 1 million keys databasein 40 milliseconds. Still it's better to consider this one ofthe slow commands that may ruin the DB performance if not usedwith care.</blockquote>
<blockquote>Note that while the time complexity for this operation is O(n)the constant times are pretty low. For example Redis runningon an entry level laptop can scan a 1 million keys databasein 40 milliseconds. Still it's better to consider this one ofthe slow commands that may ruin the DB performance if not usedwith care.</blockquote>
Glob style patterns examples:
Glob style patterns examples:
<ul><li> h?llo will match hello hallo hhllo</li><li> h<b>llo will match hllo heeeello
<ul><li> h?llo will match hello hallo hhllo</li><li> h<b>llo will match hllo heeeello
<blockquote>* h<ahref="ae.html">ae</a>llo will match hello and hallo, but not hillo</blockquote>Use \ to escape special chars if you want to match them verbatim.<h2><aname="Return value">Return value</a></h2><ahref="ReplyTypes.html">Bulk reply</a>, specifically a string in the form of space separated list of keys. Note that most client libraries will return an Array of keys and not a single string with space separated keys (that is, split by "" is performed in the client library usually).<h2><aname="See also">See also</a></h2>
<blockquote>* h<ahref="ae.html">ae</a>llo will match hello and hallo, but not hillo</blockquote>Use \ to escape special chars if you want to match them verbatim.<h2><aname="Return value">Return value</a></h2><ahref="ReplyTypes.html">Bulk reply</a>, specifically a string in the form of space separated list of keys. Note that most client libraries will return an Array of keys and not a single string with space separated keys (that is, split by "" is performed in the client library usually).
<blockquote>* <ahref="RandomkeyCommand.html">RANDOMKEY</a> to get the name of a randomly selected key in O(1).</blockquote></b></li></ul>
<blockquote>Return the UNIX TIME of the last DB save executed with success.A client may check if a <ahref="BgsaveCommand.html">BGSAVE</a> command succeeded reading the LASTSAVEvalue, then issuing a <ahref="BgsaveCommand.html">BGSAVE</a> command and checking at regular intervalsevery N seconds if LASTSAVE changed.</blockquote>
<blockquote>Return the UNIX TIME of the last DB save executed with success.A client may check if a <ahref="BgsaveCommand.html">BGSAVE</a> command succeeded reading the LASTSAVEvalue, then issuing a <ahref="BgsaveCommand.html">BGSAVE</a> command and checking at regular intervalsevery N seconds if LASTSAVE changed.</blockquote>
<h2><aname="Return value">Return value</a></h2><ahref="ReplyTypes.html">Integer reply</a>, specifically an UNIX time stamp.<h2><aname="See also">See also</a></h2>
<h2><aname="Return value">Return value</a></h2><ahref="ReplyTypes.html">Integer reply</a>, specifically an UNIX time stamp.
<i>Time complexity: O(n) (with n being the length of the list)</i><blockquote>Return the specified element of the list stored at the specifiedkey. 0 is the first element, 1 the second and so on. Negative indexesare supported, for example -1 is the last element, -2 the penultimateand so on.</blockquote>
<i>Time complexity: O(n) (with n being the length of the list)</i><blockquote>Return the specified element of the list stored at the specifiedkey. 0 is the first element, 1 the second and so on. Negative indexesare supported, for example -1 is the last element, -2 the penultimateand so on.</blockquote>
<blockquote>If the value stored at key is not of list type an error is returned.If the index is out of range an empty string is returned.</blockquote>
<blockquote>If the value stored at key is not of list type an error is returned.If the index is out of range an empty string is returned.</blockquote>
<blockquote>Note that even if the average time complexity is O(n) asking forthe first or the last element of the list is O(1).</blockquote>
<blockquote>Note that even if the average time complexity is O(n) asking forthe first or the last element of the list is O(1).</blockquote>
<h2><aname="Return value">Return value</a></h2><ahref="ReplyTypes.html">Bulk reply</a>, specifically the requested element.<h2><aname="See also">See also</a></h2>
<h2><aname="Return value">Return value</a></h2><ahref="ReplyTypes.html">Bulk reply</a>, specifically the requested element.
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>ListCommandsSidebar: Contents</b>
</div>
<h1class="wikiname">ListCommandsSidebar</h1>
<divclass="summary">
</div>
<divclass="narrow">
== List Commands ==<br/><br/><ul><li><ahref="RpushCommand.html">RPUSH</a></li><li><ahref="RpushCommand.html">LPUSH</a></li><li><ahref="LlenCommand.html">LLEN</a></li><li><ahref="LrangeCommand.html">LRANGE</a></li><li><ahref="LtrimCommand.html">LTRIM</a></li><li><ahref="LindexCommand.html">LINDEX</a></li><li><ahref="LsetCommand.html">LSET</a></li><li><ahref="LremCommand.html">LREM</a></li><li><ahref="LpopCommand.html">LPOP</a></li><li><ahref="LpopCommand.html">RPOP</a></li><li><ahref="RpoplpushCommand.html">RPOPLPUSH</a></li><li><ahref="SortCommand.html">SORT</a></li></ul>
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>Lists: Contents</b><br> <ahref="#Redis List Type">Redis List Type</a><br> <ahref="#Implementation details">Implementation details</a>
</div>
<h1class="wikiname">Lists</h1>
<divclass="summary">
</div>
<divclass="narrow">
#sidebar <ahref="ListCommandsSidebar.html">ListCommandsSidebar</a><h1><aname="Redis List Type">Redis List Type</a></h1>Redis Lists are lists of <ahref="Stings.html">Redis Strings</a>, sorted by insertion order. It's possible to add elements to a Redis List pushing new elements on the head (on the left) or on the tail (on the right) of the list.<br/><br/>The <ahref="RpushCommand.html">LPUSH</a> command inserts a new elmenet on head, while <ahref="RpushCommand.html">RPUSH</a> inserts a new element on tail. A new list is created when one of this operations is performed against an empty key.<br/><br/>For instance if perform the following operations:
<preclass="codeblock python"name="code">
LPUSH mylist a # now the list is "a"
LPUSH mylist b # now the list is "b","a"
RPUSH mylist c # now the list is "b","a","c" (RPUSH was used this time)
</pre>
The resulting list stored at <i>mylist</i> will contain the elements "b","a","c".<br/><br/>The max length of a list is 232-1 elements (4294967295, more than 4 billion of elements per list).<h1><aname="Implementation details">Implementation details</a></h1>Redis Lists are implemented as doubly liked lists. A few commands benefit from the fact the lists are doubly linked in order to reach the needed element starting from the nearest extreme (head or tail). <ahref="LrangeCommand.html">LRANGE</a> and <ahref="LindexCommand.html">LINDEX</a> are examples of such commands.<br/><br/>The use of linked lists also guarantees that regardless of the length of the list pushing and popping are O(1) operations.<br/><br/>Redis Lists cache length information so <ahref="LlenCommand.html">LLEN</a> is O(1) as well.
<i>Time complexity: O(1)</i><blockquote>Return the length of the list stored at the specified key. If thekey does not exist zero is returned (the same behaviour as forempty lists). If the value stored at <i>key</i> is not a list an error is returned.</blockquote>
<i>Time complexity: O(1)</i><blockquote>Return the length of the list stored at the specified key. If thekey does not exist zero is returned (the same behaviour as forempty lists). If the value stored at <i>key</i> is not a list an error is returned.</blockquote>
<i>Time complexity: O(1)</i><blockquote>Atomically return and remove the first (LPOP) or last (RPOP) elementof the list. For example if the list contains the elements "a","b","c" LPOPwill return "a" and the list will become "b","c".</blockquote>
<i>Time complexity: O(1)</i><blockquote>Atomically return and remove the first (LPOP) or last (RPOP) elementof the list. For example if the list contains the elements "a","b","c" LPOPwill return "a" and the list will become "b","c".</blockquote>
<blockquote>If the <i>key</i> does not exist or the list is already empty the specialvalue 'nil' is returned.</blockquote>
<blockquote>If the <i>key</i> does not exist or the list is already empty the specialvalue 'nil' is returned.</blockquote>
<i>Time complexity: O(n) (with n being the length of the range)</i><blockquote>Return the specified elements of the list stored at the specifiedkey. Start and end are zero-based indexes. 0 is the first elementof the list (the list head), 1 the next element and so on.</blockquote>
<i>Time complexity: O(n) (with n being the length of the range)</i><blockquote>Return the specified elements of the list stored at the specifiedkey. Start and end are zero-based indexes. 0 is the first elementof the list (the list head), 1 the next element and so on.</blockquote>
<blockquote>For example LRANGE foobar 0 2 will return the first three elementsof the list.</blockquote>
<blockquote>For example LRANGE foobar 0 2 will return the first three elementsof the list.</blockquote>
<blockquote>_start_ and <i>end</i> can also be negative numbers indicating offsetsfrom the end of the list. For example -1 is the last element ofthe list, -2 the penultimate element and so on.</blockquote>
<blockquote>_start_ and <i>end</i> can also be negative numbers indicating offsetsfrom the end of the list. For example -1 is the last element ofthe list, -2 the penultimate element and so on.</blockquote>
<blockquote>Indexes out of range will not produce an error: if start is overthe end of the list, or start <codename="code"class="python">></code> end, an empty list is returned.If end is over the end of the list Redis will threat it just likethe last element of the list.</blockquote>
<blockquote>Indexes out of range will not produce an error: if start is overthe end of the list, or start <codename="code"class="python">></code> end, an empty list is returned.If end is over the end of the list Redis will threat it just likethe last element of the list.</blockquote>
<h2><aname="Return value">Return value</a></h2><ahref="ReplyTypes.html">Multi bulk reply</a>, specifically a list of elements in the specified range.<h2><aname="See also">See also</a></h2>
<h2><aname="Return value">Return value</a></h2><ahref="ReplyTypes.html">Multi bulk reply</a>, specifically a list of elements in the specified range.
<i>Time complexity: O(N) (with N being the length of the list)</i><blockquote>Remove the first <i>count</i> occurrences of the <i>value</i> element from the list.If <i>count</i> is zero all the elements are removed. If <i>count</i> is negativeelements are removed from tail to head, instead to go from head to tailthat is the normal behaviour. So for example LREM with count -2 and_hello_ as value to remove against the list (a,b,c,hello,x,hello,hello) willlave the list (a,b,c,hello,x). The number of removed elements is returnedas an integer, see below for more information about the returned value.Note that non existing keys are considered like empty lists by LREM, so LREMagainst non existing keys will always return 0.</blockquote>
<i>Time complexity: O(N) (with N being the length of the list)</i><blockquote>Remove the first <i>count</i> occurrences of the <i>value</i> element from the list.If <i>count</i> is zero all the elements are removed. If <i>count</i> is negativeelements are removed from tail to head, instead to go from head to tailthat is the normal behaviour. So for example LREM with count -2 and_hello_ as value to remove against the list (a,b,c,hello,x,hello,hello) willlave the list (a,b,c,hello,x). The number of removed elements is returnedas an integer, see below for more information about the returned value.Note that non existing keys are considered like empty lists by LREM, so LREMagainst non existing keys will always return 0.</blockquote>
<i>Time complexity: O(N) (with N being the length of the list)</i><blockquote>Set the list element at <i>index</i> (see LINDEX for information about the_index_ argument) with the new <i>value</i>. Out of range indexes willgenerate an error. Note that setting the first or last elements ofthe list is O(1).</blockquote>
<i>Time complexity: O(N) (with N being the length of the list)</i><blockquote>Set the list element at <i>index</i> (see LINDEX for information about the_index_ argument) with the new <i>value</i>. Out of range indexes willgenerate an error. Note that setting the first or last elements ofthe list is O(1).</blockquote>
<i>Time complexity: O(n) (with n being len of list - len of range)</i><blockquote>Trim an existing list so that it will contain only the specifiedrange of elements specified. Start and end are zero-based indexes.0 is the first element of the list (the list head), 1 the next elementand so on.</blockquote>
<i>Time complexity: O(n) (with n being len of list - len of range)</i><blockquote>Trim an existing list so that it will contain only the specifiedrange of elements specified. Start and end are zero-based indexes.0 is the first element of the list (the list head), 1 the next elementand so on.</blockquote>
<blockquote>For example LTRIM foobar 0 2 will modify the list stored at foobarkey so that only the first three elements of the list will remain.</blockquote>
<blockquote>For example LTRIM foobar 0 2 will modify the list stored at foobarkey so that only the first three elements of the list will remain.</blockquote>
<blockquote>_start_ and <i>end</i> can also be negative numbers indicating offsetsfrom the end of the list. For example -1 is the last element ofthe list, -2 the penultimate element and so on.</blockquote>
<blockquote>_start_ and <i>end</i> can also be negative numbers indicating offsetsfrom the end of the list. For example -1 is the last element ofthe list, -2 the penultimate element and so on.</blockquote>
...
@@ -36,8 +36,8 @@
...
@@ -36,8 +36,8 @@
LPUSH mylist <someelement>
LPUSH mylist <someelement>
LTRIM mylist 0 99
LTRIM mylist 0 99
</pre><blockquote>The above two commands will push elements in the list taking care thatthe list will not grow without limits. This is very useful when usingRedis to store logs for example. It is important to note that when usedin this way LTRIM is an O(1) operation because in the average casejust one element is removed from the tail of the list.</blockquote>
</pre><blockquote>The above two commands will push elements in the list taking care thatthe list will not grow without limits. This is very useful when usingRedis to store logs for example. It is important to note that when usedin this way LTRIM is an O(1) operation because in the average casejust one element is removed from the tail of the list.</blockquote>
<i>Time complexity: O(1) for every key</i><blockquote>Get the values of all the specified keys. If one or more keys dont existor is not of type String, a 'nil' value is returned instead of the valueof the specified key, but the operation never fails.</blockquote>
<i>Time complexity: O(1) for every key</i><blockquote>Get the values of all the specified keys. If one or more keys dont existor is not of type String, a 'nil' value is returned instead of the valueof the specified key, but the operation never fails.</blockquote>
<h1><aname="MONITOR">MONITOR</a></h1><blockquote>MONITOR is a debugging command that outputs the whole sequence of commandsreceived by the Redis server. is very handy in order to understandwhat is happening into the database. This command is used directlyvia telnet.</blockquote>
#sidebar <ahref="ControlCommandsSidebar.html">ControlCommandsSidebar</a><h1><aname="MONITOR">MONITOR</a></h1><blockquote>MONITOR is a debugging command that outputs the whole sequence of commandsreceived by the Redis server. is very handy in order to understandwhat is happening into the database. This command is used directlyvia telnet.</blockquote>
<preclass="codeblock python"name="code">
<preclass="codeblock python"name="code">
% telnet 127.0.0.1 6379
% telnet 127.0.0.1 6379
Trying 127.0.0.1...
Trying 127.0.0.1...
...
@@ -52,8 +52,8 @@ set foo_a 5
...
@@ -52,8 +52,8 @@ set foo_a 5
hello
hello
</pre><blockquote>The ability to see all the requests processed by the server is useful in orderto spot bugs in the application both when using Redis as a database and asa distributed caching system.</blockquote>
</pre><blockquote>The ability to see all the requests processed by the server is useful in orderto spot bugs in the application both when using Redis as a database and asa distributed caching system.</blockquote>
<blockquote>In order to end a monitoring session just issue a QUIT command by hand.</blockquote>
<blockquote>In order to end a monitoring session just issue a QUIT command by hand.</blockquote>
<h2><aname="Return value">Return value</a></h2><b>Non standard return value</b>, just dumps the received commands in an infinite flow.<h2><aname="See also">See also</a></h2>
<h2><aname="Return value">Return value</a></h2><b>Non standard return value</b>, just dumps the received commands in an infinite flow.
<blockquote>Move the specified key from the currently selected DB to the specifieddestination DB. Note that this command returns 1 only if the key wassuccessfully moved, and 0 if the target key was already there or if thesource key was not found at all, so it is possible to use MOVE as a lockingprimitive.</blockquote>
<blockquote>Move the specified key from the currently selected DB to the specifieddestination DB. Note that this command returns 1 only if the key wassuccessfully moved, and 0 if the target key was already there or if thesource key was not found at all, so it is possible to use MOVE as a lockingprimitive.</blockquote>
<i>Time complexity: O(1) to set every key</i><blockquote>Set the the rispective keys to the rispective values. MSET will replace oldvalues with new values, while MSETNX will not perform any operation at alleven if just a single key already exists.</blockquote>
<i>Time complexity: O(1) to set every key</i><blockquote>Set the the rispective keys to the rispective values. MSET will replace oldvalues with new values, while MSETNX will not perform any operation at alleven if just a single key already exists.</blockquote>
<blockquote>Because of this semantic MSETNX can be used in order to set different keysrepresenting different fields of an unique logic object in a way thatensures that either all the fields or none at all are set.</blockquote>
<blockquote>Because of this semantic MSETNX can be used in order to set different keysrepresenting different fields of an unique logic object in a way thatensures that either all the fields or none at all are set.</blockquote>
0 if no key was set (at least one key already existed)
0 if no key was set (at least one key already existed)
</pre><h2><aname="See also">See also</a></h2><ul><li><ahref="MgetCommand.html">MGET</a></li><li><ahref="DelCommand.html">DEL</a> (DEL supports deleting multiple keys in a single operation)</li></ul>
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>QuickStart: Contents</b><br> <ahref="#Quick Start">Quick Start</a><br> <ahref="#Obtain the latest version">Obtain the latest version</a><br> <ahref="#Compile">Compile</a><br> <ahref="#Run the server">Run the server</a><br> <ahref="#Play with the built in client">Play with the built in client</a><br> <ahref="#Further reading">Further reading</a>
<b>QuickStart: Contents</b><br> <ahref="#Obtain the latest version">Obtain the latest version</a><br> <ahref="#Compile">Compile</a><br> <ahref="#Run the server">Run the server</a><br> <ahref="#Play with the built in client">Play with the built in client</a><br> <ahref="#Further reading">Further reading</a>
</div>
</div>
<h1class="wikiname">QuickStart</h1>
<h1class="wikiname">QuickStart</h1>
...
@@ -26,7 +26,7 @@
...
@@ -26,7 +26,7 @@
</div>
</div>
<divclass="narrow">
<divclass="narrow">
<h1><aname="Quick Start">Quick Start</a></h1>This quickstart is a five minutes howto on how to get started with Redis. For more information on Redis check <ahref="http://code.google.com/p/redis/wiki/index"target="_blank">Redis Documentation Index</a>.<h2><aname="Obtain the latest version">Obtain the latest version</a></h2>The latest stable source distribution of Redis can be obtained <ahref="http://code.google.com/p/redis/downloads/list"target="_blank">at this location as a tarball</a>.<br/><br/><preclass="codeblock python"name="code">
= Quick Start =<br/><br/>This quickstart is a five minutes howto on how to get started with Redis. For more information on Redis check <ahref="http://code.google.com/p/redis/wiki/index"target="_blank">Redis Documentation Index</a>.<h2><aname="Obtain the latest version">Obtain the latest version</a></h2>The latest stable source distribution of Redis can be obtained <ahref="http://code.google.com/p/redis/downloads/list"target="_blank">at this location as a tarball</a>.<br/><br/><preclass="codeblock python"name="code">
</pre>The unstable source code, with more features but not ready for production, can be downloaded using git:<br/><br/><preclass="codeblock python python"name="code">
</pre>The unstable source code, with more features but not ready for production, can be downloaded using git:<br/><br/><preclass="codeblock python python"name="code">
$ git clone git://github.com/antirez/redis.git
$ git clone git://github.com/antirez/redis.git
...
@@ -57,18 +57,7 @@ firstvalue
...
@@ -57,18 +57,7 @@ firstvalue
$ ./redis-cli lrange mylist 0 -1
$ ./redis-cli lrange mylist 0 -1
1. thirdvalue
1. thirdvalue
2. secondvalue
2. secondvalue
</pre><ahref="Lists.html">Lists</a> (and <ahref="Sets.html">Sets</a> too) can be sorted:<br/><br/><preclass="codeblock python python python python python python python"name="code">
</pre><h2><aname="Further reading">Further reading</a></h2><ul><li> What to play more with Redis? Read <ahref="IntroductionToRedisDataTypes.html">Fifteen minutes introduction to Redis data types</a>.</li><li> Check all the <ahref="Features.html">Features</a></li><li> Read the full list of available commands in the <ahref="CommandReference.html">Command Reference</a>.</li><li> Start using Redis from your <ahref="SupportedLanguages.html">favorite language</a>.</li><li> Take a look at some <ahref="ProgrammingExamples.html">Programming Examples</a>. </li></ul>
./redis-cli sort mylist alpha
1. secondvalue
2. thirdvalue
</pre>And despite Redis doesn't have integers, you can do some math also:<br/><br/><preclass="codeblock python python python python python python python python"name="code">
$ ./redis-cli get mycounter
(nil)
$ ./redis-cli incr mycounter
1
./redis-cli incr mycounter
2
</pre><h2><aname="Further reading">Further reading</a></h2><ul><li> Check all the <ahref="Features.html">Features</a></li><li> Read the full list of available commands in the <ahref="CommandReference.html">Command Reference</a>.</li><li> Start using Redis from your <ahref="SupportedLanguages.html">favorite language</a>.</li><li> Take a look at some <ahref="ProgrammingExamples.html">Programming Examples</a>. </li></ul>
<h1><aname="Quit">Quit</a></h1><blockquote>Ask the server to silently close the connection.</blockquote>
#sidebar <ahref="ConnectionHandlingSidebar.html">ConnectionHandlingSidebar</a><h1><aname="Quit">Quit</a></h1><blockquote>Ask the server to silently close the connection.</blockquote>
<h2><aname="Return value">Return value</a></h2>None. The connection is closed as soon as the QUIT command is received.
<h2><aname="Return value">Return value</a></h2>None. The connection is closed as soon as the QUIT command is received.
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>README: Contents</b><br> <ahref="#Introduction">Introduction</a><br> <ahref="#Beyond key-value databases">Beyond key-value databases</a><br> <ahref="#What are the differences between Redis and Memcached?">What are the differences between Redis and Memcached?</a><br> <ahref="#What are the differences between Redis and Tokyo Cabinet / Tyrant?">What are the differences between Redis and Tokyo Cabinet / Tyrant?</a><br> <ahref="#Does Redis support locking?">Does Redis support locking?</a><br> <ahref="#Multiple databases support">Multiple databases support</a><br> <ahref="#Redis Data Types">Redis Data Types</a><br> <ahref="#Implementation Details">Implementation Details</a><br> <ahref="#Redis Tutorial">Redis Tutorial</a><br> <ahref="#License">License</a><br> <ahref="#Credits">Credits</a>
<b>README: Contents</b><br> <ahref="#All data in memory, but saved on disk">All data in memory, but saved on disk</a><br> <ahref="#Master-Slave replication made trivial">Master-Slave replication made trivial</a><br> <ahref="#It's persistent but supports expires">It's persistent but supports expires</a><br> <ahref="#Beyond key-value databases">Beyond key-value databases</a><br> <ahref="#Multiple databases support">Multiple databases support</a><br> <ahref="#Know more about Redis!">Know more about Redis!</a><br> <ahref="#Redis Tutorial">Redis Tutorial</a><br> <ahref="#License">License</a><br> <ahref="#Credits">Credits</a>
</div>
</div>
<h1class="wikiname">README</h1>
<h1class="wikiname">README</h1>
...
@@ -26,32 +26,11 @@
...
@@ -26,32 +26,11 @@
</div>
</div>
<divclass="narrow">
<divclass="narrow">
<h1><aname="Introduction">Introduction</a></h1>Redis is a database. To be specific, Redis is a very simple database implementing a dictionary, where every key is associated with a value. For example I can set the key "surname_1992" to the string "Smith".
= Introduction =<br/><br/>Redis is a database. To be specific, Redis is a database implementing a dictionary, where every key is associated with a value. For example I can set the key "surname_1992" to the string "Smith".
What makes Redis different from many other key-value stores, is that every single value has a type. The following types are supported:<br/><br/><ul><li> String</li><li> List</li><li> Set</li><li> Sorted Set (since version 1.1)</li></ul>
What makes Redis different from many other key-value stores, is that every single value has a type. The following types are supported:<br/><br/><ul><li> String</li><li> List</li><li> Set</li><li> Sorted Set (since version 1.1)</li></ul>
The type of a value determines what operations (called commands) are available for the value itself.
The type of a value determines what operations (called commands) are available for the value itself.
For example you can append elements to a list stored at the key "mylist" using the LPUSH or RPUSH command in O(1). Later you'll be able to get a range of elements with LRANGE or trim the list with LTRIM. Sets are very flexible too, it is possible to add and remove elements from Sets (unsorted collections of strings), and then ask for server-side intersection, union, difference of Sets. Each command is performed through server-side atomic operations.
For example you can append elements to a list stored at the key "mylist" using the LPUSH or RPUSH command in O(1). Later you'll be able to get a range of elements with LRANGE or trim the list with LTRIM. Sets are very flexible too, it is possible to add and remove elements from Sets (unsorted collections of strings), and then ask for server-side intersection, union, difference of Sets. Each command is performed through server-side atomic operations.
Please refer to the <ahref="CommandReference.html">Command Reference</a> to see the full list of operations associated to these data types.<br/><br/>In other words, you can look at Redis as a data structures server. A Redis user is virtually provided with an interface to <ahref="http://en.wikipedia.org/wiki/Abstract_data_type"target="_blank">Abstract Data Types</a>, saving her from the responsibility to implement concrete data structures and algorithms. Indeed both algorithms and data structures in Redis are properly choosed in order to obtain the best performance.<br/><br/>Redis loads and mantains the whole dataset into memory, but the dataset is persistent, since from time to time Redis writes a dump on disk asynchronously. The dataset is loaded from the dump every time the server is (re)started.<br/><br/>Redis can be configured to save the dataset when a certain number of changes is reached and after a given number of seconds elapses. For example, you can configure Redis to save after 1000 changes and at most 60 seconds since the last save. You can specify any combination for these numbers.<br/><br/>Because data is written asynchronously, when a system crash occurs, the last few queries can get lost (that is acceptable in many applications). Anyway it is possible to make this a non issue, since Redis supports master-slave replication from its early days, being effective even in the case where a few records lost are not acceptable.<h1><aname="Beyond key-value databases">Beyond key-value databases</a></h1>All these features allow to use Redis as the sole DB for your scalable application without the need of any relational database. <ahref="TwitterAlikeExample.html">We wrote a simple Twitter clone in PHP + Redis</a> to show a real world example, the link points to an article explaining the design and internals in very simple words.<h1><aname="What are the differences between Redis and Memcached?">What are the differences between Redis and Memcached?</a></h1>In the following ways:<br/><br/><ul><li> Memcached is not persistent, it just holds everything in memory without saving since its main goal is to be used as a cache. Redis instead can be used as the main DB for the application. We <ahref="TwitterAlikeExample.html">wrote a simple Twitter clone</a> using only Redis as database.</li></ul>
Please refer to the <ahref="CommandReference.html">Command Reference</a> to see the full list of operations associated to these data types.<br/><br/>In other words, you can look at Redis as a data structures server. A Redis user is virtually provided with an interface to <ahref="http://en.wikipedia.org/wiki/Abstract_data_type"target="_blank">Abstract Data Types</a>, saving her from the responsibility to implement concrete data structures and algorithms. Indeed both algorithms and data structures in Redis are properly choosed in order to obtain the best performance.<h1><aname="All data in memory, but saved on disk">All data in memory, but saved on disk</a></h1>Redis loads and mantains the whole dataset into memory, but the dataset is persistent, since at the same time it is saved on disk, so that when the server is restarted data can be loaded back in memory.<br/><br/>There are two kind of persistence supported: the first one is called snapshotting. In this mode Redis, from time to time, writes a dump on disk asynchronously. The dataset is loaded from the dump every time the server is (re)started.<br/><br/>Redis can be configured to save the dataset when a certain number of changes is reached and after a given number of seconds elapses. For example, you can configure Redis to save after 1000 changes and at most 60 seconds since the last save. You can specify any combination for these numbers.<br/><br/>Because data is written asynchronously, when a system crash occurs, the last few queries can get lost (that is acceptable in many applications but not in all). In order to make this a non issue Redis supports another, safer persistence mode, called <ahref="AppendOnlyFileHowto.html">Append Only File</a>, where every command received altering the dataset (so not a read-only command, but a write command) is written on an append only file ASAP. This commands are <i>replayed</i> when the server is restarted in order to rebuild the dataset in memory.<br/><br/>Redis Append Only File supports a very handy feature: the server is able to safely rebuild the append only file in background in a non-blocking fashion when it gets too long. You can find <ahref="AppendOnlyFileHowto.html">more details in the Append Only File HOWTO</a>.<h1><aname="Master-Slave replication made trivial">Master-Slave replication made trivial</a></h1>Whatever will be the persistence mode you'll use Redis supports master-slave replications if you want to stay really safe or if you need to scale to huge amounts of reads.<br/><br/><b>Redis Replication is trivial to setup</b>. So trivial that all you need to do in order to configure a Redis server to be a slave of another one, with automatic synchronization if the link will go down and so forth, is the following config line: <codename="code"class="python">slaveof 192.168.1.100 6379</code>. <ahref="ReplicationHowto.html">We provide a Replication Howto</a> if you want to know more about this feature.<h1><aname="It's persistent but supports expires">It's persistent but supports expires</a></h1>Redis can be used as a <b>memcached on steroids</b> because is as fast as memcached but with a number of features more. Like memcached, Redis also supports setting timeouts to keys so that this key will be automatically removed when a given amount of time passes.<h1><aname="Beyond key-value databases">Beyond key-value databases</a></h1>All these features allow to use Redis as the sole DB for your scalable application without the need of any relational database. <ahref="TwitterAlikeExample.html">We wrote a simple Twitter clone in PHP + Redis</a> to show a real world example, the link points to an article explaining the design and internals in very simple words.<h1><aname="Multiple databases support">Multiple databases support</a></h1>Redis supports multiple databases with commands to atomically move keys from one database to the other. By default DB 0 is selected for every new connection, but using the SELECT command it is possible to select a different database. The MOVE operation can move an item from one DB to another atomically. This can be used as a base for locking free algorithms together with the 'RANDOMKEY' commands.<h1><aname="Know more about Redis!">Know more about Redis!</a></h1>To really get a feeling about what Redis is and how it works please try reading <ahref="IntroductionToRedisDataTypes.html">A fifteen minutes introduction to Redis data types</a>.<br/><br/>To know a bit more about how Redis works <i>internally</i> continue reading.<h1><aname="Redis Tutorial">Redis Tutorial</a></h1>(note, you can skip this section if you are only interested in "formal" doc.)<br/><br/>Later in this document you can find detailed information about Redis commands,
<ul><li> Like memcached Redis uses a key-value model, but while keys can just be strings, values in Redis can be lists and sets, and complex operations like intersections, set/get n-th element of lists, pop/push of elements, can be performed against sets and lists. It is possible to use lists as message queues.</li></ul>
<h1><aname="What are the differences between Redis and Tokyo Cabinet / Tyrant?">What are the differences between Redis and Tokyo Cabinet / Tyrant?</a></h1>Redis and Tokyo Cabinet can be used for the same applications, but actually they are <b>very</b> different beasts. If you read twitter messages of people involved in scalable things both products are reported to work well, but surely there are times where one or the other can be the best choice. Some differences are the followings (I may be biased, make sure to check yourself both the products).<br/><br/><ul><li> Tokyo Cabinet writes synchronously on disk, Redis takes the whole dataset on memory and writes on disk asynchronously. Tokyo Cabinet is safer and probably a better idea if your dataset is going to be bigger than RAM, but Redis is faster (note that Redis supports master-slave replication that is trivial to setup, so you are safe anyway if you want a setup where data can't be lost even after a disaster).</li></ul>
<ul><li> Redis supports higher level operations and data structures. Tokyo Cabinet supports a kind of database that is able to organize data into rows with named fields (in a way very similar to Berkeley DB) but can't do things like server side List and Set operations Redis is able to do: pushing or popping from Lists in an atomic way, in O(1) time complexity, server side Set intersections, <ahref="SORT.html">SortCommand</a> ing of schema free data in complex ways (Btw TC supports sorting in the table-based database format). Redis on the other hand does not support the abstraction of tables with fields, the idea is that you can build this stuff in software easily if you really need a table-alike approach.</li></ul>
<ul><li> Tokyo Cabinet does not implement a networking layer. You have to use a networking layer called Tokyo Tyrant that interfaces to Tokyo Cabinet so you can talk to Tokyo Cabinet in a client-server fashion. In Redis the networking support is built-in inside the server, and is basically the only interface between the external world and the dataset.</li></ul>
<ul><li> Redis is reported to be much faster, especially if you plan to access Tokyo Cabinet via Tokyo Tyrant. Here I can only say that with Redis you can expect 100,000 operations/seconds with a normal Linux box and 50 concurrent clients. You should test Redis, Tokyo, and the other alternatives with your specific work load to get a feeling about performances for your application.</li></ul>
<ul><li> Redis is (IMHO) generally an higher level and simpler to use beast in the operations supported, and to get started. <ahref="Check.html">the command reference CommandReference</a> to get a feeling. You can even start playing with Redis by telnet after reading the five minutes tutorial at the end of this README file. To implement new client libraries is trivial. <ahref="Check.html">the protocol specification ProtocolSpecification</a> for more information.</li></ul><blockquote></blockquote><ul><li> Redis is not an on-disk DB engine like Tokyo: the latter can be used as a fast DB engine in your C project without the networking overhead just linking to the library. Still in many scalable applications you need multiple servers talking with multiple clients, so the client-server model is almost always needed, this is why in Redis this is built-in.</li></ul>
<h1><aname="Does Redis support locking?">Does Redis support locking?</a></h1>No, the idea is to provide atomic primitives in order to make the programmer
able to use redis with locking free algorithms. For example imagine you have
10 computers and one Redis server. You want to count words in a very large text.
This large text is split among the 10 computers, every computer will process
its part and use Redis's INCR command to atomically increment a counter
for every occurrence of the word found.<br/><br/>INCR/DECR are not the only atomic primitives, there are others like PUSH/POP
on lists, POP RANDOM KEY operations, UPDATE and so on. For example you can
use Redis like a Tuple Space (<ahref="http://en.wikipedia.org/wiki/Tuple_space"target="_blank">http://en.wikipedia.org/wiki/Tuple_space</a>) in
order to implement distributed algorithms.<br/><br/>(News: locking with key-granularity is now planned)<h1><aname="Multiple databases support">Multiple databases support</a></h1>Another synchronization primitive is the support for multiple DBs. By default DB 0 is selected for every new connection, but using the SELECT command it is possible to select a different database. The MOVE operation can move an item from one DB to another atomically. This can be used as a base for locking free algorithms together with the 'RANDOMKEY' commands.<h1><aname="Redis Data Types">Redis Data Types</a></h1>Redis supports the following three data types as values:<br/><br/><ul><li> Strings: just any sequence of bytes. Redis strings are binary safe so they can not just hold text, but images, compressed data and everything else.</li><li> Lists: lists of strings, with support for operations like append a new string on head, on tail, list length, obtain a range of elements, truncate the list to a given length, sort the list, and so on.</li><li> Sets: an unsorted set of strings. It is possible to add or delete elements from a set, to perform set intersection, union, subtraction, and so on.</li></ul>
Values can be Strings, Lists or Sets. Keys can be a subset of strings not containing newlines ("\n") and spaces ("").<br/><br/>Note that sometimes strings may hold numeric vaules that must be parsed by
Redis. An example is the INCR command that atomically increments the number
stored at the specified key. In this case Redis is able to handle integers
that can be stored inside a 'long long' type, that is a 64-bit signed integer.<h2><aname="Implementation Details">Implementation Details</a></h2>Strings are implemented as dynamically allocated strings of characters.
Lists are implemented as doubly linked lists with cached length.
Sets are implemented using hash tables that use chaining to resolve collisions.<h1><aname="Redis Tutorial">Redis Tutorial</a></h1>(note, you can skip this section if you are only interested in "formal" doc.)<br/><br/>Later in this document you can find detailed information about Redis commands,
the protocol specification, and so on. This kind of documentation is useful
the protocol specification, and so on. This kind of documentation is useful
but... if you are new to Redis it is also BORING! The Redis protocol is designed
but... if you are new to Redis it is also BORING! The Redis protocol is designed
so that is both pretty efficient to be parsed by computers, but simple enough
so that is both pretty efficient to be parsed by computers, but simple enough
...
@@ -99,8 +78,8 @@ EXISTS foo
...
@@ -99,8 +78,8 @@ EXISTS foo
exist, and ':1' for 'foo', a key that actually exists. Replies starting with the colon character are integer reply.<br/><br/>Ok... now you know the basics, read the <ahref="CommandReference.html">REDIS COMMAND REFERENCE</a> section to
exist, and ':1' for 'foo', a key that actually exists. Replies starting with the colon character are integer reply.<br/><br/>Ok... now you know the basics, read the <ahref="CommandReference.html">REDIS COMMAND REFERENCE</a> section to
learn all the commands supported by Redis and the <ahref="ProtocolSpecification.html">PROTOCOL SPECIFICATION</a>
learn all the commands supported by Redis and the <ahref="ProtocolSpecification.html">PROTOCOL SPECIFICATION</a>
section for more details about the protocol used if you plan to implement one
section for more details about the protocol used if you plan to implement one
for a language missing a decent client implementation.<h1><aname="License">License</a></h1>Redis is released under the BSD license. See the COPYING file for more information.<h1><aname="Credits">Credits</a></h1>Redis is written and maintained by Salvatore Sanfilippo, Aka 'antirez'.<br/><br/>Enjoy,
for a language missing a decent client implementation.<h1><aname="License">License</a></h1>Redis is released under the BSD license. See the COPYING file for more information.<h1><aname="Credits">Credits</a></h1>Redis is written and maintained by Salvatore Sanfilippo, Aka 'antirez'.