Comprehensive guide to Redis. Part 1.

Redis (REmote DIctionary Server) is an advanced key-value data store. Read and write operations in Redis are very fast because it saves all data in the memory. Redis can also save data on the hard drive. The official Redis documentation can be found at http://redis.io. Redis is an open sources project used by many companies including Instagram and Twitter. In this tutorial, we will install Redis, install Node.js, and try out several data types.

In this series of tutorials, I’m using Redis 3.0.5 as well as Linux Mint.

To install Redis you should:
1. Download the latest stable release from http://redis.io/download
2. Unpack it
3. Run sudo make install
4. After the installation is finished, run make test to check whether everything is working correctly

There are several executable commands in Redis:
– redis-cli: command-line interface for Redis(client part)
– redis-server: Redis data store.

By default, Redis binds to port 6379. Run redis-server in your terminal.
r1

You can run the Redis client via redis-cli.
SET: creates a key with a string value
GET: reads the key value

r2

The HELP command is useful for learning about syntax.

r3

The KEYS command returns all keys that match a pattern.

r4

Now it’s time to install Node.js. You can download it at https://nodejs.org/en/download/.

Then create a separate folder for this tutorial, for example tutorial1. Run npm install redis inside this folder. This will install the redis module for Node.js.

Now let’s create a classic “Hello World” example. Create a file called helloworld.js with the following code:

Now run node helloworld. You should see the following:

r5

Redis data types

Different Redis data types are used to solve different issues.

String data type can store any data: text, binary, integers. A String can not exceed 512MB.
String use cases:
– counting. You can store numbers like page views or video views. To increment or decrement values, you can use INCR, INCRBY, DECR, DECRBY, and INCRFLOATBY commands.
– cache. You can cache binary or text data. It can be implemented using SET, GET, MSET, MGET commands. Strings have an automatic key expiration through the SETEX, EXPIRE, and EXPIREAT commands.

MSET: sets the values of multiple keys at once.
MGET: returns the values of multiple keys at once.

r6

EXPIRE: adds an expiration time in seconds to a given key. After that time, the is automatically deleted. It returns 1 (expiration is set successfully) or 0 (the key does not exist or cannot be set).

TTL(Time To Live): returns an integer(seconds a given key has left to live). It can also return -2 (the key is expired or does not exist) or -1(the key exists but no expiration time set).

r7

INCR: increments a key by 1 and returns the value
INCRBY: increments a key by a given number and returns the value
DECR: decrements a key by 1 and returns the value
DECRBY: decrements a key by a given number and returns the value
INCRBYFLOAT: increments a key by a given float number and returns the value

INCRBY, DECRBY, and INCRBYFLAOT can accept positive or negative numbers.

r8

Notice that the above commands are atomic(2 different clients can not execute the same command at the same time). Redis is single threaded. It always executes one command at a time.

Let’s create a String example. We will create an application with a set of functions used to like and dislike photos. Add 3 examples:

r9

Notice the key structure: photo:[ID]:title. In this key we store our photo title. In the second key photo:[ID]:likes we will store the number of likes. The following example explains better.

There will be 3 functions in our code, the first increments the number of likes by 1, the seconds decrements the number of likes by 1, and the third displays the results. Create a file photolikes.js with the following code:

Notice that all Redis commands have an optional callback function for errors and replies from the Redis server. We are using one of this callback in the mget function.

Now run node photolikes. You should see the following output:

r10

The next data type we are going to take up is Lists. This data type acts like a simple collection, stack, or queue. List commands are atomic. There are blocking commands in Redis’s Lists. It means that when a client executes a command in an empty List, the client will wait for a new item to be added in the List. Redis’s Lists are linked lists. A single List can hold more that 4 billion elements.

List use cases:
– storing most recent posts. As Twitter does.
– event queue

LPUSH: inserts data at the beginning of a List(left push)
RPUSH: inserts data at the end of a List(right push)

r11

LLEN: returns the length of a List
LINDEX: returns the element in a given index(indices are zero-based)

It is possible to use negative indicies. -1 is the last element, -2 is penultimate, and so on.

r12

LRANGE: returns an array with all elements from a given index range(including the start and the end indicies).

r13

LPOP: removes and returns the first element of a List
RPOP: removes and returns the last element of a List

r14

Now let’s implement a simple log queue system. Items there are inserted at the front of the queue and removed from the end(FIFO – First In, First Out). Create a file called logqueue.js with the following code:

The producer pushes messages into the “logs” queue. The consumer then pops messages in another terminal window.

Create a file producer.js, which is going to add logs to a queue:

Now execute the producer file. You should see the following:
r15

Create a consumer.js file and add the following code:

The queue system is ready. Run node producer on one terminal window and node consumer in another. Notice the consumer will continue waiting for new messages, so you can run node producer again to see new log messages.

r16

The above example is not ready for production environment. If anything goes wrong, popped items may be not properly handled. You can use RPOPLPUSH to add the item to an additional queue and check that there are no errors.

Now it’s time to discover hashes. Hashes are great for storing objects. The are optimized to use memory efficiently. Hash is a mapping of a String to a String. Hash can be a ziplist or a hash table. A zilpist is a memory efficient dually linked list. Hash table is not memory-optimized but has a constant-time lookup.

HSET: sets a value to a field of a given key
HMSET: sets multiple field values to a key
HINCRBY: increments a field by a given integer
HINCRBYFLOAT: increments a field by a given float
HGET: retrieves a field from a hash
HMGET: retrieves multiple fields at once

r17

HGETALL: returns an array of all field/value pairs in a hash
HDEL: deletes a field from a hash

r18

HKEYS: returns only the field names
HVALS: returns only the field values

r19

Let’s create an example application. It will be a book voting system with upvote and downvote functions.

Create a bookvotes.js file:

Now run node bookvotes.

r20

Notice that HGETALL may have a memory issues if a Hash has many fields. In this case, it is better using the HSCAN function. It returns a cursor and the Hash fields with their values in chunks. You need to execute this function until the returned cursor is 0.

r21

The above example may return something like

In this case to retrieve the next chunk of data we need to run HSCAN test 17.

In this tutorial, we installed Redis and tried out several data types. That’s all for today 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *