Recientemente realicé algunas pruebas de rendimiento y análisis de una aplicación ASP.NET usando estado de sesión fuera de proceso: esto es necesario cuando se usa el estado de sesión en una granja de servidores web para poder recuperar el estado cualquiera de los servidores web, por ejemplo si las solicitudes HTTP posteriores llegan a un servidor diferente porque las sesiones no son 'pegajosas' o el servidor original está inactivo, etc.Posibles soluciones a un rendimiento de serialización pobre
Lo que me sorprendió fue que cuando ejecuté los servidores web a plena carga y perfilé el uso de la CPU algo así como el 99% del tiempo de CPU se pasó serializando y deserializando el estado de la sesión. Posteriormente implementamos un servidor de estado 'caché' personalizado; esto siempre serializa el estado pero también mantiene el estado en la memoria, de modo que si usa sesiones adhesivas, el estado no tiene que deserializarse la mayor parte del tiempo. Este rendimiento mejorado del servidor por un factor de 2; Sin embargo, la serialización sigue representando el 98% o más del tiempo de CPU.
Obtuvimos algunas mejoras adicionales en la velocidad mediante el 'recorte' de referencias de objetos innecesarios entre los objetos en el estado de la sesión antes de la serialización, arreglando las referencias manualmente al finalizar la publicación. Esto mejoró la velocidad en otro 10-20% más o menos. El razonamiento aquí es que parte de la pérdida de rendimiento se debe a que la serialización integrada tiene que recorrer el gráfico de punteros de objeto, lo que se convierte en una tarea más compleja con más punteros.
Continuando con la investigación, escribimos rutinas de serialización personalizadas para algunas de nuestras clases en lugar de confiar en la serialización incorporada de .Net. Lo que encontramos fue que el rendimiento fue mejoró notablemente, por un factor de aproximadamente 50x. Parece que la mayor parte de la carga de la CPU está causada por la serialización .Net incorporada, que a su vez es lenta debido a la dependencia de usar Reflection para recorrer los punteros/gráficos del objeto y extraer datos de campo.
Es muy tentador aumentar nuestro rendimiento en 50x, reduciendo así los requisitos de hardware del servidor web por un factor grande (y los requisitos de potencia por un factor menor pero aún significativo). Las opciones actualmente son:
1) Escribir serialización personalizada. Este es un problema debido a la complejidad de la tarea y la sobrecarga de mantenimiento que genera, es decir, cualquier cambio al estado de clase requiere un cambio en las rutinas de serialización/deserialización.
2) Alguna solución de terceros. Tal vez algún producto que genere automáticamente código de guardar/cargar estado en tiempo de compilación, eliminando así la necesidad de utilizar Reflection.
Estaría muy interesado en saber si alguien sabe de una solución de un tercero, o se ha encontrado con este problema, ya que no he encontrado ninguna mención de ello en las búsquedas en Internet.
ACTUALIZACIÓN: Algunos han sugerido una especie de solución intermedia entre la serialización incorporada por defecto y las rutinas de serialización personalizadas puras. La idea es implementar la serialización personalizada para las clases que más afectan al rendimiento, p. superando ISerializable. Este es un enfoque interesante y prometedor; Sin embargo, todavía creo que hay espacio para un reemplazo completo de la serialización integrada sin tener que escribir y mantener ningún código personalizado; esto no se puede hacer en tiempo de ejecución porque Reflection es necesario para consultar objetos y acceder a datos privados. Pero teóricamente es posible posprocesar conjuntos ya construidos e inyectar nuevos métodos como un paso de construcción adicional. Algunos perfiladores utilizan este enfoque para inyectar código de creación de perfiles en ensamblados una vez que han sido compilados por el compilador de C#. También creo/leo en alguna parte que el .Net framework admite la inyección de métodos en clases, por lo que todo el juego con IL es potencialmente atendido.
Bastante seguro de que los métodos de inyección de los que está hablando serían el uso de clases parciales. Creo que el principio es si dos clases en el mismo espacio de nombres tienen el mismo nombre y una está marcada como parcial. Se produce una dll que incorpora métodos y propiedades de ambas clases. – Robert