Redis is more than a cache; it's a multi-tool for building high-performance systems. Discover how qb
's asynchronous qbm-redis
client makes it easy to leverage Redis for caching, message queuing, and real-time Pub/Sub in your C++ applications.
Target Audience: Intermediate to Advanced C++ developers building systems that require caching, job queues, or real-time messaging.
GitHub: https://github.com/isndev/qbm-redis
In modern distributed systems, performance and scalability often depend on fast access to data and efficient communication between components. Redis, the in-memory data structure store, is the industry standard for solving these problems.
The qbm-redis
module brings the full power of Redis to the qb
actor framework with a clean, asynchronous, and type-safe C++ client. It allows your actors to interact with Redis without ever blocking, enabling you to build incredibly responsive and scalable systems.
Let's explore three common patterns where qbm-redis
shines.
1. High-Performance Caching
The most common use for Redis is as a distributed cache to reduce database load and speed up response times. qbm-redis
makes this trivial.
The pattern is simple: before making an expensive database call or computation, check the cache.
// In a qb::Actor that needs to fetch user data...
#include <redis/redis.h>
class UserDataService : public qb::Actor {
private:
qb::redis::tcp::client _redis{"tcp://localhost:6379"};
// ... database connection member ...
public:
bool onInit() override {
if (!_redis.connect()) {
qb::io::cerr() << "Failed to connect to Redis" << std::endl;
return false;
}
// ...
return true;
}
void handle_user_request(int user_id) {
std::string cache_key = "user:" + std::to_string(user_id);
// 1. Check the cache first (using async call with callback)
_redis.get(cache_key, [this, user_id, cache_key](auto&& reply) {
if (reply.ok() && reply.result().has_value()) {
// Cache hit! Use the cached data.
qb::io::cout() << "Cache HIT for user " << user_id << std::endl;
std::string user_json = *reply.result();
// ... process user_json and send response ...
return;
}
// 2. Cache miss. Fetch from the database (this would be another async call).
qb::io::cout() << "Cache MISS for user " << user_id << ". Fetching from DB." << std::endl;
std::string data_from_db = "{\"id\": " + std::to_string(user_id) + ", \"name\": \"Alice\"}";
// 3. Store the result in the cache for next time with an expiration.
// SETEX sets a key with a Time-To-Live (TTL).
_redis.setex(cache_key, 300, data_from_db); // Cache for 5 minutes
// ... process data_from_db and send response ...
});
}
};
This simple pattern can dramatically improve your application's performance by offloading work from your primary database.
2. Reliable Job Queues with Lists
How do you distribute work among a pool of worker actors? A Redis List is a perfect tool for a reliable job queue. Producers LPUSH
jobs onto one end of the list, and workers use BRPOP
(blocking list pop) to atomically pull jobs from the other end.
BRPOP
is a blocking command, but when used with qbm-redis
in a qb
actor, it's non-blocking from the framework's perspective. The actor remains responsive to other events while waiting for a job.
Based on examples/qbm/redis/example3_list_operations.cpp
// In a WorkerActor...
#include <redis/redis.h>
class WorkerActor : public qb::Actor, public qb::ICallback {
private:
qb::redis::tcp::client _redis{"tcp://localhost:6379"};
const std::string _queue_key = "jobs:image_processing";
public:
bool onInit() override {
_redis.connect();
registerCallback(*this); // Periodically check for jobs
return true;
}
// Periodically check for a new job
void onCallback() override {
// Use BRPOP with a timeout of 1 second.
// The callback-based version is ideal here.
_redis.brpop({_queue_key}, 1, [this](auto&& reply) {
if (reply.ok() && reply.result().has_value()) {
// Job received! The result is a pair of {key, value}
auto& job_data = reply.result()->second;
qb::io::cout() << "Worker " << id() << " processing job: " << job_data << std::endl;
// ... do the actual work ...
} else {
// No job received in the last second.
qb::io::cout() << "Worker " << id() << ": No jobs in queue." << std::endl;
}
});
}
};
// In a ProducerActor...
void submit_job(const std::string& job_data) {
// LPUSH pushes to the head of the list.
_redis.lpush("jobs:image_processing", job_data);
}
3. Real-Time Messaging with Publish/Subscribe
For broadcasting real-time events, Redis Pub/Sub is a powerful and simple solution. Publishers send messages to a "channel" without knowing who, if anyone, is listening. Subscribers express interest in one or more channels and receive messages as they are published.
qbm-redis
provides a specialized cb_consumer
client for handling subscriptions efficiently.
Based on examples/qbm/redis/example5_pubsub_example.cpp
#include <redis/redis.h>
// 1. The Subscriber Actor
class SubscriberActor : public qb::Actor {
private:
// The cb_consumer takes a callback in its constructor for handling messages.
qb::redis::tcp::cb_consumer _consumer{"tcp://localhost:6379",
[this](auto&& msg) {
// This lambda is called by the consumer when a message arrives
qb::io::cout() << "Subscriber " << id() << " received on '"
<< msg.channel << "': " << msg.message << std::endl;
}
};
public:
bool onInit() override {
_consumer.connect();
// Subscribe to a channel
_consumer.subscribe("app:notifications");
return true;
}
};
// 2. The Publisher Actor
class PublisherActor : public qb::Actor {
private:
qb::redis::tcp::client _redis{"tcp://localhost:6379"};
public:
bool onInit() override {
_redis.connect();
return true;
}
void send_notification(const std::string& message) {
// Publish a message to the channel
long subscribers_count = _redis.publish("app:notifications", message);
qb::io::cout() << "Published notification to " << subscribers_count
<< " subscribers." << std::endl;
}
};
This pattern is perfect for building real-time dashboards, chat systems, or any application where components need to react instantly to events happening elsewhere in the system.
With qbm-redis
, you can easily integrate these powerful Redis patterns into your high-performance C++ actor system, building applications that are fast, scalable, and resilient.
Explore the qbm-redis
module on GitHub:
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.