Diez reglas para matar el rendimiento del servidor IIS

  
                              

Cada una de las siguientes reglas afectará efectivamente el rendimiento y la escalabilidad de su código. En otras palabras, ¡trate de no seguir los mandamientos tanto como sea posible! A continuación, explicaré cómo destruirlos para mejorar el rendimiento y la escalabilidad.

1. Deben asignarse y liberarse múltiples objetos

Debe intentar evitar la sobre asignación de memoria, ya que la asignación de memoria puede ser costosa. La liberación de bloques de memoria puede ser más costosa porque la mayoría de los operadores de asignación siempre intentan conectar bloques de memoria liberados adyacentes en bloques más grandes. Hasta que Windows NT® 4.0 Service Pack 4.0, en el procesamiento de multiproceso, el montón del sistema generalmente funciona mal. El montón está protegido por un bloqueo global y no es extensible en sistemas multiprocesador.

2. No debe considerar el uso de la memoria caché del procesador.

La mayoría de las personas saben que las fallas de páginas difíciles causadas por los subsistemas de memoria virtual son costosas y es mejor evitarlas. Pero muchas personas piensan que no hay diferencia en otros métodos de acceso a la memoria. Desde 80486, esta vista no es correcta. Las CPU modernas son mucho más rápidas que la memoria RAM, la memoria RAM requiere al menos dos niveles de memoria caché, la memoria caché L1 de alta velocidad puede contener 8KB de datos y 8KB de instrucciones, mientras que la memoria caché L2 más lenta puede contener cientos de kilobytes de datos y códigos, combinados con datos y códigos. Juntos Una referencia a una región de memoria en la memoria caché L1 toma un ciclo de reloj, una referencia a la memoria caché L2 toma de 4 a 7 ciclos de reloj, y una referencia a la memoria principal requiere muchos ciclos de reloj del procesador. El último número pronto superará los 100 ciclos de reloj. En muchos sentidos, el almacenamiento en caché es como un pequeño sistema de memoria virtual de alta velocidad.

La unidad de memoria básica asociada con el almacenamiento en caché no es un byte sino una columna de caché. La columna de caché de Pentium tiene 32 bytes de ancho. La columna de caché alfa es de 64 bytes de ancho. Esto significa que solo hay 512 ranuras en el caché L1 para código y datos. Si se usan varios datos juntos (posición de tiempo) y no se almacenan juntos (ubicación espacial), el rendimiento será deficiente. La posición espacial de los arreglos es buena, y la lista de listas interconectadas y otras estructuras de datos basadas en punteros tienden a ser deficientes.

Empaquetar datos en la misma columna de caché generalmente mejorará el rendimiento, pero también degradará el rendimiento de los sistemas multiprocesador. Es difícil para el subsistema de memoria coordinar el almacenamiento en caché entre los procesadores. Si los datos de solo lectura utilizados por todos los procesadores comparten una columna de caché con los datos utilizados por un procesador y se actualizan con frecuencia, la caché tardará mucho tiempo en actualizar la copia de la columna de caché. A este juego de ping-pong de alta velocidad a menudo se le conoce como " sache cacheo " Si los datos de solo lectura están en una columna de caché diferente, se pueden evitar los saltos.

La optimización del espacio para el código es más eficiente que la optimización de la velocidad. Cuanto menos código hay, menos páginas ocupa el código, lo que requiere menos configuraciones de ejecución y menos fallos de página, y menos columnas de caché. Sin embargo, algunas funciones básicas deben ser optimizadas en velocidad. Los perfiladores se pueden utilizar para identificar estas funciones.
3. Nunca almacene en caché los datos utilizados frecuentemente.
El almacenamiento en caché del software puede ser utilizado por una variedad de aplicaciones. Cuando un cálculo es caro, guarda una copia del resultado. Este es un compromiso de tiempo-espacio típico: ahorre algo de tiempo sacrificando algo de espacio de almacenamiento. Si se hace bien, este enfoque puede ser muy eficaz.

Debes cachear correctamente. Si se almacenan en caché los datos incorrectos, se desperdicia el espacio de almacenamiento. Si cachea demasiado, habrá muy poca memoria disponible para otras operaciones. Si cachea muy poco, la eficiencia será baja porque tiene que volver a calcular los datos faltantes. Si los datos sensibles al tiempo se almacenan en la memoria caché durante demasiado tiempo, los datos estarán desactualizados. En general, los servidores están más preocupados por la velocidad que por el espacio, por lo que tienen más caché que los sistemas de escritorio. Asegúrese de eliminar los cachés no utilizados de forma regular, de lo contrario habrá problemas al ejecutar la configuración.

4. Deben crearse múltiples hilos, cuanto más, mejor.

Es importante ajustar la cantidad de subprocesos que funcionan en el servidor. Si el subproceso está enlazado a E /S, tomará mucho tiempo esperar a que se complete la E /S; un subproceso bloqueado es un subproceso que no realiza ningún trabajo útil. Agregar subprocesos adicionales puede aumentar el rendimiento, pero agregar demasiados subprocesos degradará el rendimiento del servidor porque el intercambio de contexto será una sobrecarga significativa. Hay tres razones por las que la velocidad de intercambio de contexto debería ser baja: el intercambio de contexto es una sobrecarga, y no hay beneficio para el trabajo de la aplicación; el intercambio de contexto se queda sin ciclos de reloj valiosos; lo peor de todo, el intercambio de contexto llena el caché del procesador Para datos inútiles, reemplazar estos datos es costoso.

Hay muchas cosas que dependen de tu estructura de hilos. Un hilo por cliente es absolutamente inapropiado. Porque no es escalable para un gran número de clientes. Los intercambios contextuales se vuelven insoportables y Windows NT se queda sin recursos. El modelo de grupo de subprocesos funcionará mejor, en el que un grupo de subprocesos de trabajo procesará una columna de solicitud porque Windows 2000 proporciona las API correspondientes, como QueueUserWorkItem.
5. Debería usar bloqueos globales en estructuras de datos

La forma más fácil de hacer que los hilos de datos sean seguros es ponerlos en un bloqueo grande. En aras de la simplicidad, todas las cosas utilizan el mismo bloqueo. Hay un problema con este enfoque: la serialización. Para obtener el bloqueo, cada subproceso que desee procesar los datos debe esperar en línea. Si el hilo está bloqueado por un bloqueo, no está haciendo nada útil. Este problema no es común cuando la carga en el servidor es liviana, porque solo un hilo a la vez necesita un bloqueo. En el caso de una carga pesada, la feroz competencia por las cerraduras puede convertirse en un gran problema.

Imagine un accidente en una carretera de varios carriles donde todos los vehículos de la carretera se convirtieron en una carretera estrecha. Si el vehículo es pequeño, el impacto de esta transición en la velocidad del flujo de tráfico es insignificante. Si hay muchos vehículos, los atascos de tráfico pueden extenderse por millas cuando el vehículo se une lentamente en ese carril único.

Existen varias técnicas para reducir la competencia de bloqueo.

· No sobreproteger, es decir, no es necesario bloquear los datos. Mantenga el candado solo cuando lo necesite y no demore demasiado. Es importante no usar bloqueos alrededor de grandes trozos de código o en código ejecutado con frecuencia.
· Divida los datos para que puedan protegerse con un conjunto separado de bloqueos. Por ejemplo, una tabla de símbolos se puede dividir por la primera letra del identificador, de modo que cuando se modifica el valor de un símbolo cuyo nombre comienza con Q, no se lee el valor del símbolo cuyo nombre comienza con H.
· Utilice la serie de API de interbloqueo (InterlockedIncrement, InterlockedCompareExchangePointer, etc.) para modificar automáticamente los datos sin la necesidad de un bloqueo.
· Los bloqueos de lector único /escritor múltiple pueden usarse cuando los datos no se modifican con frecuencia. Obtendrá una mejor concurrencia, aunque el costo de la operación de bloqueo será más alto y puede correr el riesgo de matar de hambre al autor.
· Usa el contador de bucles en partes clave. Consulte la API SetCriticalSectionSpinCount en el Service Pack 3 de Windows NT 4.0.
· Si no puede obtener el bloqueo, use TryEnterCriticalSection y haga algún otro trabajo útil.
La alta competencia conduce a la serialización, y la serialización conduce a una menor utilización de la CPU, lo que incita a los usuarios a unirse a más subprocesos y las cosas empeoran.

6. No preste atención a las máquinas multiprocesador.

Su código se ejecuta peor en los sistemas multiprocesador que en los sistemas con un solo procesador, lo que puede ser asqueroso. Las cosas Una idea natural es que sería mejor ejecutar N veces en un sistema N-dimensional. El motivo del bajo rendimiento es la competencia: la competencia de bloqueo, la contención de bus y /o la competencia de columna de caché. Los procesadores compiten por la propiedad de los recursos compartidos en lugar de hacer más trabajo.

Si debe escribir una aplicación de múltiples subprocesos, debe realizar pruebas de resistencia y pruebas de rendimiento en su aplicación en una caja de multiprocesador. Un solo sistema de procesador proporciona un artefacto de concurrencia ejecutando subprocesos en intervalos de tiempo. Las cajas multiprocesador tienen verdadera concurrencia, y es más probable que se produzcan entornos competitivos y competitivos.
7. Las llamadas modulares siempre deben usarse, son interesantes.

El uso de llamadas modulares síncronas para realizar operaciones de E /S es apropiado para la mayoría de las aplicaciones de escritorio. Sin embargo, no son una buena forma de utilizar la (s) CPU (s) en el servidor. Las operaciones de E /S requieren millones de ciclos de reloj para completarse, y estos ciclos de reloj podrían haberse utilizado mejor. Con la E /S asíncrona puede obtener tasas de solicitud de usuario y rendimiento de E /S significativamente mayores, pero con una complejidad adicional agregada.

Si tiene llamadas modulares u operaciones de E /S que llevan mucho tiempo, debe probar cuántos recursos están asignados a ellas. ¿Quieres usar todos los hilos o tienes un límite? En general, es mejor utilizar un número limitado de subprocesos. Cree un grupo y una cola de subprocesos pequeños, utilizando la cola para programar el trabajo del subproceso para completar la llamada modular. De esta manera, otros subprocesos pueden recoger y procesar sus solicitudes no modulares.

8. No mida

Cuando puede medir lo que está hablando y expresarlo con números, esto significa que tiene cierta comprensión de él, pero si no puede usar números Cuando expresas, tu conocimiento es insatisfactorio e insatisfactorio, este puede ser el comienzo del conocimiento, pero es simplemente imposible que eleves tu mente al nivel de la ciencia.

- Lord Kelvin (William Thomson)

Si no mide, no puede entender las características de la aplicación. Estás a tientas en la oscuridad, medio adivinando. Si no identifica problemas de rendimiento, no puede realizar ninguna mejora o hacer un plan de carga de trabajo.

Las mediciones incluyen medición de caja negra y perfiles. Medición de caja negra significa recopilar datos mostrados por contadores de rendimiento (uso de memoria, intercambio de contexto, uso de CPU, etc.) y herramientas de inspección externa (flujo, tiempo de reflexión, etc.). Para crear un perfil de su código, compila una versión de la herramienta del código, luego lo ejecuta en varias condiciones y recopila estadísticas sobre el tiempo de ejecución y la frecuencia de llamadas de proceso.

Las mediciones no son útiles si no se utilizan para el análisis. La medición no solo le dirá que hay un problema, sino que incluso puede ayudarlo a descubrir dónde está el problema, pero no puede decirle por qué hay un problema. Analiza el problema para que puedas corregirlo correctamente. Es necesario resolver el problema fundamentalmente en lugar de permanecer en la superficie.

Cuando realiza cambios, debe volver a medir. Necesitas saber si tus cambios son válidos. Los cambios también pueden exponer otros problemas de rendimiento, y el ciclo de medición-análisis-corrección-re-medición comenzará nuevamente. También debe realizar mediciones regularmente para encontrar problemas de degradación del rendimiento.
9. Se debe utilizar un solo usuario, método de prueba de solicitud única.

Un problema común al escribir aplicaciones ASP e ISAPI es probar la aplicación con un solo navegador. Cuando aplicaron sus programas en Internet, descubrieron que sus aplicaciones no podían manejar grandes cargas y que el rendimiento y el tiempo de respuesta eran lamentables.

Es necesario probar con un navegador, pero no es suficiente. Si el navegador no reacciona lo suficientemente rápido, sabes que estás en problemas. Pero incluso si es rápido cuando usa un navegador, no sabe qué tan bien maneja la carga. ¿Qué sucede si más de una docena de usuarios solicitan al mismo tiempo? Cien? ¿Qué tipo de rendimiento puede tolerar su aplicación? ¿Qué tipo de tiempo de reacción proporciona? ¿Qué pasará con estos números en cargas ligeras? ¿Qué pasa con la carga media? Sobrecargado? ¿Qué sucede con su aplicación en una máquina multiprocesador? La prueba de intensidad de su aplicación es fundamental para encontrar errores y encontrar problemas de rendimiento.
Se aplican consideraciones similares de prueba de carga a todas las aplicaciones del servidor.

10. El entorno real no debe utilizarse.

Las personas tienden a modificar las aplicaciones solo en algunos entornos artificiales específicos (como los puntos de referencia). Es importante elegir las diversas situaciones que corresponden a la situación real y optimizar para cada operación. Si no hace esto, sus usuarios y críticos definitivamente lo harán y lo usarán para juzgar la calidad de su aplicación.

Copyright © Conocimiento de Windows All Rights Reserved