Eu tenho um grupo de disponibilidade AlwaysOn configurado e quero garantir que meus usuários estejam usando ApplicationIntent = ReadOnly em suas cadeias de conexão.
No SQL Server via DMVs (ou Eventos estendidos ou o que for), posso saber se um usuário conectado a ApplicationIntent = ReadOnly em sua cadeia de conexão?
Por favor, não responda como impedir conexões - não é sobre isso que se trata. Não posso simplesmente interromper as conexões, porque temos aplicativos existentes que estão se conectando sem a string correta e preciso saber quais são eles para poder trabalhar com os desenvolvedores e usuários para corrigi-los gradualmente ao longo do tempo.
Suponha que os usuários tenham vários aplicativos. Por exemplo, Bob se conecta ao SQL Server Management Studio e ao Excel. Ele se conecta ao SSMS quando precisa fazer atualizações e ao Excel quando precisa fazer leituras. Eu preciso ter certeza de que ele está usando ApplicationIntent = ReadOnly quando ele se conectar ao Excel. (Esse não é o cenário exato, mas é próximo o suficiente para ilustrar.)
fonte
sqlserver.read_only_route_complete
, pois é acionado apenas no primário.Respostas:
Captar o
sqlserver.read_only_route_complete
evento estendido mencionado por Kin e Remus, é um evento agradável de depuração , mas não carrega muita informação - apenasroute_port
(por exemplo, 1433) eroute_server_name
(por exemplo, sqlserver-0.contoso.com) por padrão . Isso também ajudaria a determinar quando uma conexão de intenção somente leitura foi bem-sucedida. Há umread_only_route_fail
evento, mas eu não consegui acioná-lo, talvez se houvesse um problema com o URL de roteamento, ele não parecia acionar quando a instância secundária estava indisponível / desligada, tanto quanto eu sabia.No entanto, tive algum sucesso ao associar isso ao
sqlserver.login
rastreamento de eventos e causalidade ativado, juntamente com algumas ações (comosqlserver.username
) para torná-lo útil.Passos para reproduzir
Crie uma sessão de Eventos estendidos para rastrear eventos relevantes, além de ações úteis e rastrear causalidade:
Execute a sessão XE (considere a amostragem, pois este é um evento de Depuração) e colete alguns logins:
Observe aqui que o sqlserver-0 é meu secundário legível e o sqlserver-1 o principal. Aqui, estou usando a
-K
opção desqlcmd
para simular logons de intenção de aplicativo somente leitura e alguns logons SQL. O evento somente leitura é acionado em um login de intenção somente leitura bem-sucedido.Ao pausar ou interromper a sessão, posso consultá-la e tentar vincular os dois eventos, por exemplo:
A consulta deve mostrar os logins com e sem a intenção somente leitura do aplicativo:
read_only_route_complete
é um evento de depuração, portanto use com moderação. Considere amostragem, por exemplo.Tentei fazer o
pair_matching
alvo funcionar, mas o tempo acabou. Há algum potencial de desenvolvimento aqui, algo como:fonte
Não, não parece haver nenhuma propriedade de conexão exposta ao DMV (em sys.dm_exec_connections ou sys.dm_exec_sessions ) ou mesmo CONNECTIONPROPERTY que esteja relacionado ao
ApplicationIntent
palavra-chave ConnectionString.No entanto, pode valer a pena solicitar, via Microsoft Connect, que essa propriedade seja adicionada à
sys.dm_exec_connections
DMV, pois parece ser uma propriedade da conexão armazenada em algum lugar na memória do SQL Server, com base nas seguintes informações encontradas na página MSDN para Suporte do SqlClient para alta disponibilidade e recuperação de desastres (ênfase em itálico):Se uma
USE
instrução puder ser verificada, éApplicationIntent
necessário que exista além da tentativa de conexão inicial. No entanto, eu não verifiquei pessoalmente esse comportamento.PS Eu estava pensando que poderíamos fazer uso dos fatos que:
USE
instrução for executada.A idéia era criar um novo banco de dados apenas com o objetivo de testar e rastrear essa configuração. O novo banco de dados seria usado em um novo grupo de disponibilidade que seria definido para permitir apenas
READ_WRITE
conexões. A teoria era que dentro de um gatilho de logon, umEXEC(N'USE [ReadWriteOnly]; INSERT INTO LogTable...;');
dentro de umaTRY...CATCH
construção, com essencialmente nada noCATCH
bloco, não produziria nenhum erro para conexões ReadWrite (que se registrariam no novo banco de dados) ou oUSE
erro nas conexões ReadOnly, mas então nada aconteceria desde que o erro foi detectado e desconsiderado (e aINSERT
declaração nunca seria alcançada). Nos dois casos, o evento de logon real não seria impedido / negado. O código do acionador de logon seria efetivamente:Infelizmente, ao testar o efeito da emissão de uma
USE
declaração dentro de umaEXEC()
dentro de umTRY...CATCH
interior de uma Transação, descobri que a violação de acesso foi um abort-nível de lote, e não um abort-nível de instrução. E configuraçãoXACT_ABORT OFF
não mudou nada. Até criei um procedimento armazenado SQLCLR simples para usarContext Connection = true;
e depois chameiSqlConnection.ChangeDatabase()
dentro de atry...catch
e a transação ainda foi abortada. E você não pode usarEnlist=false
na conexão de contexto. E usar uma conexão regular / externa no SQLCLR para sair da Transação não ajudaria, pois seria uma Conexão totalmente nova.Há uma possibilidade muito, muito pequena, de que o HAS_DBACCESS possa ser usado no lugar da
USE
instrução, mas eu realmente não tenho grandes esperanças de que seja capaz de incorporar as informações atuais da Conexão em suas verificações. Mas também não tenho como testá-lo.Obviamente, se houver um sinalizador de rastreamento que possa causar a violação de acesso sem interrupção de lote, o plano mencionado acima deverá funcionar ;-).
fonte
ROLLBACK
no Acesso de gatilho para umINSERT
em uma tabela log :-)Quão doente você quer estar? O fluxo TDS não é tão difícil de proxy, fizemos isso para nosso aplicativo SaaS. O bit que você está procurando (literalmente um pouco) está na mensagem de login7. Você pode fazer com que seus usuários se conectem por meio de um proxy e registrem / imponham o bit lá. Inferno, você pode até ligar para eles. :)
fonte
Seu aplicativo usa uma conta de serviço ou talvez várias contas de serviço? Nesse caso, use o Evento estendido para monitorar o tráfego de login, mas exclua suas contas de serviço no servidor primário sempre ativo. Agora você deve poder ver quem está efetuando login no servidor primário sempre ativo e não está usando a cadeia de conexão secundária somente leitura. Estou me preparando para instalar o Always-On e é isso que vou fazer, a menos que você me diga que isso não funcionará.
fonte
Infelizmente, não tenho o ambiente para testar o seguinte, e há, sem dúvida, vários pontos nos quais ele pode falhar, mas eu o divulgarei pelo que vale a pena.
Um procedimento armazenado CLR tem acesso à conexão atual por meio da
new SqlConnection("context connection=true")
construção (obtida daqui ). O tipo SqlConnection expõe uma propriedade ConnectionString . Como ApplicationIntent está na cadeia de conexão inicial, suponho que ele esteja disponível nesta propriedade e possa ser analisado. É claro que existem muitas desvantagens nessa cadeia, portanto há muitas oportunidades para que tudo corra em forma de pêra.Isso seria executado a partir de um gatilho de logon e os valores necessários persistiam conforme necessário.
fonte