Mon entreprise utilise une application qui présente des problèmes de performances assez importants. Il y a un certain nombre de problèmes avec la base de données elle-même que je suis en train de résoudre, mais beaucoup de problèmes sont purement liés à l'application.
Dans mon enquête, j'ai découvert qu'il y avait des millions de requêtes frappant la base de données SQL Server qui interrogent des tables vides. Nous avons environ 300 tables vides et certaines de ces tables sont interrogées jusqu'à 100-200 fois par minute. Les tableaux n'ont rien à voir avec notre domaine d'activité et font essentiellement partie de l'application d'origine que le fournisseur n'a pas supprimée lorsqu'ils ont été engagés par mon entreprise pour produire une solution logicielle pour nous.
Outre le fait que nous soupçonnons que notre journal d'erreurs d'application est inondé d'erreurs liées à ce problème, le fournisseur nous assure qu'il n'y a aucun impact sur les performances ou la stabilité pour l'application ou le serveur de base de données. Le journal des erreurs est inondé dans la mesure où nous ne pouvons pas voir plus de 2 minutes d'erreurs pour effectuer des diagnostics.
Le coût réel de ces requêtes va évidemment être faible en termes de cycles CPU, etc. Mais quelqu'un peut-il suggérer quel serait l'effet sur SQL Server et l'application? Je soupçonne que les mécanismes réels d'envoi d'une demande, de confirmation, de traitement, de retour et d'accusé de réception de la demande auraient eux-mêmes un impact sur les performances.
Nous utilisons SQL Server 2008 R2, Oracle Weblogic 11g pour l'application.
@ Frisbee - Bref, j'ai créé une table contenant le texte de la requête qui a frappé les tables vides dans la base de données de l'application, puis je l'ai interrogé pour tous les noms de tables que je sais vides et j'ai obtenu une très longue liste. Le résultat le plus élevé a été de 2,7 millions d'exécutions sur 30 jours de disponibilité, sachant que l'application est généralement utilisée de 8h00 à 18h00, de sorte que ces chiffres sont plus concentrés sur les heures opérationnelles. Plusieurs tables, plusieurs requêtes, probablement certaines relavent via des jointures, d'autres non. Le résultat le plus élevé (2,7 millions à l'époque) était un simple choix dans une seule table vide avec une clause where, pas de jointure. Je m'attendrais à ce que des requêtes plus importantes avec des jointures aux tables vides puissent inclure des mises à jour des tables liées, mais je vais vérifier cela et mettre à jour cette question dès que possible.
Mise à jour: il y a 1000 requêtes avec un nombre d'exécutions compris entre 1043 et 4622614 (sur 2,5 mois). Je vais devoir creuser plus pour savoir d'où vient le plan mis en cache. C'est juste pour vous donner une idée de l'étendue des requêtes. La plupart sont raisonnablement complexes avec plus de 20 jointures.
@ srutzky- oui, je crois qu'il y a une colonne de date liée au moment où le plan a été compilé, ce qui serait intéressant, donc je vais vérifier cela. Je me demande si les limites de threads sont un facteur lorsque le serveur SQL se trouve sur un cluster VMware? Bientôt un Dell PE 730xD dédié, heureusement.
@Frisbee - Désolé pour la réponse tardive. Comme vous l'avez suggéré, j'ai exécuté une sélection * de la table vide 10 000 fois sur 24 threads à l'aide de SQLQueryStress (donc en fait 240 000 itérations) et j'ai immédiatement frappé 10 000 requêtes par lot. Ensuite, j'ai réduit à 1000 fois plus de 24 threads et atteint un peu moins de 4 000 demandes de lot / s. J'ai également essayé 10 000 itérations sur seulement 12 threads (donc 1 20000 itérations au total), ce qui a produit un maintien de 6 505 lots / s. L'effet sur le processeur était en fait notable, environ 5 à 10% de l'utilisation totale du processeur lors de chaque test. Les temps d'attente sur le réseau étaient négligeables (comme 3 ms avec le client sur mon poste de travail) mais l'impact du processeur était là, c'est certain, ce qui est assez concluant en ce qui me concerne. Il semble se résumer à l'utilisation du processeur et à un peu d'E / S de fichiers de base de données inutiles. Le nombre total d'exécutions / seconde s'élève à un peu moins de 3000, ce qui est plus qu'en production, mais je ne teste qu'une seule des dizaines de requêtes comme celle-ci. L'effet net de centaines de requêtes atteignant des tables vides à un taux compris entre 300 et 4000 fois par minute ne serait donc pas négligeable en ce qui concerne le temps CPU. Tous les tests effectués contre un PE 730xD inactif avec double baie flash et 256 Go de RAM, 12 cœurs modernes.
@ srutzky- bonne pensée. SQLQueryStress semble utiliser le regroupement de connexions par défaut, mais j'ai quand même regardé et j'ai constaté que oui, la case pour le regroupement de connexions est cochée. Mise à jour à suivre
@ srutzky- Le pool de connexions n'est apparemment pas activé sur l'application - ou s'il l'est, il ne fonctionne pas. J'ai fait une trace de profileur et j'ai constaté que les connexions ont EventSubClass "1 - Non groupé" pour les événements de connexion d'audit.
RE: Connection Pooling - Vérifié les weblogics et trouvé le pool de connexions activé. Ran plus de traces contre les signes en direct et trouvés de regroupement ne se produisant pas correctement / pas du tout:
Et voici à quoi cela ressemble lorsque j'exécute une seule requête sans jointure sur une table remplie; les exceptions indiquent "Une erreur liée au réseau ou spécifique à l'instance s'est produite lors de l'établissement d'une connexion à SQL Server. Le serveur n'a pas été trouvé ou n'était pas accessible. Vérifiez que le nom de l'instance est correct et que SQL Server est configuré pour autoriser les connexions à distance. (fournisseur: fournisseur de canaux nommés, erreur: 40 - Impossible d'ouvrir une connexion à SQL Server) "Notez le compteur de demandes par lots. Le ping du serveur pendant la génération des exceptions entraîne une réponse ping réussie.
Mise à jour - deux exécutions de test consécutives, même charge de travail (sélectionnez * fromEmptyTable), regroupement activé / non activé. Un peu plus d'utilisation du processeur et beaucoup d'échecs et ne dépasse jamais 500 requêtes par lot. Les tests montrent 10 000 lots / s et aucune défaillance avec le regroupement activé, et environ 400 lots / s, puis beaucoup d'échecs dus à la désactivation du regroupement. Je me demande si ces échecs sont liés à un manque de disponibilité de connexion?
@ srutzky- Sélectionnez Count (*) dans sys.dm_exec_connections;
Pooling activé: 37 de manière cohérente, même après l'arrêt du test de charge
Pooling désactivé: 11-37 selon que des exceptions se
produisent ou non sur SQLQueryStress, c'est-à-dire que lorsque ces creux apparaissent sur le
graphique Batch / sec, les exceptions se produisent sur SQLQueryStress et le
nombre de connexions tombe à 11, puis revient progressivement à 37 lorsque les lots commencent à culminer et que les exceptions ne se produisent pas. Très, très intéressant.
Le nombre maximal de connexions sur les deux instances de test / live est défini sur 0 par défaut.
Après avoir vérifié les journaux des applications et ne pas trouver de problèmes de connectivité, il ne reste que quelques minutes de journalisation disponibles en raison du grand nombre et de la taille des erreurs, à savoir: beaucoup d'erreurs de trace de pile. Un collègue du support des applications indique qu'un nombre important d'erreurs HTTP se produisent en raison de la connectivité. Il semblerait basé sur cela, que pour une raison quelconque l'application ne regroupe pas correctement les connexions et par conséquent, le serveur manque à plusieurs reprises de connexions. J'examinerai davantage les journaux d'application. Je me demande s'il existe un moyen de prouver que cela se produit dans la production du côté de SQL Server?
@ srutzky- Merci. Je vérifierai la configuration weblogic demain et mettrai à jour. Je pensais cependant aux 37 simples connexions - si SQLQueryStress fait 12 threads à 10 000 itérations = 120 000 instructions de sélection non regroupées, cela ne devrait-il pas signifier que chaque sélection crée une connexion distincte à l'instance SQL?
@ srutzky- Weblogics sont configurés pour regrouper les connexions, donc cela devrait fonctionner correctement. Le regroupement de connexions est configuré comme ceci, sur chacun des 4 blogues à charge équilibrée:
- Capacité initiale: 10
- Capacité maximale: 50
- Capacité minimum: 5
Lorsque j'augmente le nombre de threads exécutant la sélection à partir d'une requête de table vide, le nombre de connexions culmine autour de 47. Lorsque le pool de connexions est désactivé, je constate systématiquement une baisse du nombre maximal de demandes de lot / s (de 10 000 à environ 400). Ce qui se produira à chaque fois, c'est que les «exceptions» sur SQLQueryStress se produisent peu de temps après que les lots / s soient entrés dans un creux. C'est lié à la connectivité, mais je ne peux pas comprendre exactement pourquoi cela se produit. Lorsqu'aucun test n'est en cours, #connections descend à environ 12.
Avec la mise en commun des connexions désactivée, j'ai du mal à comprendre pourquoi les exceptions se produisent, mais peut-être qu'il s'agit d'une toute autre question stackExchange / question pour Adam Machanic?
@srutzky Je me demande alors pourquoi les exceptions se produisent sans regroupement activé, même si SQL Server ne manque pas de connexions?
SELECT COUNT(*) FROM sys.dm_exec_connections;
pour voir si la valeur est très différente entre le regroupement activé ou ne pas. Sur la base de ces erreurs, je pense qu'il y aurait beaucoup plus de connexions lorsque la mise en commun est désactivée.Pooling=false
ouMax Pool Size
?Réponses:
Oui, et il y a même des facteurs supplémentaires, mais il est impossible de dire dans quelle mesure ces éléments affectent réellement votre système sans analyser le système.
Cela étant dit, vous demandez ce qui pourrait être un problème, et il y a certaines choses à mentionner, même si certaines d'entre elles ne sont pas actuellement un facteur dans votre situation particulière. Vous dites que:
Il pourrait même y en avoir plus, mais cela devrait aider à comprendre les choses. Et gardez à l'esprit que, comme la plupart des problèmes de performances, tout est une question d'échelle. Tous les éléments mentionnés ci-dessus ne posent aucun problème s'ils sont touchés une fois par minute. C'est comme tester une modification sur votre poste de travail ou dans la base de données de développement: cela fonctionne toujours avec seulement 10 à 100 lignes dans les tables. Déplacez ce code en production et cela prend 10 minutes pour s'exécuter, et quelqu'un est obligé de dire: "eh bien, cela fonctionne sur ma boîte" ;-). Cela signifie que c'est uniquement en raison du volume important d'appels que vous voyez un problème, mais c'est la situation qui existe.
Donc, même pour 1 million de requêtes à 0 ligne inutiles, cela revient à:
plus de connexions maintenues qui occupent plus de mémoire. De combien de RAM physique inutilisée disposez-vous? cette mémoire serait mieux utilisée pour exécuter des requêtes et / ou un cache de plan de requête. Le pire des cas serait que vous manquez de mémoire physique et SQL Server doit commencer à utiliser la mémoire virtuelle (swap), car cela ralentit les choses (consultez votre journal des erreurs SQL Server pour voir si vous recevez des messages sur la mémoire paginée).
Et juste au cas où quelqu'un mentionne, "eh bien, il y a une mise en commun des connexions". Oui, cela aide certainement à réduire le nombre de connexions nécessaires. Mais avec des requêtes pouvant atteindre 200 fois par minute, cela représente beaucoup d'activité simultanée et des connexions doivent encore exister pour les requêtes légitimes. Faites un
SELECT * FROM sys.dm_exec_connections;
pour voir combien de connexions actives vous maintenez.Si je ne me trompe pas sur ce que j'ai déclaré ici, il me semble que, même à petite échelle, il s'agit d'un type d'attaque DDoS sur votre système car il envahit le réseau et votre serveur SQL avec de fausses demandes. , ce qui empêche les demandes réelles d'accéder à SQL Server ou d'être traitées par SQL Server.
la source
Si les tables sont frappées 100 à 200 fois par minute, elles sont (espérons-le) en mémoire. La charge sur le serveur est très très faible. À moins que vous n'ayez un processeur ou une mémoire élevé sur le serveur de base de données, il s'agit probablement d'un problème.
Oui, les requêtes prennent des verrous partagés mais, espérons-le, ne bloquent aucun verrou de mise à jour et ne sont bloqués par aucun verrou de mise à jour. Avez-vous des mises à jour, des insertions ou des suppressions sur ces tableaux? Sinon, je laisserais tomber - si vous rencontrez des problèmes de performances, il doit y avoir un plus gros poisson à frire du point de vue du serveur de base de données.
J'ai exécuté un test sur 100 000 comptes sélectionnés (*) sur une table vide et il a fonctionné en 32 secondes et les requêtes ont été effectuées sur un réseau. Donc 1/3 milliseconde. À moins que votre réseau ne soit surchargé, cela n'a même pas d'impact sur le client. Si vous rencontrez des problèmes de performances majeurs, ces requêtes vides de 1/3 millisecondes ne sont pas ce qui tue l'application.
Et ceux-ci pourraient être juste une partie d'une jointure gauche saisissant des données de type statique qui ne fait pas partie de l'application actuelle. Il pourrait être enchaîné avec d'autres requêtes, ce n'est donc pas un aller-retour supplémentaire. Si oui, c'est bâclé, mais cela ne cause même pas plus de trafic.
Revenons donc aux déclarations réelles. Voyez-vous des mises à jour, des ajouts ou des suppressions sur ces tables?
Oui, de nombreuses tables vides et requêtes sur des tables vides indiquent un codage bâclé. Mais si vous rencontrez des problèmes de performances majeurs, ce n'est pas la cause, sauf si vous avez également des opérations d'écriture vraiment bâclées avec ces tables.
la source
En général, pour chaque requête, les étapes suivantes sont effectuées:
de nombreuses requêtes, comme vous l'avez mentionné, peuvent entraîner une charge supplémentaire sur un système qui est déjà lourd - une charge supplémentaire sur les connexions, le processeur, la RAM et les E / S.
la source