Bevor Sie fortfahren, denken Sie bitte darüber nach, uns einen GitHub-Stern zu geben ️. Danke schön!
Andere Sprachen: 简体中文 日本語 한국어
Website • Dokumente • Schnellstart • Community Discord • Dragonfly-Forum • Treten Sie der Dragonfly-Community bei
GitHub-Diskussionen • GitHub-Probleme • Mitwirken • Dragonfly Cloud
Dragonfly ist ein In-Memory-Datenspeicher, der für moderne Anwendungs-Workloads entwickelt wurde.
Dragonfly ist vollständig kompatibel mit Redis- und Memcached-APIs und erfordert keine Codeänderungen zur Übernahme. Im Vergleich zu älteren In-Memory-Datenspeichern bietet Dragonfly einen 25-mal höheren Durchsatz, höhere Cache-Trefferraten bei geringerer Tail-Latenz und kann bei gleicher Arbeitslast mit bis zu 80 % weniger Ressourcen betrieben werden.
Wir vergleichen zunächst Dragonfly mit Redis auf m5.large
-Instanz, die aufgrund ihrer Single-Thread-Architektur häufig zum Ausführen von Redis verwendet wird. Das Benchmark-Programm wird von einer anderen Lasttestinstanz (c5n) in derselben AZ mit memtier_benchmark -c 20 --test-time 100 -t 4 -d 256 --distinct-client-seed
ausgeführt
Dragonfly zeigt eine vergleichbare Leistung:
--ratio 1:0
):Redis | DF |
---|---|
QPS: 159K, P99.9: 1,16 ms, P99: 0,82 ms | QPS: 173K, P99.9: 1,26 ms, P99: 0,9 ms |
--ratio 0:1
):Redis | DF |
---|---|
QPS: 194K, P99.9: 0,8 ms, P99: 0,65 ms | QPS: 191K, P99.9: 0,95 ms, P99: 0,8 ms |
Der obige Benchmark zeigt, dass die algorithmische Ebene innerhalb von DF, die eine vertikale Skalierung ermöglicht, beim Single-Threaded-Betrieb keinen großen Tribut fordert.
Wenn wir jedoch eine etwas stärkere Instanz (m5.xlarge) nehmen, beginnt die Kluft zwischen DF und Redis zu wachsen. ( memtier_benchmark -c 20 --test-time 100 -t 6 -d 256 --distinct-client-seed
):
--ratio 1:0
):Redis | DF |
---|---|
QPS: 190K, P99.9: 2,45 ms, P99: 0,97 ms | QPS: 279K, P99.9: 1,95 ms, P99: 1,48 ms |
--ratio 0:1
):Redis | DF |
---|---|
QPS: 220K, P99.9: 0,98 ms, P99: 0,8 ms | QPS: 305K, P99.9: 1,03 ms, P99: 0,87 ms |
Die Durchsatzkapazität von Dragonfly wächst mit der Instanzgröße weiter, während Single-Threaded-Redis einen CPU-Engpass hat und lokale Leistungsmaxima erreicht.
Wenn wir Dragonfly und Redis auf der netzwerkfähigsten Instanz c6gn.16xlarge vergleichen, zeigte Dragonfly eine 25-fache Steigerung des Durchsatzes im Vergleich zum Redis-Einzelprozess und überschritt 3,8 Mio. QPS.
Die 99. Perzentil-Latenzmetriken von Dragonfly bei Spitzendurchsatz:
op | r6g | c6gn | c7g |
---|---|---|---|
Satz | 0,8 ms | 1ms | 1ms |
erhalten | 0,9 ms | 0,9 ms | 0,8 ms |
setex | 0,9 ms | 1,1 ms | 1,3 ms |
Alle Benchmarks wurden mit memtier_benchmark
(siehe unten) durchgeführt, wobei die Anzahl der Threads pro Server und Instanztyp optimiert wurde. memtier
wurde auf einer separaten c6gn.16xlarge-Maschine ausgeführt. Wir haben die Ablaufzeit für den SETEX-Benchmark auf 500 festgelegt, um sicherzustellen, dass er das Ende des Tests übersteht.
memtier_benchmark --ratio ... -t < threads > -c 30 -n 200000 --distinct-client-seed -d 256
--expiry-range=...
Im Pipeline-Modus --pipeline=30
erreicht Dragonfly 10 Mio. QPS für SET- und 15 Mio. QPS für GET-Vorgänge.
Wir haben Dragonfly mit Memcached auf einer c6gn.16xlarge-Instanz auf AWS verglichen.
Bei vergleichbarer Latenz übertraf der Dragonfly-Durchsatz den Memcached-Durchsatz sowohl bei Schreib- als auch bei Lese-Workloads. Dragonfly zeigte eine bessere Latenz bei Schreib-Workloads aufgrund von Konflikten um den Schreibpfad in Memcached.
Server | QPS (Tausende qps) | Latenz 99 % | 99,9 % |
---|---|---|---|
Libelle | ? 3844 | ? 0,9 ms | ? 2,4 ms |
Im Speicher gespeichert | 806 | 1,6 ms | 3,2 ms |
Server | QPS (Tausende qps) | Latenz 99 % | 99,9 % |
---|---|---|---|
Libelle | ? 3717 | 1ms | 2,4 ms |
Im Speicher gespeichert | 2100 | ? 0,34 ms | ? 0,6 ms |
Memcached zeigte beim Lese-Benchmark eine geringere Latenz, aber auch einen geringeren Durchsatz.
Um die Speichereffizienz zu testen, haben wir Dragonfly und Redis mithilfe des Befehls debug populate 5000000 key 1024
mit ca. 5 GB Daten gefüllt, Aktualisierungsdatenverkehr mit memtier
gesendet und die Snapshot-Erstellung mit dem Befehl bgsave
gestartet.
Diese Abbildung zeigt, wie sich jeder Server im Hinblick auf die Speichereffizienz verhält.
Dragonfly war im Ruhezustand 30 % speichereffizienter als Redis und zeigte während der Snapshot-Phase keinen sichtbaren Anstieg der Speichernutzung. In der Spitze stieg die Speichernutzung von Redis auf fast das Dreifache der von Dragonfly.
Dragonfly beendete den Schnappschuss schneller, innerhalb weniger Sekunden.
Weitere Informationen zur Speichereffizienz in Dragonfly finden Sie in unserem Dashtable-Dokument.
Dragonfly unterstützt gegebenenfalls gängige Redis-Argumente. Sie können beispielsweise Folgendes ausführen: dragonfly --requirepass=foo --bind localhost
.
Dragonfly unterstützt derzeit die folgenden Redis-spezifischen Argumente:
port
: Redis-Verbindungsport ( default: 6379
).bind
: Verwenden Sie localhost
um nur Localhost-Verbindungen zuzulassen, oder eine öffentliche IP-Adresse, um Verbindungen zu dieser IP -Adresse zuzulassen (also auch von außen). Verwenden Sie 0.0.0.0
, um alle IPv4 zuzulassen.requirepass
: Das Passwort für die AUTH-Authentifizierung ( default: ""
).maxmemory
: Beschränkung des maximalen Speichers (in für Menschen lesbaren Bytes), der von der Datenbank verwendet wird ( default: 0
). Ein maxmemory
Wert von 0
bedeutet, dass das Programm automatisch die maximale Speichernutzung ermittelt.dir
: Dragonfly Docker verwendet standardmäßig den Ordner /data
für Snapshots, die CLI verwendet ""
. Sie können die Docker-Option -v
verwenden, um es Ihrem Hostordner zuzuordnen.dbfilename
: Der Dateiname zum Speichern und Laden der Datenbank ( default: dump
).Es gibt auch einige Dragonfly-spezifische Argumente:
memcached_port
: Der Port, auf dem die Memcached-kompatible API aktiviert werden soll ( default: disabled
).
keys_output_limit
: Maximale Anzahl zurückgegebener Schlüssel im Befehl keys
( default: 8192
). Beachten Sie, dass keys
ein gefährlicher Befehl sind. Wir kürzen das Ergebnis, um einen Anstieg der Speichernutzung beim Abrufen zu vieler Schlüssel zu vermeiden.
dbnum
: Maximale Anzahl unterstützter Datenbanken für select
.
cache_mode
: Siehe den Abschnitt zum neuartigen Cache-Design weiter unten.
hz
: Häufigkeit der Schlüsselablaufauswertung ( default: 100
). Eine niedrigere Frequenz beansprucht im Leerlauf weniger CPU, allerdings auf Kosten einer langsameren Räumungsrate.
snapshot_cron
: Cron-Zeitplanausdruck für automatische Backup-Snapshots unter Verwendung der Standard-Cron-Syntax mit der Granularität von Minuten ( default: ""
). Nachfolgend finden Sie einige Beispiele für Cron-Zeitplanausdrücke. Weitere Informationen zu diesem Argument finden Sie in unserer Dokumentation.
Cron-Zeitplanausdruck | Beschreibung |
---|---|
* * * * * | In jeder Minute |
*/5 * * * * | Jede 5. Minute |
5 */2 * * * | Um 5 nach jeder 2. Stunde |
0 0 * * * | Jeden Tag um 00:00 Uhr (Mitternacht). |
0 6 * * 1-5 | Von Montag bis Freitag um 06:00 Uhr (Morgendämmerung). |
primary_port_http_enabled
: Ermöglicht den Zugriff auf die HTTP-Konsole am Haupt-TCP-Port, wenn true
( default: true
).
admin_port
: Um den Administratorzugriff auf die Konsole am zugewiesenen Port zu aktivieren ( default: disabled
). Unterstützt sowohl HTTP- als auch RESP-Protokolle.
admin_bind
: Um die TCP-Verbindung der Admin-Konsole an eine bestimmte Adresse zu binden ( default: any
). Unterstützt sowohl HTTP- als auch RESP-Protokolle.
admin_nopass
: Um den offenen Administratorzugriff auf die Konsole am zugewiesenen Port zu ermöglichen, ohne dass ein Authentifizierungstoken erforderlich ist ( default: false
). Unterstützt sowohl HTTP- als auch RESP-Protokolle.
cluster_mode
: Cluster-Modus unterstützt ( default: ""
). Unterstützt derzeit nur emulated
.
cluster_announce_ip
: Die IP, die Cluster-Befehle dem Client bekannt geben.
announce_port
: Der Port, den Cluster-Befehle dem Client und dem Replikationsmaster bekannt geben.
./dragonfly-x86_64 --logtostderr --requirepass=youshallnotpass --cache_mode=true -dbnum 1 --bind localhost --port 6379 --maxmemory=12gb --keys_output_limit=12288 --dbfilename dump.rdb
Argumente können auch bereitgestellt werden über:
--flagfile <filename>
: Die Datei sollte ein Flag pro Zeile auflisten, mit Gleichheitszeichen anstelle von Leerzeichen für Schlüsselwert-Flags. Für Flag-Werte sind keine Anführungszeichen erforderlich.DFLY_x
fest, wobei x
der genaue Name des Flags ist (Groß- und Kleinschreibung beachten). Für weitere Optionen wie Protokollverwaltung oder TLS-Unterstützung führen Sie dragonfly --help
aus.
Dragonfly unterstützt derzeit ca. 185 Redis-Befehle und alle Memcached-Befehle außer cas
. Fast auf Augenhöhe mit der Redis 5-API wird der nächste Meilenstein von Dragonfly darin bestehen, die Grundfunktionalität zu stabilisieren und die Replikations-API zu implementieren. Wenn Sie einen Befehl benötigen, der noch nicht implementiert ist, öffnen Sie bitte ein Issue.
Für die native Dragonfly-Replikation entwerfen wir ein verteiltes Protokollformat, das um ein Vielfaches höhere Geschwindigkeiten unterstützt.
Nach der Replikationsfunktion werden wir weiterhin fehlende Befehle für die APIs der Redis-Versionen 3–6 hinzufügen.
Die aktuell von Dragonfly unterstützten Befehle finden Sie in unserer Befehlsreferenz.
Dragonfly verfügt über einen einzigen, einheitlichen, adaptiven Caching-Algorithmus, der einfach und speichereffizient ist.
Sie können den Caching-Modus aktivieren, indem Sie das Flag --cache_mode=true
übergeben. Sobald dieser Modus aktiviert ist, entfernt Dragonfly Elemente, über die man in Zukunft am wenigsten stolpern wird, allerdings nur, wenn die maxmemory
Speichergrenze erreicht ist.
Die Ablauffristen sind auf ~8 Jahre begrenzt.
Ablauffristen mit Millisekundengenauigkeit (PEXPIRE, PSETEX usw.) werden für Fristen größer als 2^28 ms auf die nächste Sekunde gerundet, was einen Fehler von weniger als 0,001 % aufweist und für große Bereiche akzeptabel sein sollte. Wenn dies für Ihren Anwendungsfall nicht geeignet ist, nehmen Sie Kontakt mit uns auf oder eröffnen Sie ein Problem, in dem Sie Ihren Fall erläutern.
Detailliertere Unterschiede zwischen den Ablauffristen von Dragonfly und Redis-Implementierungen finden Sie hier.
Standardmäßig erlaubt Dragonfly den HTTP-Zugriff über seinen Haupt-TCP-Port (6379). Richtig, Sie können sich über das Redis-Protokoll und das HTTP-Protokoll mit Dragonfly verbinden – der Server erkennt das Protokoll automatisch beim Verbindungsaufbau. Probieren Sie es einfach mit Ihrem Browser aus. Der HTTP-Zugriff verfügt derzeit nicht über viele Informationen, wird aber in Zukunft nützliche Debugging- und Verwaltungsinformationen enthalten.
Gehen Sie zur URL :6379/metrics
um Prometheus-kompatible Metriken anzuzeigen.
Die von Prometheus exportierten Metriken sind mit dem Grafana-Dashboard kompatibel, siehe hier.
Wichtig! Der Zugriff auf die HTTP-Konsole soll innerhalb eines sicheren Netzwerks erfolgen. Wenn Sie den TCP-Port von Dragonfly extern verfügbar machen, empfehlen wir Ihnen, die Konsole mit --http_admin_console=false
oder --nohttp_admin_console
zu deaktivieren.
Dragonfly begann als Experiment, um zu sehen, wie ein In-Memory-Datenspeicher aussehen könnte, wenn er im Jahr 2022 entworfen würde. Basierend auf den Erkenntnissen aus unseren Erfahrungen als Benutzer von Speicherspeichern und Ingenieure, die für Cloud-Unternehmen arbeiteten, wussten wir, dass wir zwei beibehalten mussten Schlüsseleigenschaften für Dragonfly: Atomaritätsgarantien für alle Vorgänge und niedrige Latenzzeiten von unter einer Millisekunde bei sehr hohem Durchsatz.
Unsere erste Herausforderung bestand darin, die CPU-, Speicher- und I/O-Ressourcen mithilfe von Servern, die heute in öffentlichen Clouds verfügbar sind, vollständig auszunutzen. Um dieses Problem zu lösen, verwenden wir eine Shared-Nothing-Architektur, die es uns ermöglicht, den Schlüsselraum des Speichers zwischen Threads aufzuteilen, sodass jeder Thread seinen eigenen Teil der Wörterbuchdaten verwalten kann. Wir nennen diese Scheiben „Scherben“. Die Bibliothek, die das Thread- und I/O-Management für die Shared-Nothing-Architektur unterstützt, ist hier als Open-Source-Bibliothek verfügbar.
Um Atomizitätsgarantien für Mehrschlüsseloperationen bereitzustellen, nutzen wir die Fortschritte der jüngsten akademischen Forschung. Wir haben uns für den Artikel „VLL: ein Lock-Manager-Redesign für Hauptspeicher-Datenbanksysteme“ entschieden, um das Transaktions-Framework für Dragonfly zu entwickeln. Die Wahl der Shared-Nothing-Architektur und der VLL ermöglichte es uns, atomare Mehrschlüsseloperationen zu erstellen, ohne Mutexe oder Spinlocks zu verwenden. Dies war ein wichtiger Meilenstein für unseren PoC und seine Leistung stach von anderen kommerziellen und Open-Source-Lösungen ab.
Unsere zweite Herausforderung bestand darin, effizientere Datenstrukturen für den neuen Shop zu entwickeln. Um dieses Ziel zu erreichen, haben wir unsere Kern-Hashtable-Struktur auf dem Papier „Dash: Scalable Hashing on Persistent Memory“ basiert. Das Papier selbst konzentriert sich auf die Domäne des persistenten Speichers und bezieht sich nicht direkt auf Hauptspeicher, ist aber dennoch am besten auf unser Problem anwendbar. Das im Dokument vorgeschlagene Hashtable-Design ermöglichte es uns, zwei besondere Eigenschaften beizubehalten, die im Redis-Wörterbuch vorhanden sind: Die inkrementelle Hashing-Fähigkeit während des Datenspeicherwachstums und die Fähigkeit, das Wörterbuch bei Änderungen mithilfe eines zustandslosen Scanvorgangs zu durchlaufen. Zusätzlich zu diesen beiden Eigenschaften ist Dash effizienter bei der CPU- und Speichernutzung. Durch die Nutzung des Dash-Designs konnten wir mit den folgenden Funktionen weitere Innovationen einführen:
Nachdem wir die Grundlage für Dragonfly geschaffen hatten und mit seiner Leistung zufrieden waren, fuhren wir mit der Implementierung der Redis- und Memcached-Funktionalität fort. Wir haben bisher etwa 185 Redis-Befehle (entspricht in etwa der Redis 5.0-API) und 13 Memcached-Befehle implementiert.
Und schließlich,
Unsere Mission ist es, einen gut konzipierten, ultraschnellen und kosteneffizienten In-Memory-Datenspeicher für Cloud-Workloads aufzubauen, der die neuesten Hardware-Fortschritte nutzt. Wir beabsichtigen, die Schwachstellen aktueller Lösungen anzugehen und gleichzeitig ihre Produkt-APIs und Vorschläge beizubehalten.