[Editor – Publicado originalmente en 2016, este artículo se ha actualizado para utilizar las funcionalidades de NGINX que se han revisado desde entonces. Para obtener más información, consulte Registro avanzado con el módulo JavaScript de NGINX y Panel de NGINX Plus.]
Introdujimos el balanceo de carga TCP en NGINX Plus R5, y desde entonces hemos ido añadiendo funciones en las versiones posteriores, además de compatibilidad con el balanceo de carga UDP. En este artículo analizamos los principales requisitos del balanceo de carga TCP y cómo los aborda NGINX Plus.
Para explorar las funciones de NGINX Plus, utilizaremos un entorno de prueba sencillo que representa los componentes clave de una aplicación con un backend de base de datos escalado. Para obtener instrucciones completas sobre cómo crear el entorno de prueba, consulte el Apéndice.

En este entorno, NGINX Plus actúa como proxy inverso para el servidor de bases de datos y escucha en el puerto predeterminado de MySQL, el 3306. Esto proporciona una interfaz sencilla al cliente, mientras que los nodos MySQL del backend pueden ampliarse (e incluso desconectarse) sin afectar en modo alguno al cliente. Utilizamos la herramienta de línea de comandos de MySQL como cliente, que representa la aplicación frontend en el entorno de prueba.
Muchas de las funciones descritas en este artículo se aplican tanto a NGINX Open Source como a NGINX Plus. Para simplificar, nos referiremos a NGINX Plus en todo el artículo e indicaremos explícitamente las funciones que no están disponibles en NGINX Open Source.
Exploraremos los siguientes casos de uso:
- Balanceo de carga TCP
- Alta disponibilidad y comprobaciones de estado
- Registro y diagnóstico
- Consideraciones sobre las escrituras simultáneas
Equilibrado de carga TCP
Antes de configurar el balanceo de carga para cualquier aplicación, es importante comprender cómo se conecta la aplicación a la base de datos. En la mayoría de nuestras pruebas, utilizamos la herramienta de línea de comandos de MySQL, mysql(1), para conectarnos al clúster de Galera, ejecutar una consulta y, a continuación, cerrar la conexión. Sin embargo, muchos frameworks de aplicaciones utilizan un pool de conexiones para minimizar la latencia y aprovechar de forma eficiente los recursos del servidor de bases de datos.
El balanceo de carga TCP se configura en el contexto de configuración stream, por lo que creamos nuestra configuración básica de balanceo de carga de MySQL añadiendo un bloque stream al archivo principal nginx.conf.
Cargando ejemplo de código…
Esto separa nuestra configuración de balanceo de carga TCP del archivo de configuración principal. A continuación, creamos stream.conf en el mismo directorio que nginx.conf. Tenga en cuenta que, de forma predeterminada, el directorio conf.d está reservado para el contexto de configuración http, por lo que añadir archivos de configuración de stream a ese directorio no funciona.
Cargando ejemplo de código…
Primero, definimos un grupo upstream denominado galera_cluster, que contiene los tres nodos MySQL de nuestro clúster de Galera. En nuestro entorno de prueba, se puede acceder a cada uno de ellos en localhost mediante un número de puerto único. La directiva zone define una cantidad de memoria que se comparte entre todos los procesos de trabajo de NGINX Plus para mantener el estado del balanceo de carga. El bloque server{} configura cómo gestiona NGINX Plus las conexiones de los clientes. NGINX Plus escucha en el puerto predeterminado de MySQL, el 3306, y reenvía todo el tráfico al clúster de Galera definido en el bloque upstream.
Para comprobar que esta configuración básica funciona, podemos usar el cliente MySQL para obtener el nombre de host del nodo del clúster de Galera al que nos hemos conectado.
$ echo "SHOW VARIABLES WHERE Variable_name = 'hostname'" | mysql --protocol=tcp --user=nginx --password=plus -N 2> /dev/nullhostname node1Para comprobar que el balanceo de carga funciona, podemos repetir el mismo comando.
$ !!;!!;!!hostname node2
hostname node3
hostname node1Esto demuestra que el algoritmo de balanceo de carga por turnos predeterminado funciona correctamente. Sin embargo, si nuestra aplicación utiliza un grupo de conexiones para acceder a la base de datos (como se ha indicado anteriormente), es probable que abrir conexiones con el clúster por turnos dé lugar a un número desigual de conexiones en cada nodo. Además, no podemos equiparar una conexión con una carga de trabajo determinada, ya que las conexiones pueden estar inactivas (a la espera de una consulta de la aplicación) u ocupadas procesando una consulta. Un algoritmo de balanceo de carga más adecuado para conexiones TCP de larga duración es Menor número de conexiones, que se configura con la directiva least_conn:
Cargando ejemplo de código…
Ahora, cuando un cliente abre una nueva conexión con la base de datos, NGINX Plus elige el nodo del clúster con el menor número de conexiones activas.
Alta disponibilidad y comprobaciones de estado
La gran ventaja de distribuir la carga de trabajo de la base de datos entre los nodos de un clúster es que también proporciona alta disponibilidad. Con la configuración descrita anteriormente, NGINX Plus marca un servidor como «inactivo» y deja de enviarle paquetes TCP si no se puede establecer una nueva conexión TCP.
Además de gestionar de este modo los servidores inactivos, NGINX Plus también se puede configurar para realizar comprobaciones de estado automáticas y proactivas, de modo que los servidores no disponibles se detecten antes de que se les envíen solicitudes de clientes (esta función es exclusiva de NGINX Plus). Asimismo, la disponibilidad de los servidores se puede comprobar mediante una comprobación de estado a nivel de aplicación, lo que significa que podemos enviar una solicitud a cada servidor y verificar que recibimos una respuesta que indica que funciona correctamente. De este modo, nuestra configuración se amplía de la siguiente manera.
Cargando ejemplo de código…
En este ejemplo, el bloque match define los datos de solicitud y respuesta necesarios para iniciar un protocolo de enlace de la versión 10 del protocolo MySQL. La directiva health_check del bloque server{} aplica este patrón y garantiza que NGINX Plus reenvíe las conexiones MySQL únicamente a servidores que realmente puedan aceptar nuevas conexiones. En este caso, realizamos la comprobación de estado cada 20 segundos, excluimos un servidor del grupo de balanceo de carga TCP tras un solo fallo y reanudamos el balanceo de carga hacia él después de 2 comprobaciones de estado correctas consecutivas.
Registro y diagnóstico
NGINX Plus ofrece un registro flexible que permite registrar todo el procesamiento TCP/UDP para depuración o análisis sin conexión. En protocolos TCP como MySQL, NGINX Plus escribe una entrada de registro cuando se cierra la conexión. La directiva log_format define qué valores aparecen en los registros. Podemos elegir entre cualquiera de las variables disponibles para los módulos Stream. Definimos el formato de registro en el contexto stream, al principio de nuestro archivo stream.conf.
Cargando ejemplo de código…
El registro se habilita añadiendo la directiva access_log en el bloque server{}, especificando la ruta del archivo de registro y el nombre del formato de registro definido en el fragmento anterior.
Cargando ejemplo de código…
Esto genera entradas de registro como la del siguiente ejemplo.
$ tail -3 /var/log/nginx/galera_access.log192.168.91.1 [23/Jul/2021:17:42:18 +0100] TCP 200 369 1611 127.0.0.1:33063 0.000 0.003 12.614 12.614
192.168.91.1 [23/Jul/2021:17:42:18 +0100] TCP 200 369 8337 127.0.0.1:33061 0.001 0.001 11.181 11.181
192.168.91.1 [23/Jul/2021:17:42:19 +0100] TCP 200 369 1611 127.0.0.1:33062 0.001 0.001 10.460 10.460Registro avanzado con el módulo JavaScript de NGINX
NGINX JavaScript es el lenguaje de configuración programática «nativo de NGINX». Es una implementación única de JavaScript para NGINX y NGINX Plus, diseñada específicamente para casos de uso del lado del servidor y el procesamiento de cada solicitud.
[Editor – El siguiente caso de uso es solo uno de los muchos disponibles para el módulo JavaScript de NGINX. Para consultar la lista completa, consulte Casos de uso del módulo JavaScript de NGINX.
Esta publicación se ha actualizado para utilizar el objeto de sesión (s) refactorizado para el módulo Stream, introducido en NGINX JavaScript 0.2.4, y la directiva js_import, introducida en NGINX JavaScript 0.4.0.]
Dentro del módulo Stream para el balanceo de carga TCP/UDP, NGINX JavaScript permite acceder al contenido de los paquetes de solicitud y respuesta. Esto significa que podemos examinar la solicitud del cliente correspondiente a la consulta SQL y extraer elementos útiles, como el método SQL, por ejemplo, SELECT o UPDATE. A continuación, NGINX JavaScript puede hacer que estos valores estén disponibles como variables normales de NGINX. En este ejemplo, colocamos nuestro código JavaScript en /etc/nginx/sql_method.js.
Cargando ejemplo de código…
A la función getSqlMethod() se le pasa un objeto JavaScript (s) que representa el paquete actual. Las propiedades de este objeto, como fromUpstream y buffer, nos proporcionan la información que necesitamos sobre el paquete y su contexto.
Primero comprobamos que el paquete TCP proceda del cliente, ya que no necesitamos examinar los paquetes procedentes del servidor MySQL ascendente. En este caso, nos interesa el tercer paquete del cliente, puesto que los dos primeros contienen información sobre el protocolo de enlace y la autenticación. El tercer paquete del cliente contiene la consulta SQL. A continuación, se compara el principio de esta cadena con uno de los métodos SQL definidos en el array methods. Cuando se encuentra una coincidencia, se almacena el resultado en la variable global $method y se escribe una entrada en el registro de errores. Los mensajes de registro de NGINX JavaScript se escriben en el registro de errores con el nivel de gravedad info, por lo que no aparecen de forma predeterminada.
La función setSqlMethod() se invoca cuando se evalúa una variable de NGINX con el mismo nombre. Cuando esto ocurre, a la variable se le asigna el valor de la variable global de NGINX JavaScript $method, obtenido mediante llamadas a la función getSqlMethod().
Tenga en cuenta que este código JavaScript de NGINX está diseñado para el cliente de línea de comandos de MySQL, donde se ejecuta una única consulta. No captura con precisión consultas complejas ni varias consultas realizadas a través de una conexión de larga duración, aunque el código podría adaptarse a esos casos de uso. Para obtener instrucciones sobre cómo instalar y habilitar el módulo JavaScript de NGINX, consulte la Guía de administración de NGINX Plus.
Para incluir el método SQL en nuestros registros, incluimos la variable $sql_method en la directiva log_format.
Cargando ejemplo de código…
También debemos ampliar nuestra configuración para indicar a NGINX Plus cómo y cuándo debe ejecutar el código JavaScript de NGINX.
Cargando ejemplo de código…
Primero especificamos la ubicación del código JavaScript de NGINX mediante la directiva js_import y usamos la directiva js_set para indicar a NGINX Plus que llame a la función setSqlMethod() cuando necesite evaluar la variable $sql_method. A continuación, dentro del bloque server{} usamos la directiva js_filter para especificar la función que se llamará cada vez que se procese un paquete. Opcionalmente, podemos añadir la directiva error_log con la opción info para habilitar el registro de JavaScript de NGINX.
Con esta configuración adicional, nuestro registro de acceso ahora tiene este aspecto.
$ tail -3 /var/log/nginx/galera_access.log192.168.91.1 [23/Jul/2021:17:42:18 +0100] TCP 200 369 1611 127.0.0.1:33063 0.000 0.003 12.614 12.614 UPDATE
192.168.91.1 [23/Jul/2021:17:42:18 +0100] TCP 200 369 8337 127.0.0.1:33061 0.001 0.001 11.181 11.181 SELECT
192.168.91.1 [23/Jul/2021:17:42:19 +0100] TCP 200 369 1611 127.0.0.1:33062 0.001 0.001 10.460 10.460 UPDATEPanel de control de NGINX Plus
[Editor – Esta sección se ha actualizado para hacer referencia a la API de NGINX Plus, que sustituye y deja obsoleto el módulo de estado ampliado independiente que se trataba originalmente aquí.]
Además de registrar detalladamente la actividad de MySQL, podemos consultar las métricas en tiempo real y el estado de nuestros servidores MySQL ascendentes en el panel de monitorización de actividad en directo de NGINX Plus (NGINX Open Source ofrece un conjunto más reducido de métricas y únicamente a través de la API de estado básica).
El panel de NGINX Plus se introdujo en NGINX Plus R7 y proporciona una interfaz web para la API de NGINX Plus. Para habilitarlo, añadimos un nuevo bloque server{} en el contexto http dentro de un archivo independiente: /etc/nginx/conf.d/dashboard.conf file:
Cargando ejemplo de código…
También debemos actualizar el bloque server{} de stream.conf con la directiva status_zone para permitir que se recopilen datos de monitorización de nuestro servicio MySQL.
Cargando ejemplo de código…
Con esta configuración, el panel de NGINX Plus está disponible en el puerto 8080. En la siguiente captura de pantalla podemos ver nuestros tres servidores MySQL, cada uno de los cuales muestra los detalles de numerosas conexiones activas y su estado actual. Podemos ver que el nodo que escucha en el puerto 33062 sufrió anteriormente una breve interrupción de 18,97 segundos (indicada en la columna DT).

Consideraciones sobre las escrituras simultáneas
Galera Cluster presenta cada nodo de servidor MySQL como una base de datos maestra que realiza tanto lecturas como escrituras. En muchas aplicaciones, la proporción de lecturas respecto a escrituras es tan elevada que el riesgo de que varios clientes actualicen simultáneamente la misma fila de una tabla resulta totalmente aceptable frente a la flexibilidad que ofrece un clúster de bases de datos multimaestro. En situaciones en las que existe un mayor riesgo de que se produzcan escrituras simultáneas, disponemos de dos opciones.
- Cree dos grupos upstream independientes, uno para las lecturas y otro para las escrituras, cada uno a la escucha en un puerto diferente. Dedique uno o varios nodos del clúster a las escrituras e incluya todos los nodos en el grupo de lecturas. El código del cliente debe actualizarse para seleccionar el puerto adecuado para las operaciones de lectura y escritura. Este enfoque se explica en Equilibrio de carga avanzado de MySQL con NGINX Plus en nuestro blog y resulta idóneo para entornos altamente escalados con numerosos nodos de servidor MySQL.
- Mantenga un único grupo de servidores upstream y modifique el código del cliente para detectar errores de escritura. Cuando se detecta un error de escritura, el código aplica un tiempo de espera exponencial antes de volver a intentarlo una vez finalizada la concurrencia. Este enfoque se analiza en Alta disponibilidad de MySQL con NGINX Plus y Galera Cluster en nuestro blog y resulta más adecuado para un clúster pequeño, en el que dedicar nodos del clúster a las escrituras pondría en riesgo la alta disponibilidad.
Resumen
En este artículo hemos analizado varios de los aspectos esenciales del balanceo de carga de una aplicación TCP (o UDP), como MySQL. NGINX Plus proporciona un balanceador de carga TCP/UDP con todas las funciones necesarias para ayudarle a ofrecer aplicaciones con rendimiento, fiabilidad, seguridad y escalabilidad, independientemente del tipo de tráfico.
Para probar NGINX Plus, inicie hoy mismo su prueba gratuita de 30 días o póngase en contacto con nosotros para hablar sobre sus casos de uso.
Apéndice: Creación del entorno de pruebas
El entorno de pruebas se instala en una máquina virtual para que esté aislado y sea reproducible. Sin embargo, no hay ningún motivo por el que no pueda instalarse en un servidor físico, es decir, directamente sobre el hardware.
Instalación de NGINX Plus
Consulte la Guía de administración de NGINX Plus.
Instalación de Galera Cluster para MySQL
En este ejemplo, instalamos Galera Cluster en un único host utilizando contenedores Docker para cada nodo. Las siguientes instrucciones son una adaptación de Primeros pasos con Galera y Docker y presuponen que tanto Docker Engine como la herramienta de línea de comandos de MySQL ya están instalados.
- Cree un archivo de configuración básico de MySQL (my.cnf) que la imagen de Docker copiará en cada contenedor de Galera.
Cargando ejemplo de código…
- Descarga la imagen básica de Docker de Galera.
$ sudo docker pull erkules/galera:basic- Crea el primer nodo de Galera (node1), exponiendo el puerto predeterminado de MySQL como 33061.
$ sudo docker run -p 33061:3306 --detach=true --name node1 -h node1 erkules/galera:basic --wsrep-cluster-name=local-test --wsrep-cluster-address=gcomm://- Cree el segundo nodo de Galera (node2). El puerto de MySQL se expone como 33062 y está vinculado a node1 para la comunicación entre clústeres.
$ sudo docker run -p 33062:3306 --detach=true --name node2 -h node2 --link node1:node1 erkules/galera:basic --wsrep-cluster-name=local-test --wsrep-cluster-address=gcomm://node1- Cree el tercer y último nodo de Galera (node3) del mismo modo que node2. El puerto de MySQL se expone como 33063.
$ sudo docker run -p 33063:3306 --detach=true --name node3 -h node3 --link node1:node1 erkules/galera:basic --wsrep-cluster-name=local-test --wsrep-cluster-address=gcomm://node1- Cree una cuenta de usuario llamada nginx que pueda utilizarse para acceder de forma remota al clúster desde el host. Para ello, ejecute el comando
mysql(1)desde el propio contenedor de Docker.
$ sudo docker exec -ti node1 mysql -e"GRANT ALL PRIVILEGES ON *.* TO 'nginx'@'172.17.0.1' IDENTIFIED BY 'plus'"- Compruebe que puede conectarse al clúster de Galera desde el host mediante el protocolo TCP.
$ mysql --protocol=tcp -P 33061 --user=nginx --password=plus -e "SHOW DATABASES"mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+- Por último, ejecute el mismo comando en otro de los nodos del clúster para comprobar que la cuenta de usuario nginx se ha replicado y que el clúster funciona correctamente.
$ mysql --protocol=tcp -P 33062 --user=nginx --password=plus -e "SHOW DATABASES"mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+Sobre el autor

Artículos relacionados del blog
Únete a F5 NGINX en AppWorld 2024
Descubre las numerosas razones para asistir al evento insignia de F5, que incluirá un emocionante anuncio sobre la cartera de productos NGINX.
Rotación de certificados SSL/TLS sin reinicios en NGINX Open Source
La función de diccionario compartido permite configurar NGINX sin necesidad de reiniciarlo al renovar los certificados SSL/TLS.
Exposición de APIs en Kubernetes
La unidad 2 de Microservices March 2022 se centra en cómo exponer tus API en Kubernetes. Aquí tienes enlaces a los recursos que necesitas: la retransmisión en directo del 14 de marzo, artículos de blog y otros recursos de preparación, y el laboratorio práctico «Protege las API de Kubernetes mediante la limitación de solicitudes».
NGINX Sprint 2.0: visión clara, código renovado y nuevos compromisos con el código abierto
Hoy, en NGINX Sprint 2.0, anunciamos cómo respaldaremos nuestra visión del futuro de las aplicaciones modernas con una mayor presencia en la comunidad de código abierto, incluida la participación en el proyecto comunitario Kubernetes, nuevos proyectos de software de código abierto y la arquitectura de referencia para aplicaciones modernas.
Presentamos NGINX Plus R22
NGINX Plus R22 incorpora nuevas funcionalidades, como la compatibilidad con OCSP para verificar la revocación de certificados en TLS mutuo, el uso de varios proveedores de identidad OIDC en una configuración, el seguimiento en tiempo real de la limitación de solicitudes y conexiones en el panel de NGINX Plus y mejoras en NGINX JavaScript.
Presentamos NGINX Plus R17
NGINX Plus R17 incorpora compatibilidad con la limitación de velocidad en dos fases y con TLS 1.3, la versión más reciente del protocolo Transport Layer Security. La configuración de OpenID Connect es más sencilla y NGINX ModSecurity WAF es el doble de rápido que antes. También se ha actualizado el módulo JavaScript de NGINX.