Les appels à plusieurs bases de données sont-ils vraiment importants avec un appel réseau pour une API Web?


16

Chez l'un de mes employeurs, nous avons travaillé sur une API REST (mais elle s'applique également à SOAP). Le client, qui est l'interface utilisateur de l'application, passerait des appels via le Web (LAN dans les déploiements de production typiques) vers l'API. L'API ferait des appels à la base de données.

Un thème qui revient dans nos discussions est la performance: certaines personnes de l'équipe pensent que vous ne devriez pas avoir plusieurs appels de base de données (généralement des lectures) à partir d'un seul appel d'API en raison des performances; vous devez les optimiser afin que chaque appel d'API n'ait (exactement) qu'un seul appel de base de données.

Mais est-ce vraiment important? Considérez que l'interface utilisateur doit effectuer un appel réseau à l'API; c'est assez gros (ordre de grandeur des millisecondes). Les bases de données sont optimisées pour garder les choses en mémoire et exécuter les lectures très, très rapidement (par exemple. SQL Server charge et conserve tout en RAM et consomme presque toute votre RAM libre si possible).

TLDR: Est-il vraiment important de s'inquiéter de plusieurs appels de base de données lorsque nous faisons déjà un appel réseau sur le LAN? Si oui, pourquoi?

Pour être clair, je parle d'ordre de grandeur - je sais que cela dépend des spécificités (matériel de la machine, choix des API et DB, etc.) Si j'ai un appel qui prend O (millisecondes), optimise pour DB les appels qui prennent un ordre de grandeur de moins, sont-ils réellement importants? Ou y a-t-il plus au problème que cela?

Edit: pour la postérité, je pense qu'il est assez ridicule d'affirmer que nous devons améliorer les performances en combinant les appels de base de données dans ces circonstances - en particulier avec un manque de profilage. Cependant, ce n'est pas ma décision de le faire ou non; Je veux savoir quelle est la raison d'être de penser que c'est une bonne façon d'optimiser les appels d'API Web.


N'y a-t-il pas un autre appel réseau entre la couche API et la base de données?
Signez le

4
Qu'ont montré vos tests de chronométrage?
Dan Pichelman

@Sign Il n'y a aucun appel réseau entre l'API et la base de données. Ils sont garantis sur la même machine, d'après ce que je comprends.
ashes999

@DanPichelman c'est ce que je demande aussi. Personne ne semble prendre et chronométrer la performance; nous obtenons simplement des exigences pour «fixer les performances dans X en combinant tous les appels DB en un seul appel».
ashes999

Réponses:


25

Mais est-ce vraiment important? Considérez que l'interface utilisateur doit effectuer un appel réseau à l'API; c'est assez gros (ordre de grandeur des millisecondes). Les bases de données sont optimisées pour garder les choses en mémoire et exécuter les lectures très, très rapidement (par exemple. SQL Server charge et conserve tout en RAM et consomme presque toute votre RAM libre si possible).

La logique

En théorie, vous avez raison. Cependant, cette justification présente quelques défauts:

  1. D'après ce que vous avez déclaré, il n'est pas clair si vous avez réellement testé / profilé votre application. En d' autres termes, vous fait savoir que les transferts de réseau de l'application à l'API sont le composant le plus lent? Parce que c'est intuitif, il est facile de supposer que c'est le cas. Cependant, lorsque vous discutez des performances, vous ne devez jamais supposer. Chez mon employeur, je suis le responsable de la performance. Lorsque j'ai rejoint le groupe pour la première fois, les gens parlaient des CDN, de la réplication, etc. en fonction de leur intuition sur les goulots d'étranglement. Il s'avère que nos plus gros problèmes de performances étaient les requêtes de base de données peu performantes.

  2. Vous dites que, parce que les bases de données sont bonnes pour récupérer des données, que la base de données fonctionne nécessairement à des performances optimales, est utilisée de manière optimale et rien ne peut être fait pour l'améliorer. En d'autres termes, les bases de données sont conçues pour être rapides, donc je ne devrais jamais avoir à m'en soucier. Une autre ligne de pensée dangereuse. C'est comme dire qu'une voiture est censée se déplacer rapidement, donc je n'ai pas besoin de changer l'huile.

  3. Cette façon de penser suppose un seul processus à la fois, ou autrement dit, aucune concurrence. Il suppose qu'une demande ne peut pas influencer les performances d'une autre demande. Les ressources sont partagées, telles que les E / S de disque, la bande passante réseau, les pools de connexions, la mémoire, les cycles de processeur, etc. Par conséquent, la réduction de l'utilisation par un appel de base de données d'une ressource partagée peut l'empêcher de ralentir d'autres requêtes. Lorsque j'ai rejoint mon employeur actuel, la direction pensait que régler une requête de base de données de 3 secondes était une perte de temps. 3 secondes c'est si peu, pourquoi y perdre du temps? Ne serions-nous pas mieux avec un CDN ou une compression ou autre chose? Mais si je peux exécuter une requête de 3 secondes en 1 seconde, par exemple en ajoutant un index, c'est-à-dire 2/3 de blocage en moins, 2/3 de temps en moins pour occuper un thread, et plus important encore, moins de données lues sur le disque,

La théorie

Il est communément admis que la performance d'un logiciel est simplement une question de vitesse .

Du point de vue de la vitesse, vous avez raison. Un système n'est aussi rapide que son composant le plus lent. Si vous avez profilé votre code et constaté qu'Internet est le composant le plus lent, alors tout le reste n'est évidemment pas la partie la plus lente.

Cependant, étant donné ce qui précède, j'espère que vous pouvez voir comment la contention des ressources, le manque d'indexation, un code mal écrit, etc. peuvent créer des différences de performances surprenantes.

Les hypothèses

Une dernière chose. Vous avez mentionné qu'un appel à une base de données devrait être bon marché par rapport à un appel réseau de l'application à l'API. Mais vous avez également mentionné que l'application et les serveurs d'API se trouvent sur le même réseau local. Par conséquent, les deux ne sont-ils pas comparables aux appels réseau? En d'autres termes, pourquoi supposez-vous que le transfert d'API est beaucoup plus lent que le transfert de base de données alors qu'ils ont tous deux la même bande passante disponible? Bien sûr, les protocoles et les structures de données sont différents, je comprends, mais je conteste l'hypothèse selon laquelle ce sont des ordres de grandeur différents.

Où ça devient le murkey

Toute cette question concerne les appels de base de données "multiples" par rapport à "simples". Mais on ne sait pas combien sont multiples. En raison de ce que j'ai dit ci-dessus, en règle générale, je recommande de faire aussi peu d'appels de base de données que nécessaire. Mais ce n'est qu'une règle d'or.

Voici pourquoi:

  1. Les bases de données sont excellentes pour lire les données. Ce sont des moteurs de stockage. Cependant, votre logique métier réside dans votre application. Si vous établissez que chaque appel d'API entraîne exactement un appel de base de données, votre logique métier peut se retrouver dans la base de données. Peut-être que ça va. De nombreux systèmes le font. Mais certains ne le font pas. C'est une question de flexibilité.
  2. Parfois, pour obtenir un bon découplage, vous souhaitez séparer 2 appels de base de données. Par exemple, chaque demande HTTP est peut-être acheminée via un filtre de sécurité générique qui valide à partir de la base de données que l'utilisateur dispose des droits d'accès appropriés. Si tel est le cas, exécutez la fonction appropriée pour cette URL. Cette fonction peut interagir avec la base de données.
  3. Appel de la base de données en boucle. C'est pourquoi j'ai demandé combien est multiple. Dans l'exemple ci-dessus, vous auriez 2 appels de base de données. 2 est très bien. 3 peut être bien. N ne va pas bien. Si vous appelez la base de données dans une boucle, vous avez maintenant rendu les performances linéaires, ce qui signifie que cela prendra plus de temps en plus de l'entrée de la boucle. Donc, dire catégoriquement que le temps réseau d'API est le plus lent néglige complètement les anomalies comme 1% de votre trafic prenant beaucoup de temps en raison d'une boucle non encore découverte qui appelle la base de données 10000 fois.
  4. Parfois, votre application est meilleure, comme certains calculs complexes. Vous devrez peut-être lire certaines données de la base de données, faire des calculs, puis en fonction des résultats, passer un paramètre à un deuxième appel à la base de données (peut-être pour écrire des résultats). Si vous les combinez en un seul appel (comme une procédure stockée) juste pour appeler une seule fois la base de données, vous vous êtes forcé à utiliser la base de données pour quelque chose que le serveur d'application pourrait être meilleur.
  5. Équilibrage de charge: vous disposez d'une base de données (probablement) et de plusieurs serveurs d'applications à charge équilibrée. Par conséquent, plus l'application fait de travail et moins la base de données le fait, plus elle est évolutive, car il est généralement plus facile d'ajouter un serveur d'applications que de configurer la réplication de la base de données. Sur la base du point précédent, il peut être judicieux d'exécuter une requête SQL, puis de faire tous les calculs dans l'application, qui est répartie sur plusieurs serveurs, puis d'écrire les résultats lorsque vous avez terminé. Cela pourrait donner un meilleur débit (même si le temps de transaction global est le même).

TL; DR

TLDR: Est-il vraiment important de s'inquiéter de plusieurs appels de base de données alors que nous faisons déjà un appel réseau sur le LAN? Si oui, pourquoi?

Oui, mais seulement dans une certaine mesure. Vous devriez essayer de minimiser le nombre d'appels de base de données lorsque cela est possible, mais ne combinez pas les appels qui n'ont rien à voir les uns avec les autres uniquement dans le but de les combiner. Évitez également d'appeler la base de données en boucle à tout prix.


3

On dirait que votre équipe optimise avant d'avoir une raison de le faire. Avez-vous mesuré le temps nécessaire pour exécuter ces demandes? Les chances forcent ce paradigme de créer des performances moins bonnes pour l'utilisateur final car les allers-retours vers le serveur Web auront une latence beaucoup plus élevée que le temps de connexion du serveur Web à la base de données. En plus de cela, la plupart des navigateurs Web ne feront que 2 connexions simultanées à un seul serveur Web, donc pour les pages complexes, vous y rencontrerez probablement un goulot d'étranglement.

Dans tous les cas, les décisions d'optimisation ne doivent pas être prises sans données pour les sauvegarder. Mesurez-le et déterminez ce qui convient le mieux à votre application.


1
C'est un bon commentaire sur nos mauvaises pratiques de performances, mais ne répond pas à ma question de savoir si les appels DB sont quelque chose à craindre lorsque j'ai déjà un appel réseau.
ashes999

1
En général, j'ai trouvé que faire plusieurs appels de base de données n'était pas un problème. Cela est principalement dû au regroupement de connexions et à la faible latence entre la base de données et le serveur Web. Il y a un point où faire un tas d'appels db différents aura un impact négatif sur les performances, mais je n'ai pas de numéro fixe pour vous. Tout dépend de l'environnement et de l'application. Seule la mesure vous donnera la réponse que vous cherchez.
brianfeucht le

Cela ne devrait pas (nécessairement) dépendre de spécificités, car je parle d'ordre de grandeur.
ashes999

Juste des suppositions approximatives (vous devez mesurer): Temps moyen de connexion à la base de données à partir du serveur Web: 2 ms Temps moyen de connexion au serveur Web à partir du client: 20 ms appels de base de données dans le temps nécessaire pour effectuer un appel de service Web. En supposant que les requêtes de base de données prennent le même temps. Ces chiffres dépendent extrêmement de l'environnement. Si le client effectuant l'appel de service Web est local, il peut baisser de plusieurs ordres de grandeur.
brianfeucht du

2

Nous ne pouvons pas vous le dire.

Nous ne savons pas à quoi ressemblent vos requêtes. Nous ne savons pas combien de temps cela prend. Nous ne savons pas combien de frais généraux sont impliqués dans chaque demande adressée à votre serveur API. Nous ne savons pas à quel point vos clients sont géographiquement dispersés. Etc.

S'il s'agit d'un scénario qui nécessite une optimisation et dans lequel vous pouvez décider de fractionner ou de joindre les appels, vous devez le comparer dans les deux sens : décider de ce que vous optimisez (latence de l'interface utilisateur, charge du processeur du serveur, conflit, etc.) et choisissez celui qui atteint le mieux votre objectif d'optimisation.


Mis à part cela, la seule une chose que je peux ajouter avec une certitude relative est la suivante:

Dans une même demande, vous devez effectuer toutes les requêtes que vous devez effectuer pour créer une réponse.

En d'autres termes, si la réponse ne peut pas être générée jusqu'à ce que toutes les N requêtes soient effectuées, il est généralement insensé de les séparer. Si vous pouvez générer des résultats significatifs, intermédiaires ou complets, après chaque requête, démarrez l'analyse comparative.


1

Deux réflexions:

Tout d'abord, pour le consommateur utilisant l'API, il fait un appel pour accomplir une tâche. Ce qui se passe après que votre serveur a reçu l'appel pour répondre à la demande ne devrait pas être aussi rigide. Si cet appel d'un consommateur nécessite 10 sous-éléments de travail pour rassembler les données et les renvoyer, cela devrait être acceptable.

Deuxièmement: voyez-vous un problème réel de performances de base de données avec le processus en question? Mon expérience a montré que souvent essayer de mettre tous les aspects d'une demande de base de données dans un seul appel peut entraîner un appel moins efficace que de simplement faire trois ou quatre appels de données. Les bases de données modernes sont très efficaces dans la mise en cache et les plans d'exécution. Souvent, lorsque vous essayez d'en faire trop, vous verrez des procédures avec des curseurs (très mauvais pour les performances car les données sont traitées ligne par ligne, pas comme un ensemble à la fois) et un code qui se traduit par un plan moins efficace que si vous aviez cassé l'appel en plusieurs petites étapes faciles.

Par simple organisation de code, je conviens que chaque appel d'API devrait éventuellement appeler une seule procédure stockée (ou fonction db) qui, à son tour, est chargée de répondre à la demande. Il peut y avoir plus d'une étape dans la procédure.


Je suis d'accord avec vous sur la mesure de la performance, ce que personne ne semble faire. Il n'y a aucune preuve que cela est plus rapide, mais cela continue de se produire. Les performances apparaissent comme un problème lorsque nous avons des appels qui peuvent faire, disons, 1000 DB SELECT.
ashes999

@ ashes999 alors que vous pouvez gagner en vitesse en regardant le nombre d'appels de base de données, il se trouve plus probablement dans la stratégie d'indexation, etc. pas dans le nombre d'appels. Comme tout le monde l'a indiqué, regardez les données de performance.
Richard

Richard, je suis d'accord, et je le sais vraiment. Ma question est de savoir pourquoi diverses personnes ne cessent d'évoquer ce point selon lequel "plusieurs appels DB sont lents" lorsqu'un appel réseau est impliqué. Je ne vois vraiment pas comment cela peut être significatif.
ashes999

@ ashes999 Désolé, vous devriez peut-être entrer un peu plus dans les détails de l'appel réseau, car cela semble évident, je sens qu'il y a un peu plus à votre question. Je pense que nous manquons quelque chose dans vos questions. Vous subirez toujours une certaine latence du réseau et chaque appel augmente potentiellement de "x" fois pour chaque appel (en termes simples). L'instruction à la valeur nominale est vraie, plusieurs appels réseau seront plus lents qu'un appel réseau vers la base de données. C'est pourquoi je suggère un appel à une procédure stockée, qui peut alors faire plusieurs appels à la base de données sans les appels multi-réseaux.
Richard

1

Si la base de données se trouve sur un serveur différent de votre service REST, chaque appel à la base de données entraînera un aller-retour sur le réseau et cela peut nuire considérablement aux performances:

J'ai observé une fois qu'un seul appel de service Web se traduisait en environ 500 requêtes de base de données - ce n'était guère un problème lorsque le service Web et la base de données sont situés sur la même machine, mais se sont transformés en un temps de réponse de 6-7 secondes lorsqu'ils étaient sur différents Machines.

De toute évidence, 500 allers-retours à la base de données est assez extrême. Je ne sais pas quelles sont vos exigences en matière de performances, mais en règle générale, je dirais que si vous restez sous environ 10 requêtes de base de données par appel REST, vous ne devriez pas connaître de performances significatives.


1

Nous avons quelques applications qui sont très, très bavardes. Il y a un appel à chaque base de données. Célibataire. Peu. Chose. Servir des données de référence encore et encore et encore est une partie importante de la charge de travail du système. Tout cet ordonnancement des threads de travail, l'acquisition et la suppression de verrous, la planification de la vérification du cache, etc. s'additionne même s'il n'y a pas d'E / S de disque réelles. La contention est plus élevée car les transactions doivent maintenir des verrous sur plusieurs appels de base de données et le débit est donc bien inférieur à ce qu'il pourrait être. Ces équipes envisagent maintenant de devoir acheter de nouveaux serveurs DB très chers pour cette raison.

Ainsi, bien que la majorité du temps écoulé dans la configuration actuelle de votre système soit consacrée aux appels d'API REST, ignorer les performances au niveau de la base de données stocke des problèmes pour l'avenir.


0

Le chemin d'optimisation présenté est tout simplement la mauvaise façon de voir les choses.

Les appels d'API doivent être atomiques. En d'autres termes, je devrais pouvoir effectuer 1 appel d'API Web pour effectuer l'action que je souhaite. Que ce soit pour récupérer des données, mettre à jour un enregistrement ou autre chose. Il ne doit JAMAIS prendre plus d'un appel pour provoquer l'action. Et tenter de tirer parti des transactions sur plusieurs appels devrait être évité comme la peste.

Parfois, une seule action est assez complexe. Par exemple, récupérer des données combinées à partir de plusieurs sources: encore une fois, cela devrait être un seul appel. Soit tout fonctionne, soit tout échoue.

Maintenant, dire qu'un seul appel d'API ne doit exécuter qu'une seule requête DB est un peu idiot. Comme vous l'avez souligné, les frais généraux liés à l'organisation de l'appel sur le réseau sont souvent beaucoup plus chers en termes de temps global.

Je peux comprendre quelque peu leur affirmation qu'une seule requête peut être exécutée plus rapidement que plusieurs; mais cela donne une fausse impression car il ignore la charge totale de la base de données et du réseau. Ce n'est qu'en profilant les différentes façons d'extraire des données de la base de données que vous pouvez comprendre quel est vraiment le problème. Je suis sûr que tout le monde a une histoire où une requête particulière exécutée 100 fois plus souvent que prévu a tué le système jusqu'à ce qu'un index approprié soit mis en place ...

En fin de compte, vous ne pourrez pas les convaincre avec juste parler. Mettre en place un cas de test pour les deux approches et les profiler. Faites attention au temps total nécessaire pour acquérir les données dont vous avez besoin, la quantité de trafic réseau généré, le nombre et le calendrier des appels à la base de données, etc. Adoptez une approche holistique - ce qui signifie que vous regardez l'ensemble du système - et vous devriez vous retrouver avec données pour manger du corbeau ou leur montrer le chemin d'or.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.