Pruebas de rendimiento precisas con `wrk`

API7.ai

November 25, 2022

OpenResty (NGINX + Lua)

En este artículo, hablaremos sobre las pruebas de rendimiento. Esta parte no es exclusiva de OpenResty, sino que se aplica a otros servicios backend.

Las pruebas de rendimiento son muy comunes, y cuando entregamos los productos, todos vienen con métricas de rendimiento, como QPS, TPS, latencia, el número de usuarios que la conexión puede soportar simultáneamente, entre otros. Para los proyectos de código abierto, también realizamos una prueba de rendimiento antes de lanzar una versión para compararla con la anterior y ver si hay un descenso significativo. También hay sitios web neutrales que publican datos comparativos de rendimiento de productos similares. Debo decir que las pruebas de rendimiento están muy cerca de nosotros.

Entonces, ¿cómo se realizan pruebas de rendimiento científicas y rigurosas?

Herramientas de Pruebas de Rendimiento

Para hacer un buen trabajo, primero debes usar una buena herramienta. Elegir una buena herramienta de pruebas de rendimiento es la mitad del éxito.

La herramienta Apache Benchmark, también conocida como ab, con la que deberías estar familiarizado, es posiblemente la herramienta de pruebas de rendimiento más fácil, pero desafortunadamente, no es muy útil. Esto se debe a que el lado del servidor actual está desarrollado basado en I/O concurrente y asíncrono, cuyo rendimiento no es malo. El ab no aprovecha los múltiples núcleos de la máquina y las solicitudes generadas no ejercen suficiente presión. En este caso, los resultados obtenidos de las pruebas con ab no son reales.

Por lo tanto, podemos elegir un criterio para la herramienta de pruebas de estrés: la herramienta en sí tiene un rendimiento sólido y puede generar suficiente estrés para presionar el programa del lado del servidor.

Por supuesto, también puedes gastar más dinero para iniciar muchos clientes de pruebas de estrés y convertirlos en un sistema de pruebas de estrés distribuido. Pero no olvides que la complejidad también aumenta.

Volviendo a la práctica de OpenResty, nuestra herramienta de pruebas de rendimiento recomendada es wrk. Primero, ¿por qué la elegimos?

Primero, wrk cumple con los criterios de selección de herramientas. El estrés generado por wrk en una sola máquina puede fácilmente permitir que NGINX alcance el 100% de utilización de la CPU, sin mencionar otras aplicaciones del lado del servidor.

Segundo, wrk tiene muchas similitudes con OpenResty. wrk no es un proyecto de código abierto escrito desde cero; se apoya en LuaJIT y Redis y aprovecha los recursos de múltiples núcleos del sistema para generar solicitudes. Además, wrk expone una API de Lua que te permite incrustar tus scripts de Lua para personalizar los encabezados y el contenido de las solicitudes, lo que lo hace muy flexible.

Entonces, ¿cómo debemos usar wrk? Es tan simple como ver el siguiente fragmento de código.

wrk -t12 -c400 -d30s http://127.0.0.1:8080/index.html

Esto significa que wrk usará 12 hilos, mantendrá 400 conexiones largas durante 30 segundos, para enviar solicitudes HTTP a la interfaz API especificada. Por supuesto, si no especificas parámetros, wrk iniciará dos hilos y diez conexiones largas por defecto.

Entorno de Pruebas

Después de encontrar las herramientas de pruebas, no podemos comenzar la prueba de estrés directamente. Necesitamos revisar el entorno de pruebas una vez. Hay cuatro elementos principales que deben verificarse en el entorno de pruebas, y los discutiré en detalle.

1. Desactivar SELinux

Si tienes un sistema operativo CentOS/RedHat, se recomienda que desactives SELinux. De lo contrario, podrías encontrarte con muchos problemas de permisos extraños.

Verifiquemos si SELinux está activado con el siguiente comando.

$ sestatus
SELinux status: disabled

Si dice que está activado (enforcing), puedes desactivarlo temporalmente con $ setenforce 0; también, modifica el archivo /etc/selinux/config para desactivarlo permanentemente cambiando SELINUX=enforcing a SELINUX=disabled.

2. Número máximo de archivos abiertos

Luego, necesitas verificar el número máximo de archivos abiertos en el sistema actual con el siguiente comando.

    $ cat /proc/sys/fs/file-nr
    3984 0 3255296

El último número 3255296 aquí es el número máximo de archivos abiertos. Si este número es pequeño en tu máquina, necesitas modificar el archivo /etc/sysctl.conf para aumentarlo.

fs.file-max = 1020000
net.ipv4.ip_conntrack_max = 1020000
net.ipv4.netfilter.ip_conntrack_max = 1020000

Después de la modificación, debes reiniciar el servicio del sistema para que surta efecto.

sudo sysctl -p /etc/sysctl.conf

3. Límites de procesos

Además del número máximo de archivos abiertos en el sistema, también hay un límite en el número de archivos que un proceso puede abrir, que puedes verificar con el comando ulimit.

$ ulimit -n
1024

Notarás que este valor por defecto es 1024, un valor pequeño. Dado que cada solicitud de usuario corresponde a un manejador de archivo, y las pruebas de estrés generan muchas solicitudes, necesitamos aumentar este valor y cambiarlo a millones, lo que puedes hacer temporalmente con el siguiente comando.

ulimit -n 1024000

También puedes modificar el archivo de configuración /etc/security/limits.conf para hacerlo permanente.

* hard nofile 1024000
* soft nofile 1024000

4. Configuración de NGINX

Finalmente, necesitarás hacer un pequeño cambio en la configuración de NGINX, que son las siguientes tres líneas de código.

events {
    worker_connections 10240;
}

Esto nos permite aumentar el número de conexiones por Worker. Dado que el valor por defecto es solo 512, esto no es suficiente para pruebas de estrés altas.

Verificación antes de la prueba de estrés

En este punto, el entorno de pruebas está listo. Debes estar ansioso por comenzar y probarlo, ¿verdad? Verifiquemos una última vez antes de lanzar la prueba con wrk. Después de todo, las personas cometen errores, por lo que es esencial hacer una prueba cruzada.

Esta última prueba se puede dividir en dos pasos.

1. Usar la herramienta automatizada c1000k

c1000k proviene del autor de SSDB. Como puedes ver en el nombre, el propósito de esta herramienta es verificar si tu entorno puede cumplir con los requisitos de 10^6 conexiones concurrentes.

El uso de esta herramienta también es sencillo. Iniciamos un server y un client, correspondientes al programa del servidor escuchando en el puerto 7000 y el programa del cliente lanzando la prueba de estrés para simular la prueba de estrés en un entorno real:

. /server 7000
. /client 127.0.0.1 7000

Inmediatamente después, el client envía una solicitud al server para verificar si el entorno del sistema actual puede soportar un millón de conexiones concurrentes. Puedes ejecutarlo tú mismo y ver el resultado.

2. Verificar si el programa del servidor está funcionando correctamente

Si el programa del lado del servidor no está funcionando correctamente, la prueba de estrés puede convertirse en una prueba de refresco de registros de errores o una prueba de respuesta 404.

Por lo tanto, el último y más crucial paso de la prueba del entorno de pruebas es ejecutar el conjunto de pruebas unitarias del lado del servidor o llamar manualmente algunas interfaces principales para asegurarse de que todas las interfaces, retornos y códigos de respuesta HTTP de la prueba wrk sean normales y que no haya mensajes de nivel de error en logs/error.log.

Envío de solicitudes

Bien, ahora todo está listo para comenzar. ¡Comencemos la prueba de estrés con wrk!

$ wrk -d 30 http://127.0.0.2:9080/hello
Running 30s test @ http://127.0.0.2:9080/hello
  2 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   595.39us  178.51us  22.24ms   90.63%
    Req/Sec     8.33k   642.91     9.46k    59.80%
  499149 requests in 30.10s, 124.22MB read
Requests/sec:  16582.76
Transfer/sec:      4.13MB

No especifiqué parámetros aquí, por lo que wrk iniciará 2 hilos y 10 conexiones largas por defecto. No necesitas ajustar el número de hilos y conexiones en wrk para que sea muy grande; siempre y cuando puedas hacer que el programa objetivo alcance el 100% de utilización de la CPU, estarás bien.

Pero el tiempo de la prueba de estrés no debe ser demasiado corto, ya que unas pocas segundos de prueba de estrés no tienen sentido. De lo contrario, la prueba de estrés probablemente terminará antes de que el programa del servidor termine la recarga en caliente. Al mismo tiempo, necesitas usar una herramienta de monitoreo como top o htop para verificar si el programa objetivo en el servidor está funcionando al 100% de utilización de la CPU durante la prueba de estrés.

Fenoménicamente, si la CPU está completamente cargada y el uso de la CPU y la memoria disminuye rápidamente después de que se detiene la prueba, entonces felicitaciones, la prueba se completó con éxito. Sin embargo, si hay alguna excepción como las siguientes, como desarrollador del lado del servidor, debes prestar atención.

  • La CPU no puede cargarse completamente. Esto no es un problema de wrk; podría ser una limitación de la red o una operación de bloqueo en tu código. Puedes determinarlo revisando tu código o usando el gráfico de llamas off CPU.
  • La CPU siempre está completamente cargada, incluso cuando se detiene el estrés. Esto indica un bucle infinito en el código causado por una expresión regular o un error de LuaJIT, que he encontrado en entornos reales. En este punto, necesitarás usar el gráfico de llamas de la CPU para determinarlo.

Finalmente, veamos las estadísticas de wrk. En cuanto a este resultado, generalmente nos enfocamos en dos valores.

El primero es QPS, o Requests/sec: 16582.76, que es una cifra exacta que indica cuántas solicitudes se procesan por segundo en el lado del servidor.

El segundo es Latencia: Latency 595.39us 178.51us 22.24ms 90.63%, tan importante como QPS, que refleja la velocidad de respuesta del sistema. Por ejemplo, para aplicaciones de puerta de enlace, queremos mantener la latencia dentro de 1 ms.

Además, wrk también proporciona un parámetro latency que imprime la distribución porcentual de la latencia en detalle, por ejemplo.

Latency Distribution
        50% 134.00us
        75% 180.00us
        90% 247.00us
        99% 552.00us

Sin embargo, los datos de distribución de latencia de wrk son inexactos porque agregan perturbaciones de red y de la herramienta que amplifican la latencia, lo que requiere tu atención especial.

Resumen

Las pruebas de rendimiento son un trabajo técnico; no muchas personas pueden hacerlo bien y correctamente. Espero que este artículo te haya dado una comprensión más completa de las pruebas de rendimiento.

Finalmente, te dejo una pregunta: wrk admite scripts de Lua personalizados para hacer pruebas de estrés, ¿puedes escribir un script simple de Lua basado en su documentación? Puede ser un poco difícil, pero entenderás la intención de las interfaces expuestas de wrk cuando lo termines.

Eres bienvenido a compartir este artículo con más personas, y juntos haremos progresos.