visual tutorial studio net mvc for español asp asp.net-mvc performance reporting scalability

asp.net mvc - tutorial - En asp.net-mvc, ¿cuál es la forma correcta de realizar operaciones costosas sin afectar a otros usuarios?



mvc 5 visual studio 2017 (8)

Creo que una herramienta / biblioteca como Hangfire es lo que estás buscando. Primero, le permitirá especificar una tarea ejecutada en un subproceso en segundo plano (en la misma aplicación / proceso). El uso de varias técnicas, como SignalR permite la notificación de front-end en tiempo real.

Sin embargo, algo que configuré después de usar Hangfire durante casi un año fue dividir el procesamiento (y la implementación) de nuestro trabajo a otro servidor mediante esta documentación. Utilizo una aplicación MVC de ASP.NET interna para procesar trabajos en un servidor diferente. El único cuello de botella del rendimiento, entonces, es si ambos servidores utilizan el mismo almacén de datos (por ejemplo, la base de datos). Si está bloqueando la base de datos, la única forma de evitarlo es minimizar el bloqueo de dicho recurso, independientemente de la metodología que utilice.

Uso interfaces para desencadenar trabajos, almacenados en una biblioteca común:

public interface IMyJob { MyJobResult Execute( MyJobSettings settings ); }

Y, el disparador, que se encuentra en la aplicación frontal:

//tell the job to run var settings = new MyJobSettings(); _backgroundJobClient.Enqueue<IMyJob>( c => c.Execute( settings ) );

Luego, en mi servidor de fondo, escribo la implementación (y la coloco en el contenedor Autofac IOC que estoy usando):

public class MyJob : IMyJob { protected override MyJobResult Running( MyJobSettings settings ) { //do stuff here } }

No me he metido demasiado en intentar que SignalR funcione en los dos servidores, ya que todavía no he encontrado ese caso de uso específico, pero me imagino que es teóricamente posible.

Hice esta pregunta hace aproximadamente 5 años acerca de cómo "descargar" operaciones costosas en las que los usuarios no necesitan esperar (como auditorías, etc.) para que obtengan una respuesta más rápida.

Ahora tengo una pregunta relacionada pero diferente. En mi asp.net-mvc, he creado algunas páginas de informes en las que puede generar informes de Excel ( estoy usando EPPlus ) e informes de PowerPoint ( estoy usando aspose.slides ). Aquí hay un ejemplo de acción del controlador:

public ActionResult GenerateExcelReport(FilterParams args) { byte[] results = GenerateLargeExcelReportThatTake30Seconds(args); return File(results, @"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", "MyReport.xlsx"); }

La funcionalidad funciona muy bien, pero estoy tratando de averiguar si estas operaciones caras (algunos informes pueden tardar hasta 30 segundos en volver) están afectando a otros usuarios. En la pregunta anterior, tuve una operación costosa que el usuario DIDN "T tiene que esperar, pero en este caso él tiene que esperar, ya que es una actividad sincrónica (haga clic en Generar informe y la expectativa es que los usuarios obtengan un informe cuando finalice). )

En este caso, no me importa que el usuario principal tenga que esperar 30 segundos, pero solo quiero asegurarme de que no esté afectando negativamente a otros usuarios debido a esta operación costosa, la generación de archivos, etc.

¿Hay alguna práctica recomendada aquí en asp.net-mvc para este caso de uso?


Debe monitorear a los usuarios de su aplicación para saber si otros usuarios se están viendo afectados, por ejemplo, al registrar los tiempos de respuesta

Si descubre que esto está afectando a otros usuarios, debe ejecutar la tarea en otro proceso, posiblemente en otra máquina. Puede utilizar la biblioteca Hangfire para lograr esto.


En general, podría considerarse una buena práctica ejecutar tareas de larga ejecución en segundo plano y proporcionar algún tipo de notificación al usuario cuando se realiza el trabajo. Como probablemente sepa, el tiempo de ejecución de la solicitud web está limitado a 90 segundos, por lo que si su tarea de ejecución prolongada podría exceder esto, no tiene más remedio que ejecutar en otro proceso / proceso. Si está utilizando .net 4.5.2, puede usar HostingEnvironment.QueueBackgroundWorkItem para ejecutar tareas de larga ejecución en segundo plano y usar SignalR para notificar al usuario cuando la tarea haya finalizado la ejecución. En caso de que esté generando un archivo, puede almacenarlo en el servidor con una ID única y enviar al usuario un enlace para descargarlo. Puede eliminar este archivo más tarde (con algunos servicios de Windows, por ejemplo).

Como lo mencionaron otros, hay algunos corredores de tareas en segundo plano más avanzados, como Hangfire, Quartz.Net y otros, pero el concepto general es el mismo: ejecute la tarea en segundo plano y notifique al usuario cuando haya terminado . Aquí hay un buen article sobre diferentes opciones para ejecutar tareas en segundo plano.


Necesitas usar async y esperar de C # .

A partir de su pregunta, pensé que está preocupado por el hecho de que la solicitud puede tomar más recursos de los que debería, en lugar de escalabilidad. Si ese es el caso, haga que las acciones de su controlador sean asíncronas, así como todas las operaciones a las que llama, siempre y cuando involucren llamadas que bloqueen subprocesos. por ejemplo, si sus solicitudes pasan por cables o operaciones de E / S, bloquearán el subproceso sin asíncrono (técnicamente, lo hará, ya que esperará la respuesta antes de continuar). Con async, esos subprocesos están disponibles (mientras esperan la respuesta), por lo que potencialmente pueden atender otras solicitudes de otros usuarios.

Asumí que no estás vagando sobre cómo escalar las solicitudes. Si es así, avíseme, y también puedo proporcionar detalles sobre eso (demasiado para escribir a menos que sea necesario).


Ponga en cola los trabajos en una tabla y haga que un proceso en segundo plano haga una encuesta en esa tabla para decidir qué trabajo muy grande necesita ejecutar a continuación. Luego, su cliente web necesitaría sondear el servidor para determinar cuándo se completó el trabajo (posiblemente al marcar un indicador en la base de datos, pero existen otros métodos). Esto garantiza que no tendrá más de uno (o muchos otros). decidir es apropiado) de estos costosos procesos que se ejecutan a la vez.

Hangfire y SignalR pueden ayudarlo aquí, pero un mecanismo de colas es realmente necesario para evitar interrupciones importantes cuando, por ejemplo, cinco usuarios solicitan este mismo proceso al mismo tiempo. Los enfoques mencionados que activan nuevos procesos o procesos en segundo plano no parecen proporcionar ningún mecanismo para minimizar el consumo del procesador / memoria para evitar interrumpir a otros usuarios debido a que consumen demasiados recursos.


Puedes probar la combinación de Hangfire y SignalR. Use Hangfire para iniciar un trabajo en segundo plano y renunciar a la solicitud http. Y una vez que la generación de informes esté completa, use SignalR para generar una notificación de inserción.

Notificación de SignalR del servidor al cliente

La opción alternativa es implementar un mecanismo de sondeo en el lado del cliente. Envíe una llamada ajax para iniciar un trabajo de hangfire para generar el informe. Y luego comience a sondear algunas api usando otra llamada ajax que proporcione el estado y, tan pronto como el informe esté listo, recupérelo. Prefiero usar SignalR en lugar de sondear.

Si el procesamiento de informes afecta el rendimiento en el servidor web, descargue ese procesamiento a otro servidor. Puede usar la mensajería (ActiveMQ o RabbitMQ o algún otro marco de su elección) o la llamada api de reposo para iniciar la generación de informes en otro servidor y luego usar nuevamente la llamada api de mensajería o reposo para notificar la finalización de la generación de informes al servidor web, finalmente SignalR para notificar al cliente. Esto permitirá que el servidor web sea más receptivo.

ACTUALIZACIÓN Sobre tu pregunta.

¿Hay alguna práctica recomendada aquí en asp.net-mvc para este caso de uso?

Tienes que controlar tu aplicación en horas extras. Monitorear tanto el lado del cliente como el lado del servidor. Hay pocas herramientas en las que puede confiar, como newrelic, la dinámica de aplicaciones. He usado newrelic y tiene características para rastrear problemas tanto en el navegador del cliente como en el servidor. Los nombres del producto son "NewRelic Browser" y "NewRelic Server". Estoy seguro de que hay otras herramientas que capturarán información similar.

Analice las métricas a lo largo del tiempo y si observa alguna anomalía, tome las medidas apropiadas. Si observa picos de memoria y CPU del lado del servidor, intente capturar métricas en el lado del cliente en el mismo período de tiempo. Del lado del cliente, si observa algún problema de tiempo de espera, los errores de conexión significan que los usuarios de su aplicación no pueden conectarse a su aplicación mientras el servidor está haciendo un gran trabajo. A continuación, intente identificar cuellos de botella del lado del servidor. Si no hay suficiente espacio para ajustar el código de rendimiento, realice un ejercicio de planificación de la capacidad del servidor y descubra cómo escalar más su hardware o mover los trabajos en segundo plano fuera de los servidores web para reducir la carga. La simple captura de métricas usando estas herramientas puede no ser suficiente, es posible que tenga que instrumentar (capturar registros) su aplicación para capturar métricas adicionales para monitorear adecuadamente el estado de la aplicación.

Here puede encontrar información sobre la planificación de la capacidad de la aplicación .net de Microsoft.

-Vinod.


Todas estas son grandes ideas sobre cómo hacer que el trabajo salga del ciclo de solicitud / respuesta. Pero creo que @leora simplemente quiere saber si una solicitud de larga duración afectará negativamente a otros usuarios de una aplicación asp.net.

La respuesta es no. asp.net es multiproceso. Cada solicitud es manejada por un hilo de trabajo separado.


Usando esa respuesta, puedes declarar una tarea con baja prioridad

bajando la prioridad del hilo Task.Factory.StartNew

public ActionResult GenerateExcelReport(FilterParams args) { byte[] result = null; Task.Factory.StartNew(() => { result = GenerateLargeExcelReportThatTake30Seconds(args); }, null, TaskCreationOptions.None, PriorityScheduler.BelowNormal) .Wait(); return File(result, @"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", "MyReport.xlsx"); }