Procesamos mensajes a través de una variedad de servicios (un mensaje tocará probablemente 9 servicios antes de que se realice, cada uno realizando una función específica relacionada con IO). En este momento tenemos una combinación del peor de los casos (serialización de contrato de datos XML) y el mejor de los casos (MSMQ en memoria) para el rendimiento.
La naturaleza del mensaje significa que nuestros datos serializados terminan entre 12 y 15 kilobytes, y procesamos alrededor de 4 millones de mensajes por semana. Los mensajes persistentes en MSMQ fueron demasiado lentos para nosotros y, a medida que crecen los datos, sentimos la presión de los archivos mapeados en memoria de MSMQ. El servidor tiene 16 GB de uso de memoria y está creciendo, solo para hacer cola. El rendimiento también sufre cuando el uso de memoria es alto, ya que la máquina comienza a intercambiar. Ya estamos haciendo el comportamiento de autolimpieza de MSMQ.
Siento que hay una parte que estamos haciendo mal aquí. Intenté usar RavenDB para persistir los mensajes y simplemente poner en cola un identificador, pero el rendimiento allí fue muy lento (1000 mensajes por minuto, en el mejor de los casos). No estoy seguro de si eso es el resultado del uso de la versión de desarrollo o qué, pero definitivamente necesitamos un mayor rendimiento [1]. El concepto funcionó muy bien en teoría, pero el rendimiento no estaba a la altura.
El patrón de uso tiene un servicio que actúa como un enrutador, que realiza todas las lecturas. Los otros servicios adjuntarán información basada en su enlace de terceros y lo enviarán de vuelta al enrutador. La mayoría de los objetos se tocan de 9 a 12 veces, aunque alrededor del 10% se ve obligado a dar vueltas en este sistema durante un tiempo hasta que los terceros responden adecuadamente. Los servicios ahora dan cuenta de esto y tienen comportamientos apropiados para dormir, ya que utilizamos el campo de prioridad del mensaje por este motivo.
Entonces, mi pregunta, ¿cuál es una pila ideal para el paso de mensajes entre máquinas discretas pero LAN en un entorno C # / Windows? Normalmente comenzaría con BinaryFormatter en lugar de la serialización XML, pero eso es un gran obstáculo si una mejor manera es descargar la serialización en un almacén de documentos. Por lo tanto, mi pregunta.
[1]: La naturaleza de nuestro negocio significa que cuanto antes procesamos los mensajes, más dinero ganamos. Hemos demostrado empíricamente que procesar un mensaje más adelante en la semana significa que es menos probable que ganemos ese dinero. Si bien el rendimiento de "1000 por minuto" suena bastante rápido, realmente necesitamos ese número de más de 10k / minuto. El hecho de que dé números en mensajes por semana no significa que tengamos una semana completa para procesar esos mensajes.
=============== editar:
Información Adicional
Según los comentarios, agregaré algunas aclaraciones:
No estoy seguro de que la serialización sea nuestro cuello de botella. He comparado la aplicación y, aunque la serialización aparece en el gráfico de calor, solo es responsable de aproximadamente el 2.5-3% de la utilización de la CPU del servicio.
Me preocupa principalmente la permanencia de nuestros mensajes y el posible uso indebido de MSMQ. Estamos utilizando mensajes no transaccionales y no persistentes para que podamos mantener el rendimiento de la cola, y realmente me gustaría tener al menos mensajes persistentes para que sobrevivan al reinicio.
Agregar más RAM es una medida provisional. La máquina ya pasó de 4 GB a> 16 GB de RAM y cada vez es más difícil desmontarla para seguir agregando más.
Debido al patrón de enrutamiento en estrella de la aplicación, la mitad del tiempo que aparece un objeto y luego lo empuja a una cola no cambia en absoluto. Esto se presta nuevamente (IMO) para almacenarlo en algún tipo de almacén de valores clave en otro lugar y simplemente pasar identificadores de mensaje.
El patrón de enrutamiento en estrella es parte integral de la aplicación y no cambiará. No podemos centipedearlo en la aplicación porque cada pieza en el camino funciona de forma asíncrona (en forma de sondeo) y queremos centralizar el comportamiento de reintento en un solo lugar.
La lógica de la aplicación está escrita en C #, los objetos son POCO inmutables, el entorno de implementación de destino es Windows Server 2012, y se nos permite poner en marcha máquinas adicionales si un software en particular solo es compatible con Linux.
Mis objetivos son mantener el rendimiento actual al tiempo que reduzco la huella de memoria y aumentan la tolerancia a fallas con un gasto mínimo de capital.