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.
la source
Réponses:
La logique
En théorie, vous avez raison. Cependant, cette justification présente quelques défauts:
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.
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.
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:
TL; DR
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.
la source
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.
la source
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.
la source
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.
la source
SELECT
.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.
la source
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.
la source
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.
la source