Introduction
Redis is a powerful in-memory data structure store used for caching, message brokering, and real-time analytics. It significantly improves performance by reducing database queries and delivering faster responses.
CampusX, my MERN stack-based social platform, leverages Redis for caching frequently accessed data like bookmarks and posts. This blog explains how Redis is integrated into CampusX for efficient data retrieval and enhanced user experience.
Why Redis for Caching?
Caching reduces redundant database queries by storing frequently accessed data in memory. This is crucial for high-traffic applications where querying the database every time would introduce latency.
Key Benefits of Redis:
- Blazing Fast Reads 🚀: Being an in-memory store, Redis serves cached data almost instantly.
- Reduced Load on Database: Offloads frequent queries from the primary database.
- Supports Expiration ⏳: Caches can have TTL (Time-To-Live) to prevent outdated data.
- Key-Value Storage 🔑: Simple yet powerful data access.
- Scalability: Handles thousands of requests per second.
Setting Up Redis in CampusX
Installing Redis
First, install Redis on the server:
sudo apt update
sudo apt install redis-server
Then start Redis:
sudo systemctl start redis
sudo systemctl enable redis
Install the Redis client in the Node.js backend:
npm install ioredis
Connecting Redis in CampusX
import Redis from 'ioredis';
const redis = new Redis(); // Default localhost connection
Caching Post Data
Problem:
Fetching a post by ID every time increases database load.
Solution:
Cache post data in Redis for quick retrieval.
Implementation:
// Get Single Post by ID with Aggregation
const getPostById = AsyncHandler(async (req, res) => {
const postId = req.params.id;
const cachedPost = await client.get(`post:${postId}`);
//check for the cached post.
if (cachedPost) {
return res.json(
new ApiResponse(
STATUS_CODES.OK,
JSON.parse(cachedPost),
"Post from Redis cache"
)
);
}
//Database Call
const post = await Post.aggregate([
{ $match: { _id: new mongoose.Types.ObjectId(postId) } },
{
$lookup: {
from: "users",
localField: "author",
foreignField: "_id",
as: "authorDetails",
},
},
{ $unwind: "$authorDetails" },
{
$lookup: {
from: "comments",
localField: "_id",
foreignField: "post",
as: "comments",
},
},
{
$lookup: {
from: "subscriptions",
localField: "author",
foreignField: "channel",
as: "followers",
},
},
{
$addFields: {
likeCount: { $size: "$likes" },
commentCount: { $size: "$comments" },
followerCount: { $size: "$followers" },
},
},
]);
if (!post.length)
throw new ApiError(STATUS_CODES.NOT_FOUND, "Post not found");
//cache the post to redis
try {
await client.setEx(`post:${postId}`, 3600, JSON.stringify(post[0]));
} catch (err) {
console.error("Redis caching error:", err);
}
res
.status(STATUS_CODES.OK)
.json(
new ApiResponse(STATUS_CODES.OK, post[0], "Post fetched successfully")
);
});
};
How It Works:
- Check Redis: If post exists in cache, return it instantly.
- Query MongoDB: If not found in Redis, fetch from the database.
- Cache the Post: Save in Redis for subsequent requests.
- Set Expiry: Automatically remove old data after 10 minutes.
Caching User Bookmarks
Problem:
Fetching user bookmarks on every request leads to unnecessary DB hits.
Solution:
Cache user bookmarks in Redis and update only when changes occur.
Implementation:
// Get User's Bookmarked Posts
const getUserBookmarks = AsyncHandler(async (req, res) => {
const userId = req.user._id;
const user = await User.findById(userId);
//chech if the bookmarks are cached
const cachedBookmarks = await client.get(`bookmarks:${userId}`);
console.log("cachedBookmarks", cachedBookmarks);
if (cachedBookmarks) {
return res.json(
new ApiResponse(
STATUS_CODES.OK,
JSON.parse(cachedBookmarks),
"bookmarks from Redis cache"
)
);
}
//Database Call
const bookmarks = await Bookmark.find({ _id: { $in: user.bookmarks } })
.populate("post", "content image category likesCount")
.populate("post_owner", "fullName userName avatar");
console.log("bookmarks", bookmarks);
//cache the user bookmarks
try {
await client.setEx(`bookmarks:${userId}`, 3600, JSON.stringify(bookmarks));
console.log("bookmarks cached");
} catch (err) {
console.error("Redis caching error:", err);
}
res
.status(STATUS_CODES.OK)
.json(
new ApiResponse(STATUS_CODES.OK, bookmarks, "Bookmarked posts fetched")
);
});
Ensuring Cache Consistency in CampusX with Redis
🔹 The Problem: Stale Cache
When users update their bookmarks, the cached data can become outdated. Instead of serving old data, CampusX ensures cache consistency by deleting the cache entry whenever a change occurs.
🛠️ How It Works
1️⃣ Check Cache: Before querying the database, Redis is checked for cached data.
2️⃣ Serve Cached Data: If available, the cached data is returned instantly.
3️⃣ Delete Cache on Update: When a bookmark is added or removed, the cache entry is deleted.
4️⃣ Fetch Fresh Data: The next request pulls updated data from the database and caches it again.
💡 Implementation
🗑️ Deleting Cache on Update
//remove the boomarks from the cache
await client.del(`bookmarks:${req.user._id}`);
console.log("🗑️ Cache cleared for user's bookmarks");
🚀 Why Delete Instead of Updating?
✔ Ensures fresh data – Users always get the latest updates.
✔ Simplifies cache management – No need to track and modify cache manually.
✔ Prevents stale data issues – Avoids serving outdated information.
By using this delete-and-reload approach, CampusX keeps Redis cache up-to-date efficiently! 🚀🔥
Redis Performance Tips
- Set Expiry Times ⏲️: Prevents stale cache from growing indefinitely.
-
Use Proper Key Naming 🏷️: Consistent prefixes (
post:ID
,bookmarks:USER_ID
) avoid conflicts. - Cache Only Essential Data 🎯: Don’t over-cache; focus on frequently accessed data.
- Use Redis Pub/Sub for Real-time Updates 🔄: Sync cache with DB changes.
Conclusion
Integrating Redis in CampusX significantly improved performance by caching frequently accessed data like posts and bookmarks. This reduced database load and provided a seamless experience for users.
Caching is essential for optimizing applications, and Redis makes it incredibly easy and efficient. Whether you're handling high traffic, real-time updates, or just want faster data access, Redis is a game-changer.
🔹 Try implementing Redis caching in your projects and experience the performance boost! 🚀