Rendimiento de las aplicaciones de red Linux. Introducción

Las aplicaciones web ahora se utilizan en todas partes y, entre todos los protocolos de transporte, HTTP ocupa la mayor parte. Al estudiar los matices del desarrollo de aplicaciones web, la mayoría de la gente presta muy poca atención al sistema operativo donde realmente se ejecutan estas aplicaciones. La separación de desarrollo (Dev) y operaciones (Ops) sólo empeoró la situación. Pero con el auge de la cultura DevOps, los desarrolladores se están volviendo responsables de ejecutar sus aplicaciones en la nube, por lo que les resulta muy útil familiarizarse a fondo con el backend del sistema operativo. Esto es especialmente útil si intenta implementar un sistema para miles o decenas de miles de conexiones simultáneas.

Las limitaciones de los servicios web son muy similares a las de otras aplicaciones. Ya sean balanceadores de carga o servidores de bases de datos, todas estas aplicaciones tienen problemas similares en un entorno de alto rendimiento. Comprender estas limitaciones fundamentales y cómo superarlas en general le ayudará a evaluar el rendimiento y la escalabilidad de sus aplicaciones web.

Estoy escribiendo esta serie de artículos en respuesta a preguntas de jóvenes desarrolladores que desean convertirse en arquitectos de sistemas bien informados. Es imposible comprender claramente las técnicas de optimización de aplicaciones de Linux sin profundizar en los conceptos básicos de cómo funcionan a nivel del sistema operativo. Aunque hay muchos tipos de aplicaciones, en esta serie quiero explorar aplicaciones basadas en web en lugar de aplicaciones de escritorio como un navegador o un editor de texto. Este material está destinado a desarrolladores y arquitectos que desean comprender cómo funcionan los programas Linux o Unix y cómo estructurarlos para lograr un alto rendimiento.

linux es Cuarto de servicio sistema operativo y, en la mayoría de los casos, sus aplicaciones se ejecutan en este sistema operativo. Aunque digo "Linux", la mayoría de las veces puedes asumir con seguridad que me refiero a todos los sistemas operativos tipo Unix en general. Sin embargo, no he probado el código adjunto en otros sistemas. Entonces, si está interesado en FreeBSD u OpenBSD, sus resultados pueden variar. Cuando pruebo algo específico de Linux, lo señalo.

Si bien puedes utilizar este conocimiento para crear una aplicación desde cero y estará perfectamente optimizada, es mejor no hacerlo. Si escribe un nuevo servidor web en C o C++ para la aplicación empresarial de su organización, este puede ser su último día de trabajo. Sin embargo, conocer la estructura de estas aplicaciones le ayudará a elegir los programas existentes. Podrá comparar sistemas basados ​​en procesos con sistemas basados ​​en subprocesos y con sistemas basados ​​en eventos. Comprenderá y apreciará por qué Nginx funciona mejor que Apache httpd, por qué una aplicación Python basada en Tornado puede servir a más usuarios en comparación con una aplicación Python basada en Django.

ZeroHTTPd: herramienta de aprendizaje

CeroHTTPd es un servidor web que escribí desde cero en C como herramienta de enseñanza. No tiene dependencias externas, incluido el acceso a Redis. Ejecutamos nuestros propios procedimientos de Redis. Consulte a continuación para obtener más detalles.

Aunque podríamos discutir la teoría extensamente, no hay nada mejor que escribir código, ejecutarlo y comparar todas las arquitecturas de servidores entre sí. Este es el método más obvio. Por lo tanto, escribiremos un servidor web ZeroHTTPd simple utilizando cada modelo: basado en procesos, basado en subprocesos y basado en eventos. Revisemos cada uno de estos servidores y veamos cómo funcionan en comparación entre sí. ZeroHTTPd se implementa en un único archivo C. El servidor basado en eventos incluye utash, una excelente implementación de tabla hash que viene en un único archivo de encabezado. En otros casos no existen dependencias, para no complicar el proyecto.

Hay muchos comentarios en el código para ayudarlo a comprender. Al ser un servidor web simple en unas pocas líneas de código, ZeroHTTPd es también un marco mínimo para el desarrollo web. Tiene una funcionalidad limitada, pero es capaz de servir archivos estáticos y páginas "dinámicas" muy simples. Debo decir que ZeroHTTPd es bueno para aprender a crear aplicaciones Linux de alto rendimiento. En general, la mayoría de los servicios web esperan solicitudes, las verifican y las procesan. Esto es exactamente lo que hará ZeroHTTPd. Esta es una herramienta para aprender, no para producir. No es muy bueno en el manejo de errores y es poco probable que cuente con las mejores prácticas de seguridad (oh, sí, usé strcpy) o los ingeniosos trucos del lenguaje C. Pero espero que haga bien su trabajo.

Rendimiento de las aplicaciones de red Linux. Introducción
Página de inicio de ZeroHTTPd. Puede generar diferentes tipos de archivos, incluidas imágenes.

Solicitud de libro de visitas

Las aplicaciones web modernas no suelen limitarse a archivos estáticos. Tienen interacciones complejas con varias bases de datos, cachés, etc. Por lo tanto, crearemos una aplicación web sencilla llamada "Libro de visitas" donde los visitantes dejan entradas bajo sus nombres. El libro de visitas almacena las entradas dejadas anteriormente. También hay un contador de visitantes en la parte inferior de la página.

Rendimiento de las aplicaciones de red Linux. Introducción
Aplicación web "Libro de visitas" ZeroHTTPd

El contador de visitantes y las entradas del libro de visitas se almacenan en Redis. Para las comunicaciones con Redis se implementan procedimientos propios, no dependen de la biblioteca externa. No soy un gran partidario de implementar código casero cuando hay soluciones disponibles públicamente y bien probadas. Pero el propósito de ZeroHTTPd es estudiar el rendimiento de Linux y el acceso a servicios externos, mientras que atender solicitudes HTTP tiene un impacto grave en el rendimiento. Debemos controlar totalmente las comunicaciones con Redis en cada una de nuestras arquitecturas de servidores. En algunas arquitecturas utilizamos llamadas de bloqueo, en otras utilizamos procedimientos basados ​​en eventos. El uso de una biblioteca cliente de Redis externa no proporcionará este control. Además, nuestro pequeño cliente Redis solo realiza algunas funciones (obtener, configurar e incrementar una clave; obtener y agregar a una matriz). Además, el protocolo Redis es extremadamente elegante y sencillo. Ni siquiera necesitas enseñarlo especialmente. El mero hecho de que el protocolo haga todo el trabajo en unas cien líneas de código demuestra lo bien pensado que está.

La siguiente figura muestra lo que hace la aplicación cuando el cliente (navegador) solicita /guestbookURL.

Rendimiento de las aplicaciones de red Linux. Introducción
Cómo funciona la aplicación del libro de visitas

Cuando es necesario publicar una página del libro de visitas, hay una llamada al sistema de archivos para leer la plantilla en la memoria y tres llamadas de red a Redis. El archivo de plantilla contiene la mayor parte del contenido HTML de la página en la captura de pantalla anterior. También hay marcadores de posición especiales para la parte dinámica del contenido: publicaciones y contador de visitantes. Los recibimos de Redis, los insertamos en la página y proporcionamos al cliente el contenido completo. La tercera llamada a Redis se puede evitar porque Redis devuelve el nuevo valor clave cuando se incrementa. Sin embargo, para nuestro servidor, que tiene una arquitectura asincrónica basada en eventos, muchas llamadas de red son una buena prueba con fines de aprendizaje. Entonces descartamos el valor de retorno de Redis del número de visitantes y lo consultamos con una llamada separada.

Arquitecturas de servidor ZeroHTTPd

Estamos creando siete versiones de ZeroHTTPd con la misma funcionalidad pero con diferentes arquitecturas:

  • Iterativo
  • Servidor fork (un proceso hijo por solicitud)
  • Servidor previo a la bifurcación (prebifurcación de procesos)
  • Servidor con hilos de ejecución (un hilo por solicitud)
  • Servidor con creación previa al hilo
  • Basado en arquitectura poll()
  • Basado en arquitectura epoll

Medimos el rendimiento de cada arquitectura cargando el servidor con solicitudes HTTP. Pero al comparar arquitecturas altamente paralelas, el número de consultas aumenta. Probamos tres veces y calculamos el promedio.

Metodología de prueba

Rendimiento de las aplicaciones de red Linux. Introducción
Configuración de prueba de carga ZeroHTTPd

Es importante que al ejecutar pruebas, no todos los componentes se ejecuten en la misma máquina. En este caso, el sistema operativo incurre en una sobrecarga de programación adicional ya que los componentes compiten por la CPU. Medir la sobrecarga del sistema operativo de cada una de las arquitecturas de servidor seleccionadas es uno de los objetivos más importantes de este ejercicio. Agregar más variables será perjudicial para el proceso. Por lo tanto, la configuración de la imagen de arriba funciona mejor.

¿Qué hace cada uno de estos servidores?

  • load.unixism.net: Aquí es donde ejecutamos ab, utilidad Apache Benchmark. Genera la carga necesaria para probar nuestras arquitecturas de servidores.
  • nginx.unixism.net: A veces queremos ejecutar más de una instancia de un programa de servidor. Para hacer esto, el servidor Nginx con la configuración adecuada funciona como un equilibrador de carga proveniente de ab a los procesos de nuestro servidor.
  • zerohttpd.unixism.net: aquí ejecutamos nuestros programas de servidor en siete arquitecturas diferentes, una a la vez.
  • redis.unixism.net: este servidor ejecuta el demonio Redis, donde se almacenan las entradas del libro de visitas y los contadores de visitantes.

Todos los servidores se ejecutan en el mismo núcleo de procesador. La idea es evaluar el máximo rendimiento de cada arquitectura. Dado que todos los programas de servidor se prueban en el mismo hardware, esta es una base de referencia para la comparación. Mi configuración de prueba consta de servidores virtuales alquilados a Digital Ocean.

¿Qué estamos midiendo?

Puedes medir diferentes indicadores. Evaluamos el rendimiento de cada arquitectura en una configuración determinada cargando los servidores con solicitudes en diferentes niveles de paralelismo: la carga crece de 20 a 15 usuarios simultáneos.

Resultados de la prueba

El siguiente gráfico muestra el rendimiento de servidores en diferentes arquitecturas en diferentes niveles de paralelismo. El eje y es el número de solicitudes por segundo, el eje x son las conexiones paralelas.

Rendimiento de las aplicaciones de red Linux. Introducción

Rendimiento de las aplicaciones de red Linux. Introducción

Rendimiento de las aplicaciones de red Linux. Introducción

A continuación se muestra una tabla con los resultados.

solicitudes por segundo

concurrencia
iterativo
tenedor
pre-horquilla
transmisión
pre-transmisión
encuesta
encuesta

20
7
112
2100
1800
2250
1900
2050

50
7
190
2200
1700
2200
2000
2000

100
7
245
2200
1700
2200
2150
2100

200
7
330
2300
1750
2300
2200
2100

300

380
2200
1800
2400
2250
2150

400

410
2200
1750
2600
2000
2000

500

440
2300
1850
2700
1900
2212

600

460
2400
1800
2500
1700
2519

700

460
2400
1600
2490
1550
2607

800

460
2400
1600
2540
1400
2553

900

460
2300
1600
2472
1200
2567

1000

475
2300
1700
2485
1150
2439

1500

490
2400
1550
2620
900
2479

2000

350
2400
1400
2396
550
2200

2500

280
2100
1300
2453
490
2262

3000

280
1900
1250
2502
gran difusión
2138

5000

gran difusión
1600
1100
2519

2235

8000


1200
gran difusión
2451

2100

10 000


gran difusión

2200

2200

11 000




2200

2122

12 000




970

1958

13 000




730

1897

14 000




590

1466

15 000




532

1281

En el gráfico y la tabla se puede ver que por encima de 8000 solicitudes simultáneas solo nos quedan dos jugadores: pre-fork y epoll. A medida que aumenta la carga, un servidor basado en encuestas funciona peor que uno de transmisión. La arquitectura de creación previa de subprocesos es un competidor digno de epoll, un testimonio de lo bien que el kernel de Linux programa una gran cantidad de subprocesos.

Código fuente ZeroHTTPd

Código fuente ZeroHTTPd aquí. Hay un directorio separado para cada arquitectura.

ZeroHTTPd │ ├── 01_iterativo │ ├── main.c ├── 02_forking │ ├── main.c ├── 03_preforking │ ├── main.c ├── 04 _ enhebrado │ ├── principal.c ├── 05_prethreading │ ├── main.c ├── 06_poll │ ├── main.c ├── 07_epoll │ └── main.c ├── Makefile ├── public │ ├── índice .html │ └── esmoquin .png └── plantillas └── libro de visitas └── index.html

Además de siete directorios para todas las arquitecturas, hay dos más en el directorio de nivel superior: público y plantillas. El primero contiene el archivo index.html y la imagen de la primera captura de pantalla. Puede colocar otros archivos y carpetas allí, y ZeroHTTPd debería servir esos archivos estáticos sin ningún problema. Si la ruta en el navegador coincide con la ruta en la carpeta pública, ZeroHTTPd busca el archivo index.html en este directorio. El contenido del libro de visitas se genera dinámicamente. Sólo tiene una página de inicio y su contenido se basa en el archivo 'templates/guestbook/index.html'. ZeroHTTPd agrega fácilmente páginas dinámicas para extensión. La idea es que los usuarios puedan agregar plantillas a este directorio y ampliar ZeroHTTPd según sea necesario.

Para construir los siete servidores, ejecute make all desde el directorio de nivel superior, y todas las compilaciones aparecerán en este directorio. Los archivos ejecutables buscan los directorios público y de plantillas en el directorio desde el que se inician.

API de Linux

No es necesario conocer bien la API de Linux para comprender la información de esta serie de artículos. Sin embargo, recomiendo leer más sobre este tema, hay muchos recursos de referencia en Internet. Aunque abordaremos varias categorías de API de Linux, nos centraremos principalmente en procesos, subprocesos, eventos y la pila de red. Además de libros y artículos sobre la API de Linux, también recomiendo leer mana para conocer las llamadas al sistema y las funciones de biblioteca utilizadas.

Rendimiento y escalabilidad

Una nota sobre el rendimiento y la escalabilidad. En teoría, no existe ninguna conexión entre ellos. Puedes tener un servicio web que funciona muy bien, con un tiempo de respuesta de unos pocos milisegundos, pero no escala en absoluto. Del mismo modo, puede haber una aplicación web con un rendimiento deficiente que tarde unos segundos en responder, pero escala decenas para manejar decenas de miles de usuarios simultáneos. Sin embargo, la combinación de alto rendimiento y escalabilidad es una combinación muy poderosa. Las aplicaciones de alto rendimiento generalmente utilizan recursos con moderación y, por lo tanto, atienden de manera eficiente a más usuarios simultáneos en el servidor, lo que reduce los costos.

Tareas de CPU y E/S

Finalmente, en informática siempre hay dos tipos posibles de tareas: para E/S y CPU. Recibir solicitudes a través de Internet (E/S de red), servir archivos (E/S de red y disco), comunicarse con la base de datos (E/S de red y disco) son todas actividades de E/S. Algunas consultas de bases de datos pueden consumir un poco de CPU (clasificar, promediar un millón de resultados, etc.). La mayoría de las aplicaciones web están limitadas por la máxima E/S posible y el procesador rara vez se utiliza a plena capacidad. Cuando ve que alguna tarea de E/S utiliza mucha CPU, lo más probable es que sea un signo de una arquitectura de aplicación deficiente. Esto puede significar que los recursos de la CPU se desperdician en la gestión de procesos y el cambio de contexto, y esto no es del todo útil. Si está haciendo algo como procesamiento de imágenes, conversión de archivos de audio o aprendizaje automático, entonces la aplicación requiere potentes recursos de CPU. Pero para la mayoría de las aplicaciones este no es el caso.

Obtenga más información sobre las arquitecturas de servidores

  1. Parte I: Arquitectura iterativa
  2. Parte II. Servidores de horquilla
  3. Parte III. Servidores previos a la bifurcación
  4. Parte IV. Servidores con hilos de ejecución.
  5. Parte V. Servidores preprocesados
  6. Parte VI. Arquitectura basada en pol
  7. Parte VII. arquitectura basada en epoll

Fuente: habr.com

Añadir un comentario