Two years since its initial release, Redis already has an impressive list of adopters, including Engine Yard, GitHub, Craigslist, and Digg. This open source data structure server is built for speed and flexibility, making it ideal for many applications. If you're using Redis, or considering it, this concise cookbook provides recipes for a variety of issues you're likely to face.
Each recipe solves a specific problem, and provides an in-depth discussion of how the solution works. You’ll discover that Redis, while simple in nature, offers extensive functionality for manipulating and storing data.
Learn when it makes sense to use Redis Explore several methods for installing Redis Connect to Redis in a number of ways, ranging from the command line to popular languages such as Python and Ruby Solve a range of needs, from linked datasets to analytics Handle backups, sharding, datasets larger than available memory, and many other tasks
1. Downloading the source You can download Redis from the official site or directly from the Github project, either using Git or your browser to fetch a snapshot of one the branches or tags. This allows you get to get development versions, release candidates, etc. 2. Compiling Redis compilation is straightforward. The only required tools should be a C com- piler (normally GCC) and Make. If you want to run the test suite, you also need Tcl 8.5. After unpacking the source and changing your terminal path to the source direc- tory, just type: make This will compile Redis, which on a modern computer should take less than 10 seconds. If you’re using a x86_64 system but would like an x86 build (which uses less memory but also has a much lower memory limit), you can do so by passing along 32bit to Make: make 32bit After compiling Redis, particularly if you’re building a development version, you should run the test suite to ensure that the server is behaving as expected. make test 3. Installing After compiling Redis, you can go ahead and run it: cd src && ./redis-server However, you might find it more convenient to install it to another location in your system. The Makefile wlll also help you do that: make install
This will install Redis binaries to /usr/local/bin. If you wish to install to another location, you can pass it to make. For instance: make install /opt/local This will install the binaries in /opt/local/bin. After installating the Redis server, you should also copy the configuration file (redis.conf) to a path of your choice, the default being /etc/redis.conf. If your con- figuration file is in a different path from the default, you can pass it along as a parameter to redis-server: /usr/local/bin/redis-server /alternate-location-for-redis-config.conf
Installing on Linux Debian/Ubuntu sudo apt-get install redis-server Fedora/Redhat/CentOS sudo yum install redis Gentoo sudo emerge redis
Using Redis Data Types
Redis includes several built-in data types, allowing developers to structure their data in meaningful semantic ways. Predefined data types add the benefit of being able to perform data- type specific operations inside Redis, which is typically faster than processing the data externally
• Be consistent when defining your key space. Because a key can contain any char- acters, you can use separators to define a namespace with a semantic value for your business. An example might be using cache:project:319:tasks, where the colon acts as a namespace separator.
• When defining your keys, try to limit them to a reasonable size. Retrieving a key from storage requires comparison operations, so keeping keys as small as possible is a good idea. Additionally, smaller keys are more effective in terms of memory usage.
• Even though keys shouldn’t be exceptionally large, there are no big performance improvements for extremely small keys. This means you should design your keys in such a way that combines readability (to help you) and regular key sizes (to help Redis).
Strings The simplest data type in Redis is a string. Strings are also the typical (and frequently the sole) data type in other key-value storage engines. You can store strings of any kind, including binary data. You might, for example, want to cache image data for avatars in a social network. The only thing you need to keep in mind is that a specific value inside Redis shouldn’t go beyond 512MB of data.
Lists Lists in Redis are ordered lists of binary safe strings, implemented on the idea of a linked list. This means that while getting an element by a specific index is a slow operation, adding to the head or tail of the data structure is extremely fast, as it should be in a database. You might want to use lists in order to implement structures such as queues, a recipe for which we’ll look into later in the book.
Hashes Much like traditional hashtables, hashes in Redis store several fields and their values inside a specific key. Hashes are a perfect option to map complex objects inside Redis, by using fields for object attributes (example fields for a car object might be “color”, “brand”, “license plate”).
Sets and Sorted Sets Sets in Redis are an unordered collection of binary-safe strings. Elements in a given set can have no duplicates. For instance, if you try to add an element wheel to a set twice, Redis will ignore the second operation. Sets allow you to perform typical set operations such as intersections and unions. While these might look similar to lists, their implementation is quite different and they are suited to different needs due to the different operations they make available. Mem- ory usage should be higher than when using lists. Sorted sets are a particular case of the set implementation that are defined by a score in addition to the typical binary-safe string. This score allows you to retrieve an ordered list of elements by using the ZRANGE command. We’ll look at some example applications for both sets and sorted sets later in this book.
Using Redis from the Command Line
redis-cli -h
The most typical usage scenarios would be something like the following, to connect to a remote server in interactive mode:
redis-cli -h serverip
The following connects to a local server running on a nondefault port in interactive mode: redis-cli -p 6380
The following connects to a local server on the default port (6379), executes the INFO command, and returns you to your original shell: redis-cli INFO
Using Redis as a Key/Value Store
- Storing application usage counters ( storing something quite basic: counters. Imagine we run a business social network and want to track profile/page visit data. )
- we can use commands such as INCR (or INCRBY) and DECR (or DECRBY) to increment or decrement its contained value.
To store our social network page visit data, we could have a key namespace such as visits:pageid:totals, which for a page ID of 635 would look like visits:635:totals.
If for instance we need to switch from the mysql set the current values in REDIS :
SET visits:1:totals 21389
On a visit to a given page, a simple INCR command would update the counter in Redis: INCR visits:635:totals
We could then grab the page visits for any page, at any time by doing a simple GET command by key:
GET visits:635:totals
you can take advantage of the return value from the INCR command because it returns the post-increment count. A simple pseudocode for visits and counters could look like this: 1. The visitor requests the page. 2. We INCR the visits counter related to the page (INCR visits:635:totals, for in- stance). 3. We capture the return value of the INCR command. 4. We show the user the page with the return value
Ex :
$redis = new Predis_Client($single_server); $nr_visits = $redis->incr('nr_visits');
Storing object data in hashes
We’ll begin by designing a key namespace to store our users. As before, we’ll be sepa- rating keywords with colons to generate a rich key that makes sense in our system. For the sake of this recipe, we’ll go with something simple like keys in the form of users:alias, where alias is a binary-safe string. So to store information about a user called John Doe, we might build a hash called users:jdoe. Let’s also assume we want to store a number of fields about our users, such as a full name, email address, phone number, and number of visits to our application. We’ll use Redis’s hash management commands—like HSET, HGET, and HINCRBY—to store this information.
redis> hset users:jdoe name "John Doe" (integer) 1 redis> hset users:jdoe email "jdoe@test.com" (integer) 1 redis> hset users:jdoe phone "+1555313940" (integer) 1 redis> hincrby users:jdoe visits 1 (integer) 1 With our hash built and in place, we can fetch single fields with HGET or the full hash by using the HGETALL command, as exemplified here:
There are auxiliary commands like HKEYS, which return the keys stored in a particular hash, and HVALS, which returns only the values. Depending on how you want to retrieve your data, you may find it useful to use HGETALL or one of these to retrieve data from Redis into your application.
The Redis command that allows you to list your data is the KEYS command. Use it with the supported wildcard matchers. Thus, the following command: KEYS *
$data = $this->redis->keys('*');
However, that is not enough, as you still may not know what the key type is. That’s what the TYPE command is for: TYPE keyname This will tell you whether that key is a string, hash, list, set, or zset.
The wildcard syntax of the KEYS command is limited but quite useful. It supports queries like: KEYS h*llo Returns all keys starting in h and ending in llo. KEYS h?llo Returns keys that start with h, end with llo, and have exactly one character between them. KEYS h[ae]llo Returns only the keys hallo and hello, if they exist.
HSET hash-name key value Sets a value on a hash with the given key. As with other Redis commands, if the hash doesn’t exist, it’s created.
$this->redis->hset('user',"username","gafitescu"); $this->redis->hset('user',"email","james@james"); $this->redis->hset('user',"address","With Google Chrome, Firefox 4 or higher, or Internet Explore");
$data = $this->redis->hget('user','address'); debug($data); => With Google Chrome, Firefox 4 or higher, or Internet Explore
$data_all = $this->redis->hgetall('user'); debug($data_all); => Array ( [username] => gafitescu [email] => james@james [address] => With Google Chrome, Firefox 4 or higher, or Internet Explore )
HMSET hash-name key1 value1 [key2 value2 ...] Allows you to set several values in a hash with a single command.
$data_all = $this->redis->hgetall('user_info'); debug($data_all); => Array ( [first_name] => James [last_name] => Joyce [sex] => M [age] => 15 )
EXPIRE key seconds Sets an expiration timeout on a key, after which it will be deleted. This can be used on any type of key (strings, hashes, lists, sets or sorted sets) and is one of the most powerful Redis features. EXPIREAT key timestamp Performs the same operation as EXPIRE, except you can specify a UNIX timestamp (seconds since midnight, January 1, 1970) instead of the number of elapsed sec-onds. TTL key Tells you the remaining time to live of a key with an expiration timeout. PERSIST key Removes the expiration timeout on the given key.
You want to leverage Redis’s pub/sub functionality to create a light real-time chat sys- tem with Node.js and Socket.IO.
ZINCRBY zset-name increment element Adds or increments the score of an element in a sorted set. As with ZADD and SADD, the set will be created if it doesn’t exist.
HMGET hash-name field1 [field2 ...] Fetches several fields from a given hash. This command is similar to HGET, but allows you to get several fields in a single operation.
ZINTERSTORE destination-zset number-of-zsets-to-intersect zset1 [zset2 ...] [WEIGHTS weight1 [weight2 ...]] [AGGREGATE SUM | MIN | MAX] Gets the intersection of a given number of ZSETS and store the result in a new ZSET. It’s also possible to pass along a muliplication factor for each ZSET (WEIGHTS) or to specify the aggregation function. By default, it’s a sum of the scores in all the sets, but it can also be the maximum or minimum value.
ZREVRANGE zset-name start-index stop-index [WITHSCORES] Returns the elements in the sorted set within the given range, in descending order. The command can also optionally include the scores of the elements in the returned result. Array ( [0] => Array ( [0] => Kiki ricky micky [1] => 124 )
[1] => Array ( [0] => Pan2 Am [1] => 120 )
[2] => Array ( [0] => 1st serie [1] => 116 )
[3] => Array ( [0] => Sei2field [1] => 114 )
[4] => Array ( [0] => Fr2iends [1] => 108 )
)
$range = $this->redis->zrevrange('show_views_current',0,1, 'withscores'); => get only 2 first elements
The ZRANGE command performs the same operation, but in ascending order.
LRANGE list-name start-index stop-index Returns the list elements in the specified range (including the rightmost element specified).
$list = $this->redis->lrange($list,0,-1 ); =>
Array ( [0] => first [1] => first [2] => second [3] => third )
$this->redis->lrange($list,0,2 ); =>
Array ( [0] => one element [1] => first [2] => first )
LPUSH list-name value Like RPUSH, but inserts the element at the head o f the list
$this->redis->lpush($list,"one element"); Array ( [0] => one element [1] => first [2] => first [3] => second [4] => third )
LLEN list-name Returns the length of the given list. $length = $this->redis->llen($list); debug($length,1);
LREM list-name count value Removes the first count occurrences of elements equal to value from the list stored at key. The count argument influences the operation in the following ways: count > 0: Remove elements equal to value moving from head to tail. count < 0: Remove elements equal to value moving from tail to head. count = 0: Remove all elements equal to value.
For example, LREM list -2 "hello" will remove the last two occurrences of "hello" in the list stored at list. Note that non-existing keys are treated like empty lists, so when key does not exist, the command will always return 0.
Array ( [0] => one element [1] => first [2] => first [3] => second [4] => third )
After removal
Array ( [0] => one element [1] => second [2] => third )
LTRIM list-name start-index stop-index Trims the list so that it only contains the elements in the specified range. It’s similar to the LRANGE command, but instead of just returning the elements, it trims the list.
$this->redis->ltrim($list,1,1 );
LPOP list-name Removes and returns the element at the head of the list. $this->redis->lpop($list);
RPOP list-name Like LPOP, but performs the action at the tail of the list.
$this->redis->rpop($list);
Backing up the files
In case you want an up-to-date snapshot (instead of using the last one Redis did ac- cording to your settings) you can trigger it by issuing: redis-cli BGSAVE File is saved here /var/lib/redis/dump.rdb
It has some nice examples to get started. It is not the book to get a deeper knowledge of redis, but it's the next step after reading a redis primer or the original Redis in Action.
Partiamo dai pregi: i capitoli sull'amministrazione di un server sono abbastanza interessanti.
Tutto il resto, purtroppo, sono difetti.
A partire dagli esempi, basati su concetti non proprio semplici: non puoi spiegare come salvare i dati di OAuth senza spiegare come funziona OAuth, e dandolo per scontato, o fare esempi in Ruby (invece che nel normale linguaggio della console di Redis) mettendoci anche generatori, espressioni lambda e la tipica sintassi di Ruby che nessun altro linguaggio usa e pertanto risulta criptica.
In generale, poi, le spiegazioni sono davvero striminzite, anche nei capitoli sull'amministrazione di sistema. Per esempio dice che si può fare backup tramite uno snapshot, ma non dove andare a prendere lo snapshot, come copiarlo da qualche altra parte, come fare restore pulito, ecc.
Forse era limitato a livello editoriale, forse ha voluto parlare di troppi argomenti, o forse semplicemente aveva in testa come si fanno le cose ma non ha saputo spiegarle.
Overall this is a good overview with some nice use cases. You'll profit most from the code examples if you know some Ruby but the examples are not that esoteric that you won't understand them if you don't. What I'm missing most from the book is an index so you can get from a command to the use case and/or the quick reference that accompanies some of the recipes. Another niggle I have: you would think that it's pretty easy to catch typos in a volume as slim as this one but be prepared to encounter some of them especially towards the end...;-)