Também postei esta pergunta no meu blog: http://www.sqldiablo.com/2012/04/15/service-broker-alwayson-availability-groups-odd-transmission-queue-behavior/ .
Tenho trabalhado em um projeto nos últimos meses que utilizará o Service Broker e os Grupos de Disponibilidade AlwaysOn para atender a algumas das metas de HA e DR da empresa em que trabalho (mais informações: http://www.sqldiablo.com/service-broker-replication/
). Recentemente, consegui implementar a solução completa em meu laboratório de desenvolvimento e apontar uma instância de nosso site para ela. Enquanto estávamos resolvendo alguns problemas em nosso banco de dados e site para que os dois funcionassem bem com meu projeto de replicação do Service Broker, comecei a perceber um comportamento estranho no Service Broker quando usado com Grupos de Disponibilidade AlwaysOn e queria fazer um blog sobre isso em uma tentativa de ver se mais alguém viu esse problema e pode ter uma ideia de como resolvê-lo.
A configuração:
Eu tenho um host Hyper-V executando 6 VMs do Windows Server 2008 R2 (BTDevSQLVM1-BTDevSQLVM6). As VMs são agrupadas em WSFCs de 2 nós com quorum de compartilhamento de arquivos e nós. Instalei instâncias autônomas do SQL 2012 Developer Edition em cada uma das VMs e criei um Grupo de Disponibilidade com um ouvinte em cada cluster (SBReplDistrib, SBRepl1 e SBRepl2).
Para o propósito desta postagem no blog, estarei focando na comunicação entre SBRepl1 e SBReplDistrib. A ilustração abaixo mostra os objetos Service Broker para cada lado da conversa:
(Sou novo e ainda não posso postar imagens, então veja meu blog no URL acima para a imagem)
Os pontos de extremidade e as rotas do Service Broker são configurados de acordo com este artigo do MSDN . A rota SBRepl_Receive no MSDB é para o serviço do servidor local (//SBReplDistrib/SBRepl em SBReplDistrib e //SBRepl1/SBRepl em SBRepl1) e aponta para a instância local. A rota SBRepl_Send no serviço de mapas SBRepl1 //SBReplDistrib/SBRepl para TCP://SBReplDistrib:4022, e a rota SBRepl_Send_SBRepl1 no SBReplDistrib é um mapeamento semelhante para o serviço no SBRepl1.
O comportamento esperado:
Meu entendimento de como o Service Broker lida com o envio e recebimento de mensagens é assim (isso é bastante simplificado. Há muito mais detalhes sobre esse processo no livro de Klaus Aschenbrenner, “Pro SQL Server 2008 Service Broker”):
- O aplicativo iniciador cria uma mensagem (neste caso, XML bem formado)
- Se houver uma conversa de diálogo existente entre o serviço iniciador e o serviço de destino que está no status de conversa, o aplicativo pode simplesmente enviar a mensagem no identificador de conversa existente. Caso contrário, o aplicativo iniciador deve iniciar uma conversa de diálogo entre o serviço iniciador e o serviço de destino e enviar a mensagem nesse identificador de conversa.
- A mensagem é colocada na tabela do sistema sys.transmission_queue e o Service Broker começa a fazer tentativas de entregar a mensagem ao serviço de destino.
- O Service Broker procura uma rota apropriada e ligação de serviço remoto e os usa para determinar o endereço ao qual se conectar para entregar a mensagem.
- O Service Broker abre uma conexão com o destino, autentica e entrega a mensagem ao agente de serviço de destino.
- O Service Broker de destino tenta classificar a mensagem e determinar qual serviço local manipulará a mensagem (ele usa dados de rota no banco de dados msdb para isso).
- O Service Broker de destino entrega a mensagem à fila do serviço de destino
- Depois que a mensagem é entregue com sucesso à fila de destino, o Service Broker de destino procura as informações de rota de volta ao iniciador e tenta entregar uma confirmação de que a mensagem foi recebida.
- O Service Broker do iniciador recebe a confirmação e usa as informações de roteamento no MSDB para determinar para qual serviço local a confirmação se destina.
- Após o roteamento bem-sucedido da confirmação para o serviço iniciador, a mensagem é removida da tabela do sistema sys.transmission_queue.
- Se o iniciador não receber uma confirmação de que a mensagem foi recebida, ele tentará periodicamente entregar a mensagem ao destino. Se o destino já tiver recebido a mensagem, ele simplesmente descartará todas as novas tentativas de entrega e enviará confirmações para elas.
O comportamento estranho:
A etapa 11 é onde estou vendo um comportamento muito estranho com o Service Broker e o AlwaysOn. Vejo a mensagem sendo entregue ao destino e processada com sucesso, e também vejo a confirmação sendo enviada de volta ao iniciador e recebida. No entanto, a mensagem permanece em sys.transmission_queue como se nenhuma confirmação tivesse sido recebida. Para tornar as coisas ainda mais estranhas, o Service Broker não está tentando reenviar a mensagem como eu esperaria se a confirmação não fosse recebida. Em vez disso, a mensagem simplesmente permanece na sys.transmission_queue e, à medida que novas mensagens são enviadas, elas são entregues, confirmadas e também permanecem na sys.transmission_queue. Parece-me que o service broker está recebendo as confirmações e, portanto, para de tentar entregar a mensagem, mas não a remove do sistema. Transmission_queue por algum motivo. O transmissão_status dessas mensagens permanece em branco, o que deve indicar que o Service Broker ainda não tentou entregá-las.
Verifiquei a configuração de retenção na fila de serviço e ela está desativada, mas isso deve afetar apenas a fila de serviço e não o sys.transmission_queue. Também rastreei os dois lados da conversa usando o SQL Profiler e posso ver a mensagem sendo enviada e a confirmação sendo enviada de volta ao iniciador e recebida (consulte dados de rastreamento XML no final desta postagem).
Uma coisa estranha saltou para mim nos traços, no entanto. Percebi que ambos os lados pareciam um pouco confusos sobre as conexões TCP, porque as mensagens são enviadas do endereço IP do próprio nó enquanto as rotas de serviço e as próprias mensagens apontam para o nome/IP do ouvinte do AG. Essa confusão parece estar fazendo com que cada lado feche a conexão existente entre os dois serviços e crie uma nova para entregar uma mensagem ou confirmação. Não tenho certeza se isso é normal ou não ou se tem algo a ver com o motivo pelo qual as confirmações não estão sendo tratadas corretamente, mas foi a única coisa que pude ver que poderia explicar o comportamento estranho.
O pedido de ajuda:
No momento, não tenho uma solução para esse problema de retenção de mensagens além de encerrar manualmente a conversa com a limpeza de ambos os lados, e isso não é realmente algo que desejo fazer. Se você tiver alguma ideia de por que isso pode estar acontecendo ou o que posso fazer a respeito, deixe um comentário e me avise. Se houver alguma informação adicional que você gostaria que eu fornecesse sobre minha configuração ou sobre o problema, informe-me nos comentários também. Vou postar um acompanhamento para esta postagem se / quando encontrar uma solução para esse problema.
Os dados de rastreamento:
Por favor, veja minha postagem no blog (o URL está no início da pergunta).
Nos últimos meses, tenho trabalhado com a equipe de suporte ao produto da Microsoft e eles reconheceram dois bugs no SQL Server 2012 em relação a esse problema. Eles lançarão patches para esses bugs como parte do próximo service pack do SQL Server 2012.