web-dev-qa-db-fra.com

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

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, faisait des appels sur le Web (LAN dans une production typique déploiements) à 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 pour 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 dans RAM et consomme presque tout votre libre RAM = si c'est possible).

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?

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 de l'API et de la base de données, 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 de prétendre 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 à moi de décider si nous faisons cela 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.

16
ashes999

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 dans RAM et consomme presque tout votre libre RAM = si c'est 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, savez-vous réellement que les transferts réseau de l'application vers 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, disons en ajoutant un index, c'est-à-dire 2/3 de blocage en moins, 2/3 de moins de temps passé à occuper un thread, et plus important encore, moins de données lues sur le disque, ce qui signifie moins de données vidées du cache en RAM.

La théorie

Il existe une conception courante selon laquelle les performances du logiciel sont simplement à propos 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 les conflits de 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 ils sont différents de plusieurs ordres de grandeur.

Où il devient 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 à la 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 font cela. 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, continuez d'exécuter 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 l'heure du réseau API est la plus lente ignore 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 facile à mettre à l'échelle, 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 une fois 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.

25
Brandon

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.

3
brianfeucht

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 diviser ou de joindre les appels ensemble, vous devez le comparer dans les deux sens: Décidez de ce que vous optimisez (latence de l'interface utilisateur, charge du processeur du serveur, conflit, etc.) et choisissez celui celui qui atteint le mieux votre objectif d'optimisation.


Hormis cela, la seule seule chose que je puisse ajouter avec une relative certitude est la suivante:

Dans une seule demande, vous devez effectuer toutes les requêtes dont vous avez besoin 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.

2
svidgen

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 en 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 suis d'accord que chaque appel d'API devrait éventuellement appeler une seule procédure stockée (ou fonction db) qui à son tour est responsable de répondre à la demande. Il peut y avoir plus d'une étape dans la procédure.

1
Richard

Si la base de données se trouve sur un serveur différent de celui de votre service REST, chaque appel à la base de données entraînera un aller-retour réseau et que 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 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 rencontrer un impact significatif sur les performances.

1
Astrotrain

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 effectuée avec REST appels API, ignorer les performances au niveau de la base de données stocke des problèmes pour l'avenir.

1
Michael Green

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 quelque pe comprendre 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. Configurez un scénario de test pour les deux approches et profilez-les. 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 de 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 beaucoup données pour manger du corbeau ou leur montrer le chemin d'or.

0
NotMe