Wednesday, April 3, 2019

How to Build Apps Faster using Redis Cache in Node.js


NodeJs core is the speed with respect to execution of async tasks, however there are ways to improve the response time further by using Redis Cache. I would try to get into concept of Caching and approach to implementation.

Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker. It supports strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes with radius queries and streams. Redis has built-in replication, Lua scripting, LRU eviction, transactions and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster.

What is Caching?

Caching is the process of storing data in a temporary data store where data is kept for later use. This temporary data store is called Cache.

A cache as a data store is easier for the client (or server) to reach, as opposed to a permanent data store that might be located on a different service, which takes more time and resources to reach (a database or an external API endpoint).

First step in application optimization is implementation of caching. Caching involves storing data in a high performance store (many times temporarily) so such data can be retrieved faster at a later time. Redis is an efficient key-value data store that has become a preferred choice for caching. Redis holds edge over other options because of the number of data structures it supports — such as strings, hashes, lists, sets, and so on. This provides lot of flexibility! 

Plumbing Node.JS and Redis

Let’s first install the Redis to understand the impact of using it as an in-memory data structure for caching on a node server. On InstallationRedis server is started, it runs on default port 6379.

Here, we will fetch the country codes from the existing application that seldom changes and cache them on the node server. To use Redis for caching, we will need Redis module (Redis client) in the Node.JS application that will help in connecting with the Redis server.

The Redis client would help in storing and obtaining the data from the Redis cache.

When the data request is made by the Node.JS app, the products API before moving to the Node server to obtain the data, at first check the data in the Redis. In case, the data is available in the Redis, then it’s fetched from the memory and sent as a response to the request. Otherwise, products API move to the “some_other_domain” to fetch the data and from where the response is firstly cached in the Redis and then send as a response to the request.
This way the response time get drastically reduced.


In Node.JS app, when 1000 records are fetched from the legacy application, it took 8 seconds.

When the requested data is cached on Redis and again requested, the response time reduced to 50 milliseconds.

Furthermore, if database result sets are cached in Redis, then APIs performance would also increase. The cache can be automatically cleared by setting its expiration time with the ‘setex’ method.

Epilogue

Leveraging the power Redis, the Node.JS applications can create a major breakthrough for enterprises. The strong caching layer of Redis is making the apps respond quickly.


Aforementioned instance elaborated the impact of Redis on Node.JS app that needs no explanation.

Although Redis has a memory limit where the data equivalent to the drive capacity can be stored. Also, Redis is worth to use when access to loads of data is barely needed, but in case, frequent access is needed, then it proves to be quite expensive.

Redis is a magic bullet that must be used with Node.JS app strategically depending upon the type of data and access you need.

Example:
We will make a comparison of 2 pieces of code from Node.js. The following is when we try to retrieve data from the Google Book API, without put Redis on the endpoint.

Node.Js without Redis :

  1. ‘usestrict';
  2. //Define all dependencies needed
  3. constexpress=require('express');
  4. constresponseTime=require('response-time')
  5. constaxios=require('axios');
  6. //Load Express Framework
  7. var app =express();
  8. //Create a middleware that adds a X-Response-Time header to responses.
  9. app.use(responseTime());
  10. constgetBook= (req, res) => {
  11. letisbn=req.query.isbn;
  12. leturl=`https://www.googleapis.com/books/v1/volumes?q=isbn:${isbn}`;
  13. axios.get(url)
  14.     .then(response=> {
  15. let book =response.data.items
  16. res.send(book);
  17.     })
  18.     .catch(err=> {
  19. res.send('The book you are looking for is not found !!!');
  20.     });
  21. };
  22. app.get('/book', getBook);
  23. app.listen(3000, function() {
  24. console.log('Your node is running on port 3000 !!!')
  25. });

Node.Js with Redis :

  1. 'use strict';
  2. //Define all dependencies needed
  3. constexpress=require('express');
  4. constresponseTime=require('response-time')
  5. constaxios=require('axios');
  6. constRedis=require('Redis');
  7. constclient=Redis.createClient();
  8. //Load Express Framework
  9. var app =express();
  10. //Create a middleware that adds a X-Response-Time header to responses.
  11. app.use(responseTime());
  12. constgetBook= (req, res) => {
  13. letisbn=req.query.isbn;
  14. leturl=`https://www.googleapis.com/books/v1/volumes?q=isbn:${isbn}`;
  15. returnaxios.get(url)
  16.     .then(response=> {
  17. let book =response.data.items;
  18. // Set the string-key:isbn in our cache. With he contents of the cache : title
  19. // Set cache expiration to 1 hour (60 minutes)
  20. client.setex(isbn, 3600, JSON.stringify(book));
  21. res.send(book);
  22.     })
  23.     .catch(err=> {
  24. res.send('The book you are looking for is not found !!!');
  25.     });
  26. };
  27. constgetCache= (req, res) => {
  28. letisbn=req.query.isbn;
  29. //Check the cache data from the server Redis
  30. client.get(isbn, (err, result) => {
  31. if (result) {
  32. res.send(result);
  33.     } else {
  34. getBook(req, res);
  35.     }
  36.   });
  37. }
  38. app.get('/book', getCache);
  39. app.listen(3000, function() {
  40. console.log('Your node is running on port 3000 !!!')
  41. });


You can see, the above code explains that Redis will store the cache data of with unique key value that we have specified, using this function:

client.setex (isbn, 3600, JSON.stringify(book));

And take the cache data using the function below:

client.get(isbn, (err, result) => {
     if (result) {
res.send (result);
     } else {
getBook (req, res);
     }
   });
This is the result of testing of both codes. If we don’t use Redis as cache, it takes at least 908.545 ms



Very different, when node js use Redis. Look at this, it is very fast, it only takes 0.621 ms to retrieve data at the same endpoint



Conclusion:

I know there are still many ways to improve and speed up performance on Node.js and only one way above, I think not enough to make your Node.js run perfectly. Please let me know another way, by filling in the comments.