Enquanto trabalhava em vários projetos de código aberto, um dia decidi simplificar minha vida e desenvolvi o módulo Upstream para o nginx, que me ajudou a remover camadas volumosas da arquitetura de várias camadas. Foi uma experiência divertida que quero compartilhar neste artigo. Meu código está disponível publicamente aqui:
github.com/tarantool/nginx_upstream_module . Você pode pegá-lo do zero ou fazer o download da imagem do Docker neste link:
hub.docker.com/r/tarantool/tarantool-nginx .
Na agenda:
- Introdução e teoria.
- Como usar essas tecnologias.
- Classificação de desempenho.
- Links úteis.
Introdução e Teoria

É assim que a arquitetura padrão de microsserviço se parece. As solicitações do usuário passam pelo nginx para o servidor de aplicativos. Há lógica de negócios no servidor com o qual os usuários interagem.
O servidor de aplicativos não armazena o estado dos objetos; portanto, eles precisam ser armazenados em outro lugar. Você pode usar bancos de dados para isso. E não se esqueça do cache, que reduzirá a latência e proporcionará uma entrega mais rápida de conteúdo.
Divida-o em camadas:
1ª camada - nginx.
2ª camada - servidor de aplicativos.
3ª camada - cache.
4ª camada - proxy do banco de dados. Esse proxy é necessário para garantir a tolerância a falhas e manter uma conexão constante com o banco de dados.
A quinta camada é o servidor de banco de dados.
Pensando nessas camadas, descobri como excluir algumas delas. Porque Existem muitas razões. Eu gosto de coisas simples e compreensíveis; Não gosto de apoiar um grande número de sistemas diferentes na produção; e por último mas não menos importante, quanto menos camadas, menos pontos de falha. Como resultado, criei o módulo Tarantool Upstream sob o nginx, o que ajudou a reduzir o número de camadas para duas.

Como o Tarantool ajuda a reduzir o número de camadas? A primeira camada é nginx, a segunda, terceira e quinta camadas substituem o Tarantool. A quarta camada, o proxy do banco de dados, está agora no nginx. O truque é que o Tarantool é um banco de dados, cache e servidor de aplicativos, três em um. Meu módulo upstream conecta nginx e Tarantool um ao outro e permite que eles funcionem perfeitamente sem as outras três camadas.

É assim que o novo microsserviço se parece. O usuário envia uma solicitação ao REST ou JSON RPC no nginx com o módulo Tarantool Upstream. O módulo pode ser conectado diretamente ao Tarantool ou a carga pode ser balanceada em vários servidores Tarantool. Entre o nginx e o Tarantool, usamos um protocolo eficiente baseado no MSGPack. Você encontrará mais informações
neste artigo .
Você também pode seguir estes links para baixar o Tarantool e o módulo nginx. Mas eu recomendaria instalá-los através do gerenciador de pacotes da sua distribuição ou usando a imagem do Docker (
docker pull tarantool/tarantool-nginx
).
Imagens do Docker:
hub.docker.com/r/tarantool/tarantoolMódulo a montante Tarantool NginXPacotes binários:
Tarantool - DownloadCódigo fonte:
Tarantooltarantool / nginx_upstream_moduleComo usar essas tecnologias
Aqui está um exemplo de arquivo nginx.conf. Como você pode ver, este é um nginx upstream regular. Aqui temos
tnt_pass
, que
tnt_pass
diretamente ao nginx qual o caminho para colocar o tarantool a montante.
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; } } }
Aqui estão os links para a documentação:
nginx.org/en/docs/http/ngx_http_upstream_module.htmlgithub.com/tarantool/nginx_upstream_module/blob/master/README.mdConfigurou um monte de nginx e Tarantool, e daí? Agora precisamos registrar uma função de manipulador para o nosso serviço e colocá-la em um arquivo. Coloquei no arquivo "app.lua".
Aqui está um link para a documentação do
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
Agora considere o código Lua.
Nosso
Box.cfg {}
diz ao Tarantool para começar a escutar na porta 3301, mas pode aceitar outros parâmetros.
Box.once
diz ao Tarantool para chamar uma função uma vez.
function api ()
é uma função que chamarei em breve. Ele recebe uma solicitação HTTP como o primeiro argumento e retorna uma matriz de valores.
Salvei esse código em um arquivo e o nomeei "app.lua". Você pode executá-lo simplesmente iniciando o aplicativo Tarantool.
$> tarantool app.lua
Chamamos nossa função usando uma solicitação GET. Eu uso "wget" para isso. Por padrão, "wget" salva a resposta em um arquivo. E para ler os dados do arquivo, eu 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!” }] ]}
Avaliação de desempenho
A avaliação foi realizada com dados da produção. A entrada é um objeto JSON grande. O tamanho médio desse objeto é 2 Kb. Servidor único, CPU de 4 núcleos, 90 GB de RAM, SO Ubuntu 14.04.1 LTS.
Para este teste, usamos apenas um trabalhador nginx. Este trabalhador é um balanceador com um algoritmo ROUND-ROBIN simples. Ele equilibra a carga entre os dois nós do Tarantool. A carga é escalada usando sharding.
Esses gráficos mostram o número de leituras por segundo. O gráfico superior mostra os atrasos (em milissegundos).

E esses gráficos mostram o número de operações de gravação por segundo. O gráfico superior mostra atrasos (em milissegundos)

Impressionante!
No próximo artigo, falarei em detalhes sobre o REST e o JSON RPC.
Versão em inglês do artigo: hackernoon.com/shrink-the-number-of-tiers-in-a-multitier-architecture-from-5-to-2-c59b7bf46c86