Batch et mise en cache avec Dataloader

Dans cet article, nous allons expliquer ce qu'est Dataloader et comment il peut nous aider avec les demandes de base de données et réduire nos coûts de base de données.
Les bases de données sont un problème dans les applications modernes, car l'extraction de ressources sur les bases de données peut rapidement devenir complexe. Les données sont stockées dans une base de données pour être utilisées ultérieurement. Parvenir à un bon moyen de récupérer et de stocker des données dans une base de données nécessite beaucoup de connaissances et de travail acharné. L'optimisation de la base de données est quelque chose à laquelle les développeurs ne font pas attention lorsqu'ils commencent à créer leurs applications. Surtout lors de la création d'un MVP, l'optimisation de la base de données peut passer inaperçue et devenir un énorme problème à l'avenir. Les demandes de base de données coûtent de l'argent, ce qui signifie qu'elles peuvent devenir coûteuses avec le temps.
Une application qui souhaite s'adapter à des millions d'utilisateurs doit prendre en charge les demandes de base de données et la manière dont les données sont stockées. Il existe de nombreuses alternatives et modèles qui peuvent être suivis pour minimiser les coûts inutiles liés à la base de données et aider à économiser de l'argent.
L'un des domaines qui peuvent être améliorés dans les bases de données modernes est la façon dont les demandes sont envoyées à la base de données. Réduire le nombre de requêtes peut améliorer les performances de l'application.
Dans cet article, nous allons expliquer ce qu'est Dataloader et comment il peut nous aider avec les requêtes de base de données et réduire nos coûts de base de données. Tout d'abord, nous allons comprendre le problème N+1 et comment Dataloader le résout de manière élégante pour nous aider à réduire les demandes inutiles.
Qu'est-ce que le problème de la requête N+1 ?
Le problème de la requête N+1 est causé lorsque vous devez effectuer des requêtes N+1 dans la base de données. N représente le nombre d'éléments.
Ce problème se produit généralement lorsque nous voulons récupérer des données dans notre base de données et que nous parcourons les résultats. Cela provoque de nombreux allers-retours inutiles vers notre base de données car nous effectuons une nouvelle requête à chaque fois.
À la fin de l'opération, il en résulte N requêtes pour chaque élément (N) et la requête d'origine (+ 1).
Voici comment cela fonctionne :
- Imaginez que vous ayez une table appelée Publications contenant 100 éléments.
- Vous souhaitez récupérer tous les points en une seule demande.
- Après avoir récupéré tous les messages, pour chaque message, vous souhaitez renvoyer l'auteur.
- Vous mappez les résultats et pour chaque message, vous effectuez une nouvelle demande dans votre base de données.
- Cela entraîne 100 requêtes inutiles dans votre base de données, plus la première requête pour récupérer tous les messages.
Faire beaucoup de requêtes inutiles à notre base de données peut ralentir notre application. Il est assez facile d'écrire naïvement nos requêtes de base de données sans même remarquer que vous avez ce problème.
Qu'est-ce que Dataloader ?
Dataloader est une bibliothèque utilitaire générique qui peut être utilisée sur les données de notre application couche de récupération pour réduire les demandes à la base de données via le traitement par lots et la mise en cache. Il fournit une API simplifiée pour accéder aux sources de données distantes et réduire les allers-retours inutiles.
Dataloader n'est pas quelque chose de particulier à Node.js et aux applications JavaScript – il peut être utilisé avec n'importe quelle autre technologie et dans différentes situations. Il existe actuellement une tonne d'implémentations dans différents langages.
L'une des utilisations les plus courantes de Dataloader est dans les services GraphQL. Il combine les concepts de traitement par lots et de mise en cache avec les concepts de base de GraphQL et aide à créer des API modernes plus rapides et plus fiables.
Batching With Dataloader
Le traitement par lots est la tâche principale de Dataloader. Il crée notre chargeur en nous fournissant une fonction de chargement par lots.
import Dataloader from "dataloader";
const postLoader = new DataLoader(batchPostFn)
C'est une fonction qui reçoit un tableau de clés et renvoie une promesse, qui se résout en un tableau de valeurs.
Après cela, nous pouvons charger nos valeurs à l'aide du chargeur que nous venons de créer. Dataloader fusionnera tous les chargements individuels et appellera notre fonction batch avec toutes les clés demandées.
const post = await postLoader.load([19659039]1);
const postAuthor = await postLoader.load(post. author);
Dans ce code, vous voyez ce dont nous avons discuté : la fonction batch accepte un tableau de clés et renvoie une promesse, qui se résoudra en un tableau de valeurs. Le premier point à faire attention ici est que le tableau de valeurs doit être de la même longueur que le tableau de clés. Un autre point est que chaque index dans le tableau de valeurs doit correspondre au même index dans le tableau de clés.
import Dataloader from "dataloader";
async[19659030]function batchPostFn(keys) {
const résultats = wait db. fetchAllKeys(keys);
return keys.map(key => résultats [key] || new Error(`Pas de résultat pour ${key}[19659070]`))
};
const postLoader = new DataLoader(batchPostFF );
Avec cette configuration simple, nous pouvons réduire nos allers-retours inutiles au da tabase et rendre nos requêtes de base de données plus efficaces. Nous aurions fini par faire beaucoup de requêtes à notre base de données, et avec quelques lignes de code nous l'avons réduite à seulement deux requêtes.
Caching With Dataloader
Dataloader fournit un cache de mémorisation pour tous les chargements qui se produisent dans un demande unique à votre application.
Après que la fonction de chargement ait été appelée deux fois, Dataloader met en cache en mémoire et met en cache la valeur résultante pour réduire la redondance. Les données ne seront supprimées que lorsque les données seront récupérées.
Certains développeurs pourraient penser que Dataloader peut remplacer certains caches partagés au niveau de l'application tels que Redis. Mais le Dataloader GitHub clarifie :
Dataloader est avant tout un mécanisme de chargement de données, et son cache ne sert qu'à ne pas charger à plusieurs reprises les mêmes données dans le cadre d'une seule requête à votre application.
Le fait est que Dataloader ne remplace pas Redis ou tout autre cache au niveau de l'application. Redis est un magasin clé-valeur utilisé pour la mise en cache et de nombreuses autres situations.
Prise en main de Dataloader
Pour commencer avec Dataloader, nous devons installer le package :
yarn add dataloader
Maintenant, imaginons que nous ayons un schéma GraphQL simple, comme le suivant :
type Post {
ID: ID!
nom: Chaîne!
description: Chaîne!
corps : Chaîne !
auteur: Auteur!
commentaires : [Utilisateur !]
}
tapez Auteur {
ID: ID!
prénom : Chaîne !
lastName: Chaîne!
messages : [Post !]
}
tapez Commentaire {
ID: ID!
texte: Chaîne!
utilisateur : Utilisateur !
}
tapez Utilisateur {
ID: ID!
prénom : Chaîne !
lastName: String!
}
Maintenant, nous devons créer notre instance Dataloader. Nous allons créer une instance Dataloader pour notre type Post.
import Dataloader from "dataloader";
async function batchPostFn[19659028](keys) {
const résultats = await db.fetchAllKeys(keys );
return keys.map(key => results[key] || new Error(`Pas de résultat pour ${key}` ))
};
const postLoader = new DataLoader(batchPostFn);[19659033] Une bonne alternative ici pour utiliser notre chargeur sans avoir à l'importer à chaque fois le mettrait dans notre contexte GraphQL, lik e ceci :
const graphql = async (req: Request, res: Réponse) => {
retour {
schéma,
contexte: {
utilisateur,
req,
postLoader,
},
};
};
Maintenant, nous pouvons l'utiliser dans nos résolveurs GraphQL.
const résolveurs = {
Requête : {
post: (parent, args, context, info) => contexte .postLoader.load(args.id),
...
}
};
Dès que vous commencez à penser aux performances, votre application deviendra meilleure et plus fiable. Il est très facile de démarrer avec Dataloader et de créer des chargeurs de tous types dans votre API GraphQL. Cela vous aidera certainement à réduire les coûts et à rendre votre API GraphQL plus performante.
Conclusion
Une approche naïve pour récupérer les ressources de la base de données peut être coûteuse avec le temps. Dataloader nous aide à réduire nos coûts et à économiser des allers-retours inutiles vers notre base de données grâce au traitement par lots et à la mise en cache.
Source link