Caching in C++: Redis, Memcached und integrierte Lösungen: von A bis Z

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Warum ist Caching in C++ notwendig?



In moderner, hochbelasteter Software ist die Geschwindigkeit des Datenzugriffs entscheidend. Ob es sich um einen Webserver handelt, der Millionen von Anfragen verarbeitet, oder um ein Hochfrequenz-Handelsterminal – jeder unnötige Datenbankzugriff oder Zugriff auf eine langsame Festplatte kann zum Engpass werden. Hier kommt Caching ins Spiel – eine Technik, bei der häufig angefragte Daten im schnellen Arbeitsspeicher (RAM) gespeichert werden, um später sofort darauf zugreifen zu können.



Die Programmiersprache C++ bietet dem Entwickler einzigartige Möglichkeiten zur Erstellung effizienter Caching-Systeme: von der feinen Speicherkontrolle bis hin zur Nutzung leistungsstarker externer Werkzeuge. In diesem Artikel gehen wir den Weg von einfachen integrierten Lösungen bis hin zu industriellen Systemen wie Redis und Memcached und analysieren, wann welcher Ansatz zu wählen ist.



Sie erfahren:

  • Wie man einen einfachen Cache in C++ ohne externe Bibliotheken implementiert.
  • Wie man Redis und Memcached einbindet und nutzt.
  • Einen Leistungsvergleich und die Anwendungsszenarien für jeden Ansatz.


Integrierte Lösungen: Eigener Cache in C++



Bevor wir externe Dienste einbinden, sollte man verstehen, dass für viele Aufgaben ein integrierter Cache ausreicht. Hauptvorteile: keine Netzwerklatenz, einfache Bereitstellung und vollständige Kontrolle über die Daten.



Einfachster Cache mit std::unordered_map

Die grundlegendste Variante ist die Verwendung einer assoziativen Liste. Sie hat jedoch keinen Mechanismus zur Datenverdrängung (Eviction Policy) und wird unbegrenzt wachsen, was zu Speicherüberlauf führen kann.



#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 ""; // oder eine Exception werfen }};


LRU-Cache (Least Recently Used)

Eine fortgeschrittenere Lösung ist der LRU-Cache, der die am wenigsten genutzten Elemente entfernt, sobald das Limit erreicht ist. Die Implementierung erfordert eine Kombination aus Hashtabelle und doppelt verketteter Liste.



#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(); }};


Ein solcher Cache ist ideal für die Arbeit in einem einzelnen Prozess, wenn die Daten nur zu diesem Prozess gehören und keine Synchronisierung erfordern.



Memcached: Verteilter Cache für einfache Daten



Memcached ist ein leichtgewichtiges, hochleistungsfähiges Caching-System, das über das TCP/UDP-Protokoll arbeitet. Es speichert Daten im RAM und unterstützt keine Persistenz. Eine ausgezeichnete Wahl zum Cachen von Ro

Blogs

Buchempfehlungen