Avant de continuer, pensez à nous donner une étoile GitHub ️. Merci!
Autres langues : 简体中文 日本語 한국어
Site Web • Documents • Démarrage rapide • Discorde communautaire • Forum Dragonfly • Rejoignez la communauté Dragonfly
Discussions GitHub • Problèmes GitHub • Contribution • Dragonfly Cloud
Dragonfly est un magasin de données en mémoire conçu pour les charges de travail d'applications modernes.
Entièrement compatible avec les API Redis et Memcached, Dragonfly ne nécessite aucune modification de code pour être adopté. Par rapport aux anciennes banques de données en mémoire, Dragonfly offre un débit 25 fois supérieur, des taux de réussite du cache plus élevés avec une latence de queue plus faible et peut fonctionner avec jusqu'à 80 % de ressources en moins pour une charge de travail de même taille.
Nous comparons d'abord Dragonfly avec Redis sur l'instance m5.large
qui est couramment utilisée pour exécuter Redis en raison de son architecture monothread. Le programme de référence s'exécute à partir d'une autre instance de test de charge (c5n) dans la même zone de disponibilité en utilisant memtier_benchmark -c 20 --test-time 100 -t 4 -d 256 --distinct-client-seed
Dragonfly affiche une performance comparable :
--ratio 1:0
):Rédis | DF |
---|---|
QPS : 159K, P99.9 : 1,16 ms, P99 : 0,82 ms | QPS : 173 K, P99,9 : 1,26 ms, P99 : 0,9 ms |
--ratio 0:1
):Rédis | DF |
---|---|
QPS : 194K, P99.9 : 0,8 ms, P99 : 0,65 ms | QPS : 191K, P99.9 : 0,95 ms, P99 : 0,8 ms |
Le benchmark ci-dessus montre que la couche algorithmique à l'intérieur de DF qui lui permet d'évoluer verticalement ne coûte pas cher lors de l'exécution en monothread.
Cependant, si l’on prend une instance un peu plus forte (m5.xlarge), l’écart entre DF et Redis commence à se creuser. ( memtier_benchmark -c 20 --test-time 100 -t 6 -d 256 --distinct-client-seed
):
--ratio 1:0
):Rédis | 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
):Rédis | DF |
---|---|
QPS : 220K, P99.9 : 0,98 ms, P99 : 0,8 ms | QPS : 305K, P99.9 : 1,03 ms, P99 : 0,87 ms |
La capacité de débit de Dragonfly continue de croître avec la taille de l'instance, tandis que Redis monothread est goulot d'étranglement sur le processeur et atteint les maxima locaux en termes de performances.
Si nous comparons Dragonfly et Redis sur l'instance c6gn.16xlarge la plus compatible avec le réseau, Dragonfly a montré une augmentation de 25 fois du débit par rapport au processus unique Redis, dépassant 3,8 millions de QPS.
Mesures de latence du 99e centile de Dragonfly à son débit maximal :
op | r6g | c6gn | c7g |
---|---|---|---|
ensemble | 0,8 ms | 1 ms | 1 ms |
obtenir | 0,9 ms | 0,9 ms | 0,8 ms |
sétex | 0,9 ms | 1,1 ms | 1,3 ms |
Tous les tests ont été effectués à l'aide de memtier_benchmark
(voir ci-dessous) avec le nombre de threads réglés par serveur et type d'instance. memtier
a été exécuté sur une machine c6gn.16xlarge distincte. Nous avons fixé le délai d'expiration à 500 pour le benchmark SETEX afin de garantir qu'il survivra à la fin du test.
memtier_benchmark --ratio ... -t < threads > -c 30 -n 200000 --distinct-client-seed -d 256
--expiry-range=...
En mode pipeline --pipeline=30
, Dragonfly atteint 10 M QPS pour les opérations SET et 15 M QPS pour les opérations GET.
Nous avons comparé Dragonfly avec Memcached sur une instance c6gn.16xlarge sur AWS.
Avec une latence comparable, le débit de Dragonfly a surpassé celui de Memcached dans les charges de travail d'écriture et de lecture. Dragonfly a démontré une meilleure latence dans les charges de travail d'écriture en raison de conflits sur le chemin d'écriture dans Memcached.
Serveur | QPS (milliers qps) | latence 99% | 99,9% |
---|---|---|---|
Libellule | ? 3844 | ? 0,9 ms | ? 2,4 ms |
Memcaché | 806 | 1,6 ms | 3,2 ms |
Serveur | QPS (milliers qps) | latence 99% | 99,9% |
---|---|---|---|
Libellule | ? 3717 | 1 ms | 2,4 ms |
Memcaché | 2100 | ? 0,34 ms | ? 0,6 ms |
Memcached présentait une latence plus faible pour le test de lecture, mais également un débit plus faible.
Pour tester l'efficacité de la mémoire, nous avons rempli Dragonfly et Redis avec environ 5 Go de données à l'aide de la commande debug populate 5000000 key 1024
, envoyé le trafic de mise à jour avec memtier
et lancé la capture instantanée avec la commande bgsave
.
Cette figure montre le comportement de chaque serveur en termes d'efficacité de la mémoire.
Dragonfly était 30 % plus efficace en mémoire que Redis à l'état inactif et n'a montré aucune augmentation visible de l'utilisation de la mémoire pendant la phase d'instantané. Au maximum, l'utilisation de la mémoire de Redis a augmenté jusqu'à près de 3 fois celle de Dragonfly.
Dragonfly a terminé l'instantané plus rapidement, en quelques secondes.
Pour plus d'informations sur l'efficacité de la mémoire dans Dragonfly, consultez notre document Dashtable.
Dragonfly prend en charge les arguments Redis courants, le cas échéant. Par exemple, vous pouvez exécuter : dragonfly --requirepass=foo --bind localhost
.
Dragonfly prend actuellement en charge les arguments spécifiques à Redis suivants :
port
: port de connexion Redis ( default: 6379
).bind
: Utilisez localhost
pour autoriser uniquement les connexions localhost ou une adresse IP publique pour autoriser les connexions à cette adresse IP (c'est-à-dire également de l'extérieur). Utilisez 0.0.0.0
pour autoriser tous les IPv4.requirepass
: Le mot de passe pour l'authentification AUTH ( default: ""
).maxmemory
: Limite de la mémoire maximale (en octets lisibles par l'homme) utilisée par la base de données ( default: 0
). Une valeur maxmemory
de 0
signifie que le programme déterminera automatiquement son utilisation maximale de la mémoire.dir
: Dragonfly Docker utilise le dossier /data
pour la prise d'instantanés par défaut, la CLI utilise ""
. Vous pouvez utiliser l'option -v
Docker pour le mapper à votre dossier hôte.dbfilename
: Le nom de fichier pour enregistrer et charger la base de données ( default: dump
).Il existe également quelques arguments spécifiques à Dragonfly :
memcached_port
: Le port sur lequel activer l'API compatible Memcached ( default: disabled
).
keys_output_limit
: Nombre maximum de clés renvoyées dans la commande keys
( default: 8192
). Notez que keys
sont une commande dangereuse. Nous tronquons son résultat pour éviter une explosion de l'utilisation de la mémoire lors de la récupération d'un trop grand nombre de clés.
dbnum
: Nombre maximum de bases de données prises en charge pour select
.
cache_mode
: voir la nouvelle section sur la conception du cache ci-dessous.
hz
: Fréquence d'évaluation de l'expiration de la clé ( default: 100
). Une fréquence inférieure utilise moins de CPU lorsqu'elle est inactive au détriment d'un taux d'expulsion plus lent.
snapshot_cron
: expression de planification Cron pour les instantanés de sauvegarde automatique utilisant la syntaxe cron standard avec une granularité en minutes ( default: ""
). Voici quelques exemples d'expressions de planification cron ci-dessous, et n'hésitez pas à en savoir plus sur cet argument dans notre documentation.
Expression de planification Cron | Description |
---|---|
* * * * * | A chaque minute |
*/5 * * * * | Toutes les 5 minutes |
5 */2 * * * | À 5 minutes toutes les 2 heures |
0 0 * * * | À minuit (minuit) tous les jours |
0 6 * * 1-5 | À 06h00 (aube) du lundi au vendredi |
primary_port_http_enabled
: Permet d'accéder à la console HTTP sur le port TCP principal si true
( default: true
).
admin_port
: Pour activer l'accès administrateur à la console sur le port attribué ( default: disabled
). Prend en charge les protocoles HTTP et RESP.
admin_bind
: Pour lier la connexion TCP de la console d'administration à une adresse donnée ( default: any
). Prend en charge les protocoles HTTP et RESP.
admin_nopass
: Pour activer l'accès administrateur ouvert à la console sur le port attribué, sans jeton d'authentification nécessaire ( default: false
). Prend en charge les protocoles HTTP et RESP.
cluster_mode
: Mode cluster pris en charge ( default: ""
). Actuellement, ne prend en charge que emulated
.
cluster_announce_ip
: L'adresse IP annoncée par les commandes du cluster au client.
announce_port
: Le port annoncé par les commandes du cluster au client et au maître de réplication.
./dragonfly-x86_64 --logtostderr --requirepass=youshallnotpass --cache_mode=true -dbnum 1 --bind localhost --port 6379 --maxmemory=12gb --keys_output_limit=12288 --dbfilename dump.rdb
Les arguments peuvent également être fournis via :
--flagfile <filename>
: Le fichier doit répertorier un indicateur par ligne, avec des signes égal au lieu d'espaces pour les indicateurs clé-valeur. Aucun guillemet n'est nécessaire pour les valeurs d'indicateur.DFLY_x
, où x
est le nom exact de l'indicateur, sensible à la casse. Pour plus d'options telles que la gestion des journaux ou la prise en charge de TLS, exécutez dragonfly --help
.
Dragonfly prend actuellement en charge environ 185 commandes Redis et toutes les commandes Memcached en plus de cas
. Presque à égalité avec l'API Redis 5, la prochaine étape de Dragonfly sera de stabiliser les fonctionnalités de base et de mettre en œuvre l'API de réplication. Si vous avez besoin d'une commande qui n'est pas encore implémentée, veuillez ouvrir un ticket.
Pour la réplication native de Dragonfly, nous concevons un format de journal distribué qui prendra en charge des vitesses plus élevées d'un ordre de grandeur.
Suite à la fonctionnalité de réplication, nous continuerons à ajouter les commandes manquantes pour les API Redis versions 3 à 6.
Veuillez consulter notre référence des commandes pour les commandes actuellement prises en charge par Dragonfly.
Dragonfly dispose d'un algorithme de mise en cache adaptatif unique, unifié, simple et économe en mémoire.
Vous pouvez activer le mode mise en cache en passant l'indicateur --cache_mode=true
. Une fois ce mode activé, Dragonfly expulsera les éléments les moins susceptibles d'être rencontrés à l'avenir, mais uniquement lorsqu'ils seront proches de la limite de maxmemory
.
Les plages d’expiration sont limitées à environ 8 ans.
Les délais d'expiration avec une précision à la milliseconde (PEXPIRE, PSETEX, etc.) sont arrondis à la seconde la plus proche pour les délais supérieurs à 2 ^ 28 ms , ce qui comporte une erreur inférieure à 0,001 % et devrait être acceptable pour de grandes plages. Si cela ne convient pas à votre cas d'utilisation, contactez-nous ou ouvrez un ticket expliquant votre cas.
Pour des différences plus détaillées entre les délais d'expiration de Dragonfly et les implémentations Redis, voir ici.
Par défaut, Dragonfly autorise l'accès HTTP via son port TCP principal (6379). C'est vrai, vous pouvez vous connecter à Dragonfly via le protocole Redis et via le protocole HTTP — le serveur reconnaît automatiquement le protocole lors de l'initiation de la connexion. Allez-y et essayez-le avec votre navigateur. L'accès HTTP ne contient actuellement pas beaucoup d'informations mais inclura des informations utiles de débogage et de gestion à l'avenir.
Accédez à l'URL :6379/metrics
pour afficher les métriques compatibles avec Prometheus.
Les métriques exportées par Prometheus sont compatibles avec le tableau de bord Grafana, voir ici.
Important! La console HTTP est destinée à être accessible au sein d'un réseau sécurisé. Si vous exposez le port TCP de Dragonfly en externe, nous vous conseillons de désactiver la console avec --http_admin_console=false
ou --nohttp_admin_console
.
Dragonfly a commencé comme une expérience visant à voir à quoi pourrait ressembler une banque de données en mémoire si elle était conçue en 2022. Sur la base des leçons tirées de notre expérience en tant qu'utilisateurs de banques de mémoire et ingénieurs ayant travaillé pour des entreprises cloud, nous savions que nous devions préserver deux Propriétés clés de Dragonfly : garanties d'atomicité pour toutes les opérations et une latence faible, inférieure à la milliseconde, sur un débit très élevé.
Notre premier défi consistait à utiliser pleinement les ressources CPU, mémoire et E/S à l'aide des serveurs disponibles aujourd'hui dans les cloud publics. Pour résoudre ce problème, nous utilisons une architecture sans partage, qui nous permet de partitionner l'espace de clés de la mémoire entre les threads afin que chaque thread puisse gérer sa propre tranche de données de dictionnaire. Nous appelons ces tranches des « fragments ». La bibliothèque qui alimente la gestion des threads et des E/S pour une architecture sans partage est ici open source.
Pour fournir des garanties d'atomicité pour les opérations multi-clés, nous utilisons les avancées de la recherche universitaire récente. Nous avons choisi l'article « VLL : a lock manager redesign for main memory database systems » pour développer le cadre transactionnel pour Dragonfly. Le choix de l'architecture sans partage et de VLL nous a permis de composer des opérations atomiques multi-clés sans utiliser de mutex ou de spinlocks. a été une étape majeure pour notre PoC et ses performances se sont démarquées des autres solutions commerciales et open source.
Notre deuxième défi consistait à concevoir des structures de données plus efficaces pour le nouveau magasin. Pour atteindre cet objectif, nous avons basé notre structure de base de table de hachage sur l'article « Dash : Scalable Hashing on Persistent Memory ». L'article lui-même est centré sur le domaine de la mémoire persistante et n'est pas directement lié aux magasins de mémoire principale, mais il reste néanmoins le plus applicable à notre problème. La conception de table de hachage suggérée dans l'article nous a permis de conserver deux propriétés spéciales présentes dans le dictionnaire Redis : La capacité de hachage incrémentielle pendant la croissance de la banque de données, la possibilité de parcourir le dictionnaire sous les modifications à l'aide d'une opération d'analyse sans état. En plus de ces deux propriétés, Dash est plus efficace en termes d’utilisation du processeur et de la mémoire. En tirant parti de la conception de Dash, nous avons pu innover davantage avec les fonctionnalités suivantes :
Une fois que nous avons construit les bases de Dragonfly et que nous étions satisfaits de ses performances, nous avons ensuite implémenté les fonctionnalités Redis et Memcached. Nous avons à ce jour implémenté environ 185 commandes Redis (à peu près équivalentes à l'API Redis 5.0) et 13 commandes Memcached.
Et enfin,
Notre mission est de créer une banque de données en mémoire bien conçue, ultra-rapide et rentable pour les charges de travail cloud, qui tire parti des dernières avancées matérielles. Nous avons l'intention de résoudre les problèmes des solutions actuelles tout en préservant leurs API et propositions de produits.