Tengo configurado un grupo de disponibilidad Always On y quiero asegurarme de que mis usuarios estén usando ApplicationIntent = ReadOnly en sus cadenas de conexión.
Desde el servidor SQL a través de DMV (o eventos extendidos o lo que sea), ¿puedo saber si un usuario se conectó con ApplicationIntent = ReadOnly en su cadena de conexión?
No responda cómo PREVENIR las conexiones; de eso no se trata esta pregunta. No puedo simplemente detener las conexiones, porque tenemos aplicaciones existentes que se conectan sin la cadena correcta, y necesito saber cuáles son para poder trabajar con los desarrolladores y usuarios para solucionarlo gradualmente con el tiempo.
Suponga que los usuarios tienen múltiples aplicaciones. Por ejemplo, Bob se conecta con SQL Server Management Studio y con Excel. Se conecta con SSMS cuando necesita hacer actualizaciones, y Excel cuando necesita hacer lecturas. Necesito asegurarme de que esté usando ApplicationIntent = ReadOnly cuando se conecta con Excel. (Ese no es el escenario exacto, pero está lo suficientemente cerca como para ilustrarlo).
fuente
sqlserver.read_only_route_complete
ya que se activa solo en primaria.Respuestas:
Retomando el
sqlserver.read_only_route_complete
evento extendido mencionado por Kin y Remus, es un buen evento de depuración , pero no lleva mucha información, soloroute_port
(por ejemplo, 1433) yroute_server_name
(por ejemplo, sqlserver-0.contoso.com) por defecto . Esto también ayudaría a determinar cuándo una conexión de intención de solo lectura fue exitosa. Hay unread_only_route_fail
evento pero no pude activarlo, tal vez si hubiera un problema con la URL de enrutamiento, no parece que se active cuando la instancia secundaria no estaba disponible / apagado por lo que pude ver.Sin embargo, he tenido cierto éxito al unir eso con el
sqlserver.login
evento y el seguimiento de causalidad habilitado, junto con algunas acciones (comosqlserver.username
) para que sea útil.Pasos para reproducir
Cree una sesión de eventos extendidos para rastrear eventos relevantes, además de acciones útiles y rastrear causalidad:
Ejecute la sesión XE (considere el muestreo ya que este es un evento de depuración) y recopile algunos inicios de sesión:
Tenga en cuenta que sqlserver-0 es mi secundaria legible y sqlserver-1 es la primaria. Aquí estoy usando el
-K
interruptor desqlcmd
para simular inicios de sesión de intención de aplicación de solo lectura y algunos inicios de sesión SQL. El evento de solo lectura se dispara en un inicio de sesión exitoso de solo lectura.Al pausar o detener la sesión, puedo consultarla e intentar vincular los dos eventos, por ejemplo:
La consulta debe mostrar los inicios de sesión con y sin intención de solo lectura de la aplicación:
read_only_route_complete
es un evento de depuración, así que utilícelo con moderación. Considere el muestreo, por ejemplo.Traté de conseguir que el
pair_matching
objetivo funcionara pero se me acabó el tiempo. Aquí hay un potencial de desarrollo, algo como:fuente
No, no parece que haya ninguna propiedad de conexión expuesta al DMV (ya sea en sys.dm_exec_connections o sys.dm_exec_sessions ) o incluso CONNECTIONPROPERTY que se relaciona con la
ApplicationIntent
palabra clave ConnectionString.Sin embargo, podría valer la pena solicitar, a través de Microsoft Connect, que esta propiedad se agregue al
sys.dm_exec_connections
DMV, ya que parece ser una propiedad de la conexión que se almacena en algún lugar de la memoria de SQL Server, según la siguiente información que se encuentra en la página de MSDN para Soporte de SQL Client para alta disponibilidad, recuperación ante desastres (énfasis en cursiva mío):Si
USE
se puede verificar una declaración, entoncesApplicationIntent
debe existir más allá del intento de conexión inicial. Sin embargo, no he verificado personalmente este comportamiento.PD: había estado pensando que podríamos hacer uso de los hechos que:
USE
se ejecute una declaración.La idea era crear una nueva base de datos con el único fin de probar y rastrear esta configuración. La nueva base de datos se usaría en un nuevo grupo de disponibilidad que se establecería para permitir solo
READ_WRITE
conexiones. La teoría era que dentro de un Logon Trigger,EXEC(N'USE [ReadWriteOnly]; INSERT INTO LogTable...;');
dentro de unaTRY...CATCH
construcción, esencialmente sin nada en elCATCH
bloque, no produciría ningún error para las conexiones ReadWrite (que se registrarían en el nuevo DB), o elUSE
error en las conexiones ReadOnly, pero entonces no pasaría nada ya que el error se detecta y se ignora (y laINSERT
declaración nunca se alcanzará). En cualquier caso, el evento de inicio de sesión real no se evitaría / denegaría. El código Logon Trigger sería efectivamente:Por desgracia, cuando se prueba el efecto de la emisión de una
USE
declaración dentro de unEXEC()
plazo de unTRY...CATCH
interior de una transacción, he encontrado que la violación de acceso era un aborto a nivel de lote, no un aborto a nivel de declaración. Y la configuraciónXACT_ABORT OFF
no cambió nada. Incluso creé un procedimiento almacenado SQLCLR simple para usarContext Connection = true;
y luego llaméSqlConnection.ChangeDatabase()
dentro de aytry...catch
la transacción aún se canceló. Y no puede usarEnlist=false
en la conexión de contexto. Y usar una conexión regular / externa en SQLCLR para salir de la transacción no ayudaría, ya que sería una conexión completamente nueva.Existe una posibilidad muy, muy escasa de que HAS_DBACCESS pueda usarse en lugar de la
USE
declaración, pero realmente no tengo muchas esperanzas de que pueda incorporar la información actual de Connection en sus comprobaciones. Pero tampoco tengo forma de probarlo.Por supuesto, si hay un indicador de seguimiento que puede hacer que la infracción de acceso no se cancele por lotes, entonces el plan mencionado anteriormente debería funcionar ;-).
fuente
ROLLBACK
INSERT
¿Qué tan enfermo quieres estar? La transmisión TDS no es tan difícil de proxy, lo hicimos para nuestra aplicación SaaS. El bit que está buscando (literalmente un bit) está en el mensaje login7. Puede hacer que sus usuarios se conecten a través de un proxy y registren / apliquen el bit allí. Demonios, incluso podrías encenderlo para ellos. :)
fuente
¿Su aplicación utiliza una cuenta de servicio o quizás varias cuentas de servicio? Si es así, use el evento extendido para monitorear su tráfico de inicio de sesión pero excluya sus cuentas de servicio en su servidor primario siempre activo. Ahora debería poder ver quién inicia sesión en el servidor primario siempre activo y no utiliza la cadena de conexión secundaria de solo lectura. Me estoy preparando para instalar Always-On y esto es lo que voy a hacer a menos que me digas que esto no funcionará.
fuente
Desafortunadamente, no tengo el entorno para probar lo siguiente, y sin duda hay varios puntos en los que puede fallar, pero lo arrojaré por lo que vale.
Un procedimiento almacenado CLR tiene acceso a la conexión actual a través de la
new SqlConnection("context connection=true")
construcción (tomada de aquí ). El tipo SqlConnection expone una propiedad ConnectionString . Dado que ApplicationIntent está en la cadena de conexión inicial, supongo que estará disponible en esta propiedad y se puede analizar. Hay muchas transferencias en esa cadena, por supuesto, así que muchas oportunidades para que todo tenga forma de pera.Esto se ejecutaría desde un Logon Trigger y los valores requeridos persistieron según sea necesario.
fuente