Hello, my friend and welcome to this short tutorial on using Redis as a cache system in your next project.
What Is Redis?
So what is Redis, and why go through the hassle of learning this technology? I guess that's the question you've been asking yourself lately, you see it everywhere and you feel like you're missing out. Yes! you are missing out in terms of performance and speed optimization. However, this is just the tip of the iceberg of what Redis can provide but it's a good starting point to get your feet wet and remember Rome was not built in a single day. That said buckle up and explore this together.
Redis is an in-memory data structure store, used as a distributed, in-memory key-value database, cache, and message broker, with optional durability. Wow, I know that is too much to take in, let me help you digest this slowly. Basically what Redis does is act like a database that store values in JSON format using key values like an object, and provides caching capability, with messaging broker capabilities like Kafka or RabitMQ in a microservice architecture. However, our focus, for now, is caching.
Explaining the caching capabilities would do you less justice, but showing you would make you understand better with a vivid analogy of a water piping system of a house.
Imagine a plumber designing a water system for a house and wishes that it takes a shorter time for water to reach the house from the utility company. How do you think he would design this, given that the water utility company is 1000 meters away from the house? I know you are no plumber, but this is something we see every day. Well, he has two options!
The first is to send the pipelines straight to the water utility company from the house.
Secondly, is to implement a water tank storage in the house where water is first served from the water utility company before being sent to the house.
Hmmmmm, so which do you think is efficient? The second option. This is because each time any tap is open in the house, the tank is first to respond with any drop of water before the water utility company. Thus each time water is available in the tank it would take a shorter time for water to be available in this house. In contrast with the first option, each time any tap is open the water utility company has to first respond by supplying water before the house gets water. Thus we can all agree that it would take a longer time with the first option. This may be an oversimplified explanation because obviously water supply does not function like this, but this drives home the point. Thus the water tank in this case is the cache system and in our case Redis.
This is how Redis cache functions in your application, thereby enabling fewer requests to your Database and delivering faster response time to any query. The diagram below illustrates the analogy of the Water tank and utility company explained in the previous paragraph.
First Case without Redis
In this case, all requests are made directly to the server without any caching mechanism here. This takes a lot of time and the response are significantly slower.
Second Case with Redis
In this case, we can see that Redis is implemented, thereby serving the purpose of the water tank in the analogy of the water piping scenario. Thus, we can observe a faster response time and fewer computational resources to query the database. This is because all queries are made to the Redis Cache which has a faster response time and in the case where this data is not available in the Redis cache for the first query. Then the data is fetched from the Database directly and then stored in the Redis Cache for subsequent requests with lower response timing.
Alright my friends it's time to leave the world of theory and story learning to get our hands dirty. Let's code this into existence. I'll leave a copy of the repo below so you can clone it and experiment with it.
We would first need to download Redis stable version depending on your operating system. Check the link below and select a stable version for your OS. https://redis.io/download/
For Mac users like myself if you have Homebrew installed then just run this command brew install Redis, and check out this link for reference:https://redis.io/docs/getting-started/installation/install-redis-on-mac-os/
Let's open our first code and go to the terminal.
Change the directory to the desired location by typing cd Desktop/desired_folder.
Type the following into the Terminal to initialize our nodeJs app and install dependencies. We'll be using Express to spinoff our node server, nodemon to watch for changes in our code, redis for our cache and dotenv to store our environment variables such as our PORT number, and Axios to make API queries.
npm init -y
npm i express nodemon redis dotenv axios
We would need to make some adjustments to our package.json file in the root of directory, inorder to ease our development process. Add the following line in the first key value pairs of our package.json file "type": "module". This is to enable us use name import rather than required('') syntax of node. In the scripts object found in the package.json file add the following line "start": "nodemon index.js", this would enable us to avoid restarting node.
For Simplicity, we shall not be using a real database like MongoDB but rather an API endpoint with JSON data, such as the JSON placeholder API endpoint.
Let's instantiate our server
import express from "express";
import dotenv from "dotenv";
dotenv.config();//access enviroment variables
const app = express();
app.use(express.json());//express middleware for JSON data
const PORT = process.env.PORT || 5008;
app.listen(PORT, () => {
console.log(`Listening to ${PORT}`);
});
Run npm start in the terminal and you'll get the following
[nodemon] starting
node index.js
Listening to 5008
let's start our Redis client and make a post request
import { createClient } from "redis";
const client = createClient();
client.on("error", (err) => console.log("Redis Client Error", err));
await client.connect();
app.post("/", async (req, res) => {
const { key, value } = req.body;
const response = await client.set(key, value);
const output = await client.get(key);
res.json(output);
});
Please check this link with the Redis documentation out in order to set up Redis properly:https://www.npmjs.com/package/redis
To make a request to this route we would use PostMan.
I assume you know how to use Postman, if not please check this link from FreeCodeCamp on how to make a request with Postman: https://www.youtube.com/watch?v=VywxIQ2ZXw4
This is the response we get from requests using PostMan.
Let's get a simulation of what it would be like using a Database by using the JSON placeholder API end point.
import axios from "axios";
app.get("/posts/:id", async (req, res) => {
const { id } = req.params;
const cachedPost = await client.get(`post-${id}`);
if (cachedPost){return res.json(JSON.parse(cachedPost));}
const response = await axios.get(
`https://jsonplaceholder.typicode.com/posts/${id}`
);
client.set(`post-${id}`, JSON.stringify(response.data))
res.json(response.data);
});
Let's make a get request to the JSON placeholder API endpoint(https://jsonplaceholder.typicode.com/posts) for post 24. We would compare the response the first time when the response is not cached, and the 2nd, 3rd, and 4th time when the response is cached.
The first request was without any cached data in Redis. We observe a response time of 1259 milliseconds.
The second request has a faster response time of 19 milliseconds, what a significant change. This even decreases for the 3rd and 4th response time, with an average response time of 12 milliseconds.
Below is the full code base.
import express from "express";
import dotenv from "dotenv";
import { createClient } from "redis";
import axios from "axios";
dotenv.config();
const app = express();
app.use(express.json());
const client = createClient();
client.on("error", (err) => console.log("Redis Client Error", err));
await client.connect();
const PORT = process.env.PORT || 500;
app.post("/", async (req, res) => {
const { key, value } = req.body;
const response = await client.set(key, value);
const output = await client.get(key);
res.json(output);
});
app.get("/posts/:id", async (req, res) => {
const { id } = req.params;
const cachedPost = await client.get(`post-${id}`);
if (cachedPost){return res.json(JSON.parse(cachedPost));}
const response = await axios.get(
`https://jsonplaceholder.typicode.com/posts/${id}`
);
client.set(`post-${id}`, JSON.stringify(response.data))
res.json(response.data);
});
app.listen(PORT, () => {
console.log(`Listening to ${PORT}`);
});
Note: Stringify the data when setting and getting the data in Redis.
Github repo: https://github.com/amaboh/Redis_hat
I hope you found this tutorial and explanation helpful. Happy keystroking!
Top comments (0)