Introduction: Why Caching Is Critical for C++ Performance
In modern high-load C++ development, caching is no longer an option — it is a mandatory architectural element. Without it, any CRUD system or microservice quickly hits database limits, and request latency grows exponentially. At an advanced level, we face a dilemma: use external systems (Redis, Memcached) or deploy a custom in-memory solution in C++? In this article, we will analyze the pros, cons, and specific implementations of each approach, based on practical experience with network queues, locks, and serialization.
1. Redis: Flexibility and Data Structures
Redis is not just a key-value store. Its main advantage is a rich set of data types: strings, hashes, lists, sets, sorted sets. For C++, there are several clients: redis-plus-plus (recommended) and hiredis (low-level).
Example of Connection and Basic Operations with redis-plus-plus
#include <sw/redis++/redis++.h>#include <iostream>
int main() { // Connect to Redis (default localhost:6379) sw::redis::Redis redis("tcp://127.0.0.1:6379");
// Set a value with a TTL of 60 seconds redis.set("user:1001", "John Doe", std::chrono::seconds(60));
// Read auto val = redis.get("user:1001"); if (val) { std::cout << "User: " << *val << std::endl; }
// Working with hashes redis.hset("session:abc", "token", "xyz123"); redis.hset("session:abc", "expires", "3600"); auto token = redis.hget("session:abc", "token"); std::cout << "Token: " << *token << std::endl;
return 0;}Advanced features: using transactions via redis.multi() and redis.exec(), as well as Pub/Sub for cache invalidation notifications. Redis is ideal when you need to store complex structures with atomic operations (e.g., counter increment).
2. Memcached: Speed and Simplicity
Memcached is a lightweight distributed cache optimized for storing flat data (strings and binary blobs). It does not support transactions or complex structures, but it wins in speed and minimal memory consumption. For C++, we use the libmemcached library.
Example of Working with Memcached via libmemcached
#include <libmemcached/memcached.h>#include <iostream>#include <cstring>
int main() { memcached_st *memc = memcached_create(nullptr); memcached_server_st *servers = nullptr; memcached_return_t rc;
// Add a server servers = memcached_server_list_append(servers, "127.0.0.1", 11211, &rc); rc = memcached_server_push(memc, servers); if (rc != MEMCACHED_SUCCESS) { std::cerr << "Error: " << memcached_strerror(memc, rc) << std::endl; return 1; }
// Write with a TTL of 30 seconds const char *key = "config:db_host"; const char *value = "10.0.0.1"; rc = memcached_set(memc, key, strlen(key), value, strlen(value), std::time(0) + 30, (uint32_t)0); if (rc != MEMCACHED_SUCCESS) { std::cerr << "Set failed: " << memcached_strerror(memc, rc) << std::endl; }
// Read size_t val_len; uint32_t flags; char *retrieved = memcached_get(memc, key, strlen(key), &val_len, &flags, &rc); if (rc == MEMCACHED_SUCCESS) { std::cout << "DB Host: " << retrieved << std::endl; free(retrieved); }
memcached_free(memc); return 0;}When to choose Memcached? If you need a simple cache for serialized objects, without the need to store complex structures. Memcached is ideal for caching SQL query results or HTML fra