Redis is a well-known, efficient in-memory store used to house key-value pairs. Also known as data structure storage, a key can contain various data structures like strings, lists, sets, hashes, etc…
Redis is utilized in situations where quick retrieval and delivery of data is needed.
Redis is used for the following purposes:
Caching
Session management
As a message broker
Event streaming
In this article, we will cover:
Setting up Redis in node application.
Explanation of various data structures and methods associated with them
Use of Redis for server-side caching.
If you are unaware of the installation process of nodejs then you can refer to How to install node.js.
Installing Redis server on Linux and Mac is simple.
Open terminal window, and run these commands for installation.
1 2 3 4
wget https: //download.redis.io/releases/redis-6.2.4.tar.gz tar xzf redis - 6.2 .4.tar.gz cd redis - 6.2 .4 make
This process will take a few minutes.
After installation is complete, you can run redis-server by executing this command.
src/redis-server
If you want to try Redis command line tool, then the command is:
src/redis-cli
Now let’s set up our node.js application.
Create project directory and initiate npm in it.
1 2 3
mkdir redis - intro cd redis - intro npm init - y
This will set up our project. Now we need to install these npm modules,
Express
Redis (npm package to manage Redis operation inside a node application)
npm i -S express redis
Also install nodemon (npm module to rerun server every time we make changes to it).
npm i --save-dev nodemon
Create main server file app.js and set up server to listen at port 8080.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const express = require("express");
const app = express();
const redis = require("redis")
.createClient();
redis.on("connect", function () {
console.log("connected to redis!");
});
app.use(express.json());
app.use(express.urlencoded({
extended: true
}));
app.get("/", function (req, res) {
res.status(200)
.send("I am root!!");
});
app.listen(8080, function () {
console.log("Server for project redis-intro live at port 8080 ");
});
Here we are setting up our server and also connecting to the Redis server running on our system.
Notice I have called createClient while importing the Redis module with no parameters, because by default it will use localhost 6379 as host and port respectively. If you are using the cloud version of Redis or separate host then you can pass those parameters as
createClient(port, host)
Next we are also logging “connected to redis!” when we acquire connection successfully.
Run this server:
nodemon app.js
This will yield output in command line as:
Now before we start working on Redis, let’s understand the types of data structures it uses and methods associated with them.
Redis offers various data structures and all methods related to them can be accessed under the ‘redis object we created just above as redis.method().
A string key value can be simply stored as
1 2 3
redis.set('this is key', 'Value'); /********* OR***********/ redis.set(['this is key', 'value']);
You can get the value of any key by
1
2
3
redis.get('this is key', function (err, reply) {
console.log(reply); // value
});
If you want to use your key and list of values against it you can do so as follows
1
2
3
redis.rpush(['This is key', 'value1', 'value2'], function (err, reply) {
console.log(reply); // 2
});
The first element is key and the rest are values. In list rpush() pushes the element to the right (end) of the list. If you want to push values to front this can be achieved by
1
2
3
redis.lpush(['This is key', 'value1', 'value2'], function (err, reply) {
console.log(reply); // 2
});
You can retrieve the required range of elements of a list by running
1
2
3
redis.lrange('This is key', 0, -1, function (err, reply) {
console.log(reply); // [ 'value1', 'value2' ]
});
They are similar to lists but contain only unique values. These sets are unordered. The values can be added or retrieved as follows.
1
2
3
redis.sadd(['this is key', 'value1', 'value2', 'value3', 'value4', 'value4'], function (err, reply) {
console.log(reply); // 4
});
Notice it will log integer value 4 but we passed 5 elements because set will store only unique values and ignore the last value.You can get all those values by
1
2
3
redis.smembers('this is key', function (err, reply) {
console.log(reply); // [ 'value1', 'value2', 'value3', 'value4' ]
});
Note: Like unordered sets there are also ordered/sorted sets. To implement them, replace Z in place of S in each method such as zadd() instead of sadd().
HashSets are used to store objects. Storing values and retrieving can be done as follows
1
2
3
4
5
6
7
8
9
10
11
12
redis.hmset('Multiple key values', 'key1', 'value1', 'key2', 'value2', 'key3', 'value3');
/*************OR**************/
redis.hmset('Multiple key values', {
'key1': 'value1',
'key2': 'value2',
'key3': 'value3'
});
//To get all values in hashset
redis.hgetall('Mutiple key values ', function (err, object) {
console.log(object); // { key1: 'value1', key2: 'value2', key3: 'value3' }
});
Note: Redis doesn’t support nested objects.
There are also operation methods such as:
redis.exists(key) - boolean response depicting if key exists or not
redis.set(key,value) - to update value of a key
redis.del(key) - to delete a key
redis.expire(key, time)- to set expiry time of a key
redis.incr(key) - to increment integer value against key by 1.
redis.incrby(key,value) - to increment integer value against key by given value
redis.decr(key) - to decrement integer value against key by 1
redis.decrby(key,value) - to decrement integer value against key by given value
In any application, the response time is an important factor in the success of that application. The user wants an application to be fast. We can increase the response time by caching the data that is fetched frequently and responding to client requests with cached data rather than looking into the database.
We will use Redis to cache information of albums from external api and we will try to compare the performance in both cases - when data is retrieved from api and when it is retrieved from
cache.
Here we will be using free api from https://jsonplaceholder.typicode.com/albums.
We will use axios to make a request to this api so install axios.
npm i -S axios
Now open app.js and modify it as follows,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
const express = require("express");
const app = express();
const axios = require("axios");
const redis = require("redis")
.createClient();
const API_URI = "https://jsonplaceholder.typicode.com/albums";
redis.on("connect", function () {
console.log("connected to redis!");
});
app.use(express.json());
app.use(express.urlencoded({
extended: true
}));
app.get("/", function (req, res) {
res.status(200)
.send("I am root!!");
});
app.get("/album-info", function (req, res) {
try {
axios.get(`{API_URI}`)
.then(function (response) {
const albums = response.data;
console.log('Albums retrieved from external api');
res.status(200)
.send(albums);
});
} catch (err) {
res.status(500)
.send({
error: err.message
});
}
});
app.get("/cached-album-info", function (req, res) {
try {
redis.get('albums', (err, data) => {
if (err) {
console.error(err);
throw err;
}
if (data) {
console.log('Albums retrieved from Redis/cache');
res.status(200)
.send(JSON.parse(data));
} else {
axios.get(`{API_URI}`)
.then(function (response) {
const albums = response.data;
redis.setex('albums', 600, JSON.stringify(albums));
console.log('Albums retrieved from the API');
res.status(200)
.send(albums);
});
}
});
} catch (err) {
res.status(500)
.send({
error: err.message
});
}
});
app.listen(8080, function () {
console.log("Server for project redis-intro live at port 8080 ");
});
Here we have defined two new routes, /album-info and /cached-album-info. Whenever a request is made to /album-info, it directly calls the external api and returns the results. When a request is made to /cached-album-info, it checks if key=”album” is present in Redis. If yes, then it returns a value against it; otherwise it first requests the external api caches in Redis HashSet and returns the result so that next time the cached value is available.
Let’s see the responses of both routes. Open Postman and create a get request at localhost:8080/album-info.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[
{
"userId": 1,
"id": 1,
"title": "quidem molestiae enim"
},
{
"userId": 1,
"id": 2,
"title": "sunt qui excepturi placeat culpa"
},
{
"userId": 1,
"id": 3,
"title": "omnis laborum odio"
},
:
:
:
:
so on
]
Response time for this request is 672ms.
Now make a request to localhost:8080/cached-album-info.
The first time the response will be the same as above, as in this case the server will call external api and then cache the request. The second time the response will be as fast as below.
Notice that 5ms response time is in cache. Otherwise it took 672 ms without cache. Caching drastically improves response time.
If you want a detailed interactive walkthrough, try https://try.redis.io/.
Happy caching!