Estamos tentando fazer com que o Service Broker funcione em nosso ambiente para resolver um caso de negócios. Não sei se o título da mensagem é bom, mas minha pergunta está abaixo. Mas pode não ser uma boa pergunta, então, depois disso, é o que estamos fazendo e por que acho que é a pergunta certa.
Quantas mensagens devem ser enviadas em uma conversa antes de terminar a conversa?
Queremos usar o Service Broker para atualizar de forma assíncrona uma tabela de resultados. A tabela de resultados é achatada e rápida. Temos gatilhos nas tabelas base que enviam uma mensagem com sua tabela e chave primária. Temos três filas:
- Baixa latência - o objetivo é de 15 segundos para processar. Ele lida com itens que mudam relacionados a um item específico.
- Fila em massa - o objetivo é de 5 minutos para processar. Ele lida com quando algo muda que afeta muitas centenas (ou milhares) de itens. Ele divide a lista de itens que foram afetados e os alimenta na Fila de Baixa Latência Adiada
- Baixa Latência Adiada - o objetivo é 30 minutos para processar. Isso processa itens, mas apenas da fila em massa.
Basicamente, se as informações de um cliente forem atualizadas; isso afeta muitos produtos e é enviado para a fila em massa para um processamento mais lento. No entanto, se um produto é atualizado, ele é enviado para a fila de baixa latência.
Reutilizamos conversas semelhantes ao blog de Remus Rusanu http://rusanu.com/2007/04/25/reusing-conversations/ , com a exceção de que o fazemos com base no módulo da chave primária. Isso tem o benefício de ajudar na desduplicação de chaves primárias.
Portanto, estamos reutilizando as conversas e estamos dentro das nossas diretrizes. Com dois threads, consegui gravar 125 mensagens / segundo (queda artificial de vários milhares de mensagens), o que é mais do que capaz de acompanhar a produção (est. 15 mensagens / s).
No entanto, o problema que estamos enfrentando é que, após um período de tempo, ~ 4 horas ou 120 mil mensagens, começamos a ver blocos e alta contenção no sysdesend e na tabela de filas. Os bloqueios são LCK_M_U e são bloqueios KEY. Às vezes, o hobt resolve sysdesend e outras vezes para a tabela de filas específica (fila_).
Temos um processo em andamento que encerra as conversas após 24 horas ou 30 minutos de inatividade, para podermos aumentar o tempo antes de alternar as conversas.
Estamos usando o SQL 2016 Enterprise (13.0.4001.0)
- Disparar disparos (enviar para baixa latência ou volume)
- Procure ou crie um identificador de conversa.
- enviar mensagem
- Procedimento ativado da fila
- Atualizar tabela de resultados
O processo de limpeza é executado a cada 10 minutos para verificar se há alguma conversa ociosa. se os encontrar mais de três vezes seguidas, marcará como inativo e encerrará as conversas.
Informe-me se houver algum detalhe adicional que possa ser benéfico. Como não tenho muita experiência com o Service Broker, não sei se nossas mensagens / s são baixas, altas ou indiferentes.
ATUALIZAR
Por isso, tentamos novamente hoje e encontramos o mesmo problema. Alteramos o tempo de vida da conversa para 2 horas e isso não teve efeito. Então, implementamos o truque 150; que teve o mesmo problema.
Toneladas de esperas em SEND CONVERSATION, aguardando sysdesend. Alguém tem mais alguma idéia?
ATUALIZAÇÃO 2
Realizamos o teste por mais tempo hoje e, durante um período de amostra de 17 minutos, processamos 41 mil mensagens em quatro identificadores de conversa. Conseguimos acompanhar, exceto no final, quando os bloqueios no sysdesend e a tabela da fila ficaram muito altos e começamos a nos afastar antes de pará-lo. Parece que não temos problemas ao processar mensagens, sem que as coisas entrem na fila, podemos retirá-las e processá-las pelo menos 5x dessa velocidade. Nossa velocidade parece ser limitada com base na adição de mensagens.
Em um teste posterior, removemos um dos gatilhos que representavam 80% das mensagens. Mesmo com essa carga muito reduzida, começamos a ver as mesmas esperas.
ATUALIZAÇÃO 3
Obrigado, Remus pelo seu conselho (e obrigado por postar artigos excelentes no blog sobre o assunto, eles foram fundamentais para chegar a esse ponto).
Corremos novamente hoje e fizemos melhor (como demoramos mais para ver as esperas e ainda mais antes que isso nos paralisasse). Então, os detalhes.
Alteramos: * Aumentamos o número de conversas mantidas por thread de 1: 1 para 2: 1. Basicamente, tivemos 8 identificadores de conversa para 4 threads.
- consolidou a fila em massa (porque uma mensagem recebida pode significar centenas de mensagens enviadas) para consolidar em menos mensagens maiores.
Notas sobre esta tentativa:
desativando o procedimento de ativação da fila de destino. nenhuma alteração no bloqueio (esperamos 5 minutos) e as mensagens foram enviadas para sys.transmission_queues.
monitorando sys.conversation_endpoints. Esse número passou de 0 13K muito rapidamente e aumentou mais lentamente ao longo do dia, terminando em torno de 25K após ~ 5 horas. O bloqueio não começou a ocorrer até atingir 16K +/-
Entrei no DAC e executei os comandos DBREINDEX para as filas, embora, a partir de uma consulta, os registros fantasmas nunca chegassem a mais ou menos 200 antes da limpeza, e a contagem caiu para 0.
sysdesend e sysdercv tinham contagens idênticas de 24.932 quando terminei o teste.
processamos ~ 310K mensagens em 5 horas.
Nós demoramos tanto para as coisas desmoronarem que eu realmente pensei que conseguiríamos dessa vez. Amanhã tentaremos forçar as mensagens a passar pelo fio.
sys.conversation_endpoints
durante o teste (constante ou está aumentando e qual o tamanho quando o bloqueio ocorre). 2) Quando o bloqueio ocorre, a desativação da fila de destino faz diferença no bloqueio SEND (a desativação da fila deve rotear SEND para sys.transmission_queue). e 3) Forçar as mensagens a serem transmitidas, mesmo localmente (configure o ponto de extremidade SSB, adicione rotas) altera o comportamento a longo prazo
ALTER QUEUE ... REBUILD
faz diferença quando o bloqueio é iniciado?
we started seeing blocks and high contention on sysdesend and the queue table.
-> Qual é o tipo de espera -PAGELATCH_EX/SH and WRITELOG
? Você já usou o truque 150 ? Se as tabelas do sistema são o seu ponto de discórdia, o truque 150 será altamente útil.