Кэширование в C++: Redis, Memcached и встроенные решения: от А до Я

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: Зачем нужно кэширование в C++?

В современном высоконагруженном программном обеспечении скорость доступа к данным критична. Будь то веб-сервер, обрабатывающий миллионы запросов, или высокочастотный торговый терминал — каждое лишнее обращение к базе данных или медленному диску может стать узким местом. Именно здесь на помощь приходит кэширование — техника хранения часто запрашиваемых данных в быстродействующей памяти (RAM) для последующего мгновенного доступа.

Язык C++ предоставляет разработчику уникальные возможности для построения эффективных систем кэширования: от тонкого контроля над памятью до использования мощных внешних инструментов. В этой статье мы пройдём путь от простых встроенных решений до промышленных систем, таких как Redis и Memcached, и разберём, когда и какой подход выбрать.

Вы узнаете:

  • Как реализовать простой кэш в C++ без сторонних библиотек.
  • Как подключить и использовать Redis и Memcached.
  • Сравнение производительности и сценариев применения каждого подхода.

Встроенные решения: Свой кэш на C++

Прежде чем подключать внешние сервисы, стоит понять, что для многих задач достаточно встроенного кэша. Основные преимущества: нулевая задержка сети, простота развертывания и полный контроль над данными.

Простейший кэш на std::unordered_map

Самый базовый вариант — использовать ассоциативный массив. Однако он не имеет механизма вытеснения данных (eviction policy) и будет бесконечно расти, что может привести к переполнению памяти.

#include <unordered_map>
#include <string>

class SimpleCache {
    std::unordered_map<std::string, std::string> cache_;
public:
    void put(const std::string& key, const std::string& value) {
        cache_[key] = value;
    }
    std::string get(const std::string& key) {
        auto it = cache_.find(key);
        if (it != cache_.end()) {
            return it->second;
        }
        return ""; // или выбросить исключение
    }
};

LRU-кэш (Least Recently Used)

Более продвинутое решение — LRU-кэш, который удаляет наименее используемые элементы при достижении лимита. Реализация требует комбинации хеш-таблицы и двусвязного списка.

#include <list>
#include <unordered_map>

template<typename K, typename V>
class LRUCache {
    size_t capacity_;
    std::list<std::pair<K, V>> items_;
    std::unordered_map<K, typename std::list<std::pair<K, V>>::iterator> cache_;

public:
    LRUCache(size_t cap) : capacity_(cap) {}

    V get(const K& key) {
        auto it = cache_.find(key);
        if (it == cache_.end()) {
            throw std::runtime_error("Key not found");
        }
        items_.splice(items_.begin(), items_, it->second);
        return it->second->second;
    }

    void put(const K& key, const V& value) {
        auto it = cache_.find(key);
        if (it != cache_.end()) {
            it->second->second = value;
            items_.splice(items_.begin(), items_, it->second);
            return;
        }
        if (items_.size() == capacity_) {
            auto last = items_.back();
            cache_.erase(last.first);
            items_.pop_back();
        }
        items_.emplace_front(key, value);
        cache_[key] = items_.begin();
    }
};

Такой кэш идеально подходит для работы в одном процессе, когда данные принадлежат только этому процессу и не требуют синхронизации.

Memcached: Распределённый кэш для простых данных

Memcached — это легковесная, высокопроизводительная система кэширования, работающая по протоколу TCP/UDP. Она хранит данные в оперативной памяти и не поддерживает постоянство (persistence). Отличный выбор для кэширования результатов запросов к БД, сессий пользователей и HTML-фрагментов.

Подключение и работа с libmemcached

Для работы с Memcached из C++ используется библиотека libmemcached. Установите её через пакетный менеджер:

sudo apt-get install libmemcached-dev  # Ubuntu/Debian

Пример простого клиента:

#include <libmemcached/memcached.h>
#include <iostream>
#include <string>

int main() {
    memcached_server_st *servers = NULL;
    memcached_st *memc = memcached_create(NULL);

    servers = memcached_server_list_append(servers, "127.0.0.1", 11211, &rc);
    memcached_server_push(memc, servers);
    memcached_server_list_free(servers);

    // Установка значения
    const char *key = "user:123";
    const char *value = "John Doe";
    memcached_return_t rc = memcached_set(memc, key, strlen(key), value, strlen(value), 3600, 0);
    if (rc == MEMCACHED_SUCCESS) {
        std::cout << "Value cached successfully" << std::endl;
    }

    // Получение значения
    size_t value_length;
    uint32_t flags;
    char *retrieved = memcached_get(memc, key, strlen(key), &value_length, &flags, &rc);
    if (rc == MEMCACHED_SUCCESS) {
        std::cout << "Retrieved: " << retrieved << std::endl;
        free(retrieved);
    }

    memcached_free(memc);
    return 0;
}

Плюсы Memcached:

  • Простота и молниеносная скорость (чистая работа с памятью).
  • Легко масштабируется горизонтально (добавление новых серверов).
  • Низкое потребление CPU.

Минусы:

  • Нет репликации и постоянства данных (при перезагрузке всё теряется).
  • Ограниченный набор типов данных (только строки и байты).

Redis: Мощный швейцарский нож кэширования

Redis — это не просто кэш, а полноценное хранилище данных в памяти, поддерживающее структуры (списки, хеши, множества), транзакции, публикацию/подписку и постоянство на диске. Для C++ существует

Блоги

Рекомендаций по книгам