Processamos mensagens por meio de uma variedade de serviços (uma mensagem tocará provavelmente em 9 serviços antes de ser concluída, cada uma executando uma função específica de IO). No momento, temos uma combinação do pior caso (serialização de contrato de dados XML) e do melhor caso (MSMQ na memória) para desempenho.
A natureza da mensagem significa que nossos dados serializados terminam em torno de 12 a 15 kilobytes e processamos cerca de 4 milhões de mensagens por semana. As mensagens persistentes no MSMQ eram muito lentas para nós e, à medida que os dados aumentam, estamos sentindo a pressão dos arquivos mapeados na memória do MSMQ. O servidor tem 16 GB de uso de memória e está crescendo, apenas para filas. O desempenho também sofre quando o uso de memória é alto, pois a máquina começa a trocar. Já estamos fazendo o comportamento de auto-limpeza do MSMQ.
Sinto que há uma parte que estamos fazendo de errado aqui. Tentei usar o RavenDB para manter as mensagens e apenas enfileirar um identificador, mas o desempenho foi muito lento (1000 mensagens por minuto, na melhor das hipóteses). Não tenho certeza se isso é resultado do uso da versão de desenvolvimento ou o quê, mas definitivamente precisamos de uma taxa de transferência maior [1]. O conceito funcionou muito bem na teoria, mas o desempenho não estava à altura da tarefa.
O padrão de uso possui um serviço que atua como roteador, que faz todas as leituras. Os outros serviços anexarão informações com base no gancho de terceiros e retornarão ao roteador. A maioria dos objetos é tocada de 9 a 12 vezes, embora cerca de 10% sejam forçados a circular neste sistema por algum tempo até que terceiros respondam adequadamente. No momento, os serviços são responsáveis por isso e têm comportamentos adequados para dormir, pois utilizamos o campo prioritário da mensagem por esse motivo.
Então, minha pergunta, é o que é uma pilha ideal para a passagem de mensagens entre máquinas discretas, mas com LAN em um ambiente C # / Windows? Normalmente, eu começaria com BinaryFormatter em vez de serialização XML, mas isso é uma toca de coelho se a melhor maneira é descarregar a serialização em um repositório de documentos. Portanto, minha pergunta.
[1]: A natureza de nossos negócios significa que quanto mais cedo processarmos mensagens, mais dinheiro ganharemos. Empiricamente, provamos que processar uma mensagem no final da semana significa que temos menos chances de ganhar esse dinheiro. Embora o desempenho de "1000 por minuto" pareça bastante rápido, precisamos realmente desse número acima de 10k / minuto. Só porque eu estou dando números em mensagens por semana não significa que temos uma semana inteira para processar essas mensagens.
=============== editar:
Informação adicional
Com base nos comentários, adicionarei alguns esclarecimentos:
Não sei se a serialização é o nosso gargalo. Comparei o aplicativo e, embora a serialização apareça no gráfico de calor, ela é responsável por apenas 2,5 a 3% da utilização da CPU do serviço.
Estou mais preocupado com a permanência de nossas mensagens e com o possível uso indevido do MSMQ. Estamos usando mensagens não transacionais e não persistentes para que possamos manter o desempenho da fila, e eu realmente gostaria de ter pelo menos mensagens persistentes para que elas sobrevivam a uma reinicialização.
Adicionar mais RAM é uma medida paliativa. A máquina já passou de 4 GB -> 16 GB de RAM e está ficando cada vez mais difícil desativá-la para continuar adicionando mais.
Por causa do padrão de roteamento em estrela do aplicativo, na metade do tempo em que um objeto é populado e empurrado para uma fila, ele não muda. Isso se presta novamente (IMO) para armazená-lo em algum tipo de armazenamento de valor-chave em outro local e simplesmente passar identificadores de mensagem.
O padrão de roteamento em estrela é parte integrante do aplicativo e não será alterado. Não podemos centrá-lo no aplicativo, porque cada peça ao longo do caminho opera de forma assíncrona (de maneira polling) e queremos centralizar o comportamento de nova tentativa em um só lugar.
A lógica do aplicativo é escrita em C #, os objetos são POCOs imutáveis, o ambiente de implantação de destino é o Windows Server 2012 e podemos suportar máquinas adicionais se um determinado software for suportado apenas no Linux.
Meus objetivos são manter a taxa de transferência atual e reduzir o consumo de memória e aumentar a tolerância a falhas com um investimento mínimo de capital.