J'ai un groupe de disponibilité Always On configuré et je veux m'assurer que mes utilisateurs utilisent ApplicationIntent = ReadOnly dans leurs chaînes de connexion.
À partir de SQL Server via DMV (ou événements étendus ou autre), puis-je savoir si un utilisateur connecté avec ApplicationIntent = ReadOnly dans sa chaîne de connexion?
Veuillez ne pas répondre à la façon de PRÉVENIR les connexions - ce n'est pas le sujet de cette question. Je ne peux pas simplement arrêter les connexions, car nous avons des applications existantes qui se connectent sans la bonne chaîne, et j'ai besoin de savoir lesquelles elles sont afin que je puisse travailler avec les développeurs et les utilisateurs pour les réparer progressivement au fil du temps.
Supposons que les utilisateurs ont plusieurs applications. Par exemple, Bob se connecte à SQL Server Management Studio et à Excel. Il se connecte à SSMS lorsqu'il doit effectuer des mises à jour et à Excel lorsqu'il doit effectuer des lectures. Je dois m'assurer qu'il utilise ApplicationIntent = ReadOnly lorsqu'il se connecte à Excel. (Ce n'est pas le scénario exact, mais il est assez proche pour illustrer.)
la source
sqlserver.read_only_route_complete
car il est déclenché uniquement sur le primaire.Réponses:
Reprenant l'
sqlserver.read_only_route_complete
événement prolongé mentionné par Kin et Remus, il est un bon débogage événement, mais il ne porte pas beaucoup d'informations avec - justeroute_port
(par exemple 1433) etroute_server_name
(par exemple sqlserver-0.contoso.com) par défaut . Cela aiderait également à déterminer quand une connexion intentionnelle en lecture seule a réussi. Il y a unread_only_route_fail
événement mais je n'ai pas pu le déclencher, peut-être qu'en cas de problème avec l'URL de routage, il ne semblait pas se déclencher lorsque l'instance secondaire n'était pas disponible / arrêtée pour autant que je sache.J'ai cependant eu un certain succès en joignant cela à l'
sqlserver.login
événement et au suivi de la causalité activé, ainsi que certaines actions (commesqlserver.username
) pour le rendre utile.Étapes à reproduire
Créez une session d'événements étendus pour suivre les événements pertinents, ainsi que des actions utiles et suivre le lien de causalité:
Exécutez la session XE (pensez à l'échantillonnage car il s'agit d'un événement de débogage) et collectez quelques connexions:
Notez ici que sqlserver-0 est mon secondaire lisible et sqlserver-1 le principal. Ici, j'utilise le
-K
commutateur desqlcmd
pour simuler les connexions d'intention d'application en lecture seule et certaines connexions SQL. L'événement en lecture seule se déclenche sur une connexion d'intention en lecture seule réussie.En mettant en pause ou en arrêtant la session, je peux l'interroger et tenter de lier les deux événements, par exemple:
La requête doit afficher les connexions avec et sans intention de lecture seule de l'application:
read_only_route_complete
est un événement de débogage, utilisez-le avec parcimonie. Prenons l'exemple de l'échantillonnage.J'ai essayé de faire fonctionner la
pair_matching
cible mais j'ai manqué de temps. Il y a un potentiel de développement ici, quelque chose comme:la source
Non, il ne semble pas y avoir de propriété de connexion exposée DMV (soit dans sys.dm_exec_connections ou sys.dm_exec_sessions ) ni même CONNECTIONPROPERTY qui se rapporte au
ApplicationIntent
mot clé ConnectionString.Cependant, il peut être utile de demander, via Microsoft Connect, que cette propriété soit ajoutée au
sys.dm_exec_connections
DMV car elle semble être une propriété de la connexion qui est stockée quelque part dans la mémoire de SQL Server, en fonction des informations suivantes trouvées dans la page MSDN pour Prise en charge de SqlClient pour la haute disponibilité, la reprise après sinistre (accentuation en italique):Si une
USE
déclaration peut être vérifiée, alors lesApplicationIntent
besoins doivent exister au-delà de la tentative de connexion initiale. Cependant, je n'ai pas personnellement vérifié ce comportement.PS J'avais pensé que nous pourrions utiliser les faits qui:
USE
instruction.L'idée était de créer une nouvelle base de données uniquement dans le but de tester et de suivre ce paramètre. La nouvelle base de données serait utilisée dans un nouveau groupe de disponibilité qui serait défini pour autoriser uniquement les
READ_WRITE
connexions. La théorie était qu'à l'intérieur d'un déclencheur d'ouverture de session, unEXEC(N'USE [ReadWriteOnly]; INSERT INTO LogTable...;');
dans uneTRY...CATCH
construction, avec essentiellement rien dans leCATCH
bloc, ne produirait aucune erreur pour les connexions ReadWrite (qui se connecteraient dans la nouvelle base de données), ou l'USE
erreur sur les connexions ReadOnly, mais alors rien ne se passerait puisque l'erreur est détectée et ignorée (et laINSERT
déclaration ne serait jamais atteinte). Dans les deux cas, l'événement de connexion réel ne sera pas empêché / refusé. Le code d'ouverture de session serait effectivement:Malheureusement, lors du test de l'effet de l'émission d'une
USE
instruction dans unEXEC()
dans unTRY...CATCH
intérieur d'une transaction, j'ai constaté que la violation d'accès était un abandon au niveau du lot, pas un abandon au niveau de l'instruction. Et le réglageXACT_ABORT OFF
n'a rien changé. J'ai même créé une procédure stockée SQLCLR simple à utiliserContext Connection = true;
, puis appeléeSqlConnection.ChangeDatabase()
dans untry...catch
et la transaction était toujours abandonnée. Et vous ne pouvez pas utiliserEnlist=false
la connexion contextuelle. Et l'utilisation d'une connexion régulière / externe dans SQLCLR pour sortir de la transaction n'aiderait pas car ce serait une toute nouvelle connexion.Il y a une possibilité très, très mince que HAS_DBACCESS puisse être utilisé à la place de la
USE
déclaration, mais je n'ai vraiment pas grand espoir qu'il puisse incorporer les informations de connexion actuelles dans ses vérifications. Mais je n'ai aucun moyen de le tester non plus.Bien sûr, s'il existe un indicateur de trace qui peut empêcher la violation d'accès d'être annulée par lots, le plan mentionné ci-dessus devrait fonctionner ;-).
la source
ROLLBACK
déclencheur de connexion en unINSERT
dans une table de log :-)Comment voulez-vous être malade? Le flux TDS n'est pas si difficile à proxy, nous l'avons fait pour notre application SaaS. Le bit que vous recherchez (littéralement un peu) se trouve dans le message login7. Vous pouvez demander à vos utilisateurs de se connecter via un proxy et d'enregistrer / appliquer le bit à cet endroit. Enfer, vous pouvez même l'activer pour eux. :)
la source
Votre application utilise-t-elle un compte de service ou peut-être plusieurs comptes de service? Si c'est le cas, utilisez Extended Event pour surveiller votre trafic de connexion, mais excluez vos comptes de service sur votre serveur principal permanent. Vous devriez maintenant pouvoir voir qui se connecte au serveur principal permanent et n'utilise pas la chaîne de connexion secondaire en lecture seule. Je me prépare à installer Always-On et c'est ce que je vais faire, sauf si vous me dites que cela ne fonctionnera pas.
la source
Malheureusement, je n'ai pas l'environnement pour tester les éléments suivants, et il y a sans aucun doute plusieurs points où cela peut échouer, mais je vais le jeter là-bas pour ce qu'il vaut.
Une procédure stockée CLR a accès à la connexion actuelle via la
new SqlConnection("context connection=true")
construction (prise à partir d' ici ). Le type SqlConnection expose une propriété ConnectionString . Depuis ApplicationIntent est dans la chaîne de connexion initiale, je suppose qu'il sera disponible dans cette propriété et peut être analysé. Il y a beaucoup de transferts dans cette chaîne, bien sûr, donc de nombreuses opportunités pour que tout cela prenne la forme d'une poire.Cela s'exécuterait à partir d'un déclencheur d'ouverture de session et les valeurs requises persisteraient selon les besoins.
la source