Taslan Graham
Posted on January 12, 2021
Full post available here.
Speed performance is critical in modern-day applications. Most of the time your application may have to make requests to an endpoint/server to get some data. Or your application may frequently request a specific dataset.
Depending on the size of your dataset along with other things like query database and network speed, the speed at which your application can fetch certain data to display to users may get slower over time (as data increases).
This is where caching comes in handy and can dramatically improve your application's speed. In this tutorial we will look at how to implement redis caching in a node application (API) to improve the speed at which we are able to serve data to client apps. Let's dive in!
What is Caching
Before we dive into creating our own Redis cache, we have to first answer the question of what is caching?
In computing, a cache is a high-speed data storage layer which stores a subset of data, typically transient(existing for a short period of time) in nature, so that future requests for that data are served up faster than is possible by accessing the dataβs primary storage location. Caching allows you to efficiently reuse previously retrieved or computed data - https://aws.amazon.com/caching/
Here's a scenario to help you think about how caching works. Imagine you're watching your favorite sport (Soccer/Football for me ) or the news or a movie.
You're also a big fan of Potato chips, so you decide that every 15 minutes you'll go to the kitchen to get a little potato chips to eat.
You then noticed that going to the kitchen every 15 minutes is time consuming, not to mention the fact that you miss out a minute or two of what you're watching.
So instead of repeatedly making trips to the kitchen you decide fill a large bowl with chips and have it right next to you while watching the TV.
Now you can get your chips much faster and you don't need to go back to the kitchen unless your bowl is empty or you want a different kind or chips/snack . That bowl of chips is your cache.
In the world of IT, caching is similar. Data is stored somewhere (the bowl) where it can be accessed fast without having to go to the original source (the kitchen) unless the data needed is not inside the bowl.
What is Redis
Seeing that we will be using Redis to implement caching inside our node application it makes sense to first discuss what is Redis. Redis is an in memory key value pair database. Yes, you read that right, Redis stores data in memory (RAM).
Reading and writing to RAM is magnitudes faster than reading from a disk drive. This makes Redis perfect for caching.
Benefits of caching
- Redis cache uses RAM as its storage (more on this further down) which is faster than disk storage, reading from cache is extremely fast. Being able to read data at higher rates will significantly improve application performance.
- Caching frequently requested data will result in a reduction in the number of database queries needed retrieved particular data.
- Following up on the previous benefit, if we are making less database queries or even less network request to fetch external resources then our application will have lower latency.
- Your application can scale better since you can cache that is requested more frequently as more person uses your application.
Node App
Now that we understand what caching is and got an introduction to Redis we will create a node application that utilizes caching through Redis.
Our application will be a simple e-commerce API server that allows users to fetch a list products. Let's start coding!
- Create a folder name node-redis-cache (or whatever you like )
- open the folder inside your text editor(I use VScode)
We'll be using a few npm packages in our app:
- express - handle routing in our app
- redis - use redis commands in node
- axios - to make API calls
Open your terminal inside the project folder (node-redis-cache) and run the following command to install the needed packages:
npm install express redis axios
The command above installs the express, redis, and axios packages
Create Server
Now lets finally write some code. We'll first create our express server. Create a file name index.js.
Add the following imports to index.js
const express = require('express'); const app = express(); const axios = require('axios'); const PORT = 9000; const redis = require("redis"); const cacheClient= redis.createClient(); // redis client used to interact with redis database app.listen(PORT, () => console.log(`listening on port ${PORT}`));
We've created our server and set it to listen on port 9000. We've also required in the redis and axios packages which we'll use later on.
Route
Now we'll add a route that returns a list of products to the user. Add the following to index.js
app.get('/products', async (req, res) => { const { data } = await axios.get('https://fakestoreapi.com/products'); // This is a real API ;) return res.send(data); });
Here we've created a route handler for /products that will return a list of products. We are making a request to an external API to get these products.
Lets assume that this external API also makes a database request get this list of products. As you can see, when a user requests the list of available products it may take a while for them to get a response.
API Speed (without cache)
Let's test our endpoint using postman (or your favorite API testing tool). This will show us the speed performance of our application without caching.
Without caching implemented our API request takes 1540 milliseconds (or 1.54 seconds) to be processed. Now let's add caching to our route handler.
Adding caching
Update the /products route handler to the following.
app.get('/products', async (req, res) => { const TIME_TO_LIVE = 1800; // 30 minutes as seconds cacheClient.get("products", async (err, cachedProducts) => { if (cachedProducts) { res.send(JSON.parse(cachedProducts)); } else { const { data } = await axios.get('https://fakestoreapi.com/products'); cacheClient.setex("products", TIME_TO_LIVE, JSON.stringify(data)) return res.send(data); } }); });
Here, we are changing how our /products route handler operates. When we get a request to fetch for products, we first check to see if we already have that data available in cache.
If the cached data is available then we return that to the user. If there's no cached data available, we first make a call to the external API for the data. Then we cache the newly fetched data.
The setex() method allows us to set the Time To Live (TTL) for the cached data. This means that after the specified amount of time (in seconds) the cached data will be deleted. Finally we return the data to the user.
API Speed (with cache)
This will show us the speed performance of our application with caching implemented. Lets make a call to the API endpoint.
Whoa, wait, that's not much faster! Why is that so? On the first request, there's no data in the cache, so we'd have to the make a call to the external API which will take some time. The fetched data is then cached and is available on subsequent requests. So, let's make another request.
https://aws.amazon.com/caching/
https://www.cloudflare.com/learning/cdn/what-is-caching/
https://wp-rocket.me/blog/different-types-of-caching/
https://redis.io/documentation
https://www.npmjs.com/package/redis
If you found this helpful leave a comment below and share with devs who will find it useful. Until next time think, learn, create, repeat.
Posted on January 12, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.