Mientras trabajaba en varios proyectos de código abierto, un día decidí simplificar mi vida y desarrollé el módulo Upstream para nginx, que me ayudó a eliminar capas voluminosas de arquitectura multicapa. Fue una experiencia divertida que quiero compartir en este artículo. Mi código está disponible públicamente aquí:
github.com/tarantool/nginx_upstream_module . Puede recogerlo desde cero o descargar la imagen de Docker desde este enlace:
hub.docker.com/r/tarantool/tarantool-nginx .
En la agenda:
- Introducción y teoría.
- Cómo usar estas tecnologías.
- Calificación de desempeño.
- Enlaces utiles.
Introducción y teoría

Así es como se ve la arquitectura estándar de microservicios. Las solicitudes de los usuarios llegan a través de nginx al servidor de aplicaciones. Existe una lógica empresarial en el servidor con la que los usuarios interactúan.
El servidor de aplicaciones no almacena el estado de los objetos, por lo que deben almacenarse en otro lugar. Puede usar bases de datos para esto. Y no se olvide del caché, que reducirá la latencia y proporcionará una entrega más rápida de contenido.
Dividirlo en capas:
Primera capa - nginx.
2da capa - servidor de aplicaciones.
3ra capa - caché.
4ta capa - proxy de base de datos. Este proxy es necesario para garantizar la tolerancia a fallos y mantener una conexión constante a la base de datos.
La quinta capa es el servidor de bases de datos.
Pensando en estas capas, descubrí cómo excluir algunas de ellas. Por qué Hay muchas razones Me gustan las cosas simples y comprensibles; No me gusta admitir una gran cantidad de sistemas diferentes en producción; y por último, pero no menos importante, cuantas menos capas, menos puntos de falla. Como resultado, creé el módulo Tarantool Upstream en nginx, lo que ayudó a reducir el número de capas a dos.

¿Cómo ayuda Tarantool a reducir la cantidad de capas? La primera capa es nginx, la segunda, tercera y quinta capas reemplazan a Tarantool. La cuarta capa, el proxy de la base de datos, ahora está en nginx. El truco es que Tarantool es una base de datos, caché y servidor de aplicaciones, tres en uno. Mi módulo ascendente conecta nginx y Tarantool entre sí y les permite trabajar sin problemas sin las otras tres capas.

Así es como se ve el nuevo microservicio. El usuario envía una solicitud a REST o JSON RPC en nginx con el módulo Tarantool Upstream. El módulo se puede conectar directamente a Tarantool, o la carga se puede equilibrar en varios servidores de Tarantool. Entre nginx y Tarantool utilizamos un protocolo eficiente basado en MSGPack. Encontrará más información en
este artículo .
También puede seguir estos enlaces para descargar Tarantool y el módulo nginx. Pero recomendaría instalarlos a través del administrador de paquetes de su distribución o usar la imagen Docker (
docker pull tarantool/tarantool-nginx
).
Imágenes de Docker:
hub.docker.com/r/tarantool/tarantoolMódulo ascendente Tarantool NginXPaquetes binarios:
Tarantool - DescargarCódigo fuente:
Tarantooltarantool / nginx_upstream_moduleCómo usar estas tecnologías
Aquí hay un ejemplo de archivo nginx.conf. Como puede ver, este es un nginx corriente arriba. Aquí tenemos
tnt_pass
, que
tnt_pass
directamente a nginx en qué ruta colocar tarantool aguas arriba.
nginx-tnt.conf http { # upstream upstream tnt { server 127.0.0.1:3301; keepalive 1000; } server { listen 8081; # gateway location /api/do { tnt_pass_http_request parse_args; tnt_pass tnt; } } }
Aquí están los enlaces a la documentación:
nginx.org/en/docs/http/ngx_http_upstream_module.htmlgithub.com/tarantool/nginx_upstream_module/blob/master/README.mdConfigurado un montón de nginx y Tarantool, ¿entonces qué? Ahora necesitamos registrar una función de controlador para nuestro servicio y colocarla en un archivo. Lo puse en el archivo "app.lua".
Aquí hay un enlace a la documentación de
Tarantool :
tarantool.io/en/doc/1.9/book/box/data_model/#index -- Bootstrap Tarantool box.cfg { listen='*:3301' } -- Grants box.once('grants', function() box.schema.user.grant('guest', 'read,write,execute', 'universe') end) -- Global variable hello_str = 'Hello' -- function function api(http_request) local str = hello_str if http_request.method == 'GET' then str = 'Goodbye' end return 'first', 2, { str .. 'world!' }, http_request.args end
Ahora considere el código Lua.
Nuestro
Box.cfg {}
le dice a Tarantool que comience a escuchar en el puerto 3301, pero puede aceptar otros parámetros.
Box.once
le dice a Tarantool que llame a una función una vez.
function api ()
es una función que llamaré pronto. Toma una solicitud HTTP como primer argumento y devuelve una matriz de valores.
Guardé este código en un archivo y lo llamé "app.lua". Puede ejecutarlo simplemente iniciando la aplicación Tarantool.
$> tarantool app.lua
Llamamos a nuestra función mediante una solicitud GET. Yo uso "wget" para esto. Por defecto, "wget" guarda la respuesta a un archivo. Y para leer los datos del archivo, uso "cat".
$ wget '0.0.0.0:8081/api/do?arg_1=1&arg_2=2' $ cat do* { “id”:0, # — unique identifier of the request “result”: [ # — is what our Tarantool function returns [“first”], [2], [{ “request”:{“arg_2”:”2",”arg_1":”1"} “1”:”Goodbye world!” }] ]}
Calificación de desempeño
La evaluación se realizó con datos de producción. La entrada es un gran objeto JSON. El tamaño promedio de dicho objeto es de 2 Kb. Servidor único, CPU de 4 núcleos, 90 GB de RAM, sistema operativo Ubuntu 14.04.1 LTS.
Para esta prueba usamos solo un trabajador nginx. Este trabajador es un equilibrador con un algoritmo ROUND-ROBIN simple. Equilibra la carga entre los dos nodos de Tarantool. La carga se escala mediante fragmentación.
Estos gráficos muestran el número de lecturas por segundo. El gráfico superior muestra los retrasos (en milisegundos).

Y estos gráficos muestran el número de operaciones de escritura por segundo. El gráfico superior muestra retrasos (en milisegundos)

Impresionante!
En el próximo artículo hablaré en detalle sobre REST y JSON RPC.
Versión en inglés del artículo: hackernoon.com/shrink-the-number-of-tiers-in-a-multitier-architecture-from-5-to-2-c59b7bf46c86