Repository navigation
balanceador dedicado
Home > Colocar no ar > Balanceador dedicado (TRALBalancer) 🚧
Important
Em desenvolvimento (2.0). Ainda não está numa versão lançada e pode mudar.
Vale para a 2.0 · Delphi XE em diante e Lazarus/FPC 3.2 em diante · Nível: intermediário
Em uma frase: um componente que só balanceia: escuta numa porta com as suas próprias
threads (sem motor HTTP), lê apenas a linha de pedido e os cabeçalhos, escolhe um servidor
de trás pelo TRALUpstream e repassa o corpo em fluxo nos dois sentidos -
ou, no modo TCP, repassa bytes de qualquer protocolo.
Você vai precisar: os pacotes RALNetPackage e RALModuleProxyPackage (componente
TRALBalancer, paleta RAL - Server; TRALUpstream em RAL - Modules). Para HTTPS, a
OpenSSL 1.1.1 ou 3.x ao lado do programa (dependências).
TRALProxyModule |
TRALBalancer |
|
|---|---|---|
| onde roda | dentro de um servidor RAL, ao lado das suas rotas | sozinho, numa porta própria |
| motor | o do servidor (Indy, mORMot2, fpHTTP...) | nenhum: rede própria do RAL |
| plugins do servidor | todos | os de validação (ppValidate: listas de IP, limite de pedidos, inundação, encaminhado...) |
| corpo do pedido | o motor recebe inteiro antes | em fluxo, com memória constante |
| WebSocket | não | sim, como túnel |
| TCP puro (banco, MQTT, TLS sem abrir) | não | sim (Mode := bmTCP) |
| vazão | a do motor | perto da de um NGINX |
Grupo := TRALUpstream.Create(Self);
Grupo.Servers.AddServer('http://10.0.0.11:8080');
Grupo.Servers.AddServer('http://10.0.0.12:8080');
Balanceador := TRALBalancer.Create(Self);
Balanceador.Port := 80;
Balanceador.Upstream := Grupo; // o que nenhuma rota pega
Balanceador.Routes.AddRoute('', '/api/', Api).StripPrefix := True; // /api/x -> /x
Balanceador.Routes.AddRoute('admin.exemplo.com', '', Admin); // por Host
Balanceador.Active := True;As rotas são lidas em ordem e a primeira que casa vence: HostName (vazio é qualquer;
*.exemplo.com cobre um nível) e PathPrefix (segmentos inteiros: /api não pega
/apis). Nenhuma rota e nenhum Upstream: 404. O evento OnRoute pode trocar a
escolha. Tudo o que o TRALUpstream faz vale aqui: políticas, pesos, reserva, saúde
passiva e ativa, sessão grudada, estatística.
Balanceador.SSL.Enabled := True;
Balanceador.SSL.CertFile := 'certs\padrao.pem'; // para quem não pede um nome conhecido
Balanceador.SSL.KeyFile := 'certs\padrao.key';
Balanceador.SSL.Certificates.AddCertificate('www.exemplo.com', 'certs\www.pem', 'certs\www.key');
Balanceador.SSL.Certificates.AddCertificate('*.api.exemplo.com', 'certs\api.pem', 'certs\api.key');- Um certificado por nome na mesma porta, escolhido pelo SNI.
StrictServerNamerecusa quem pede um nome que nenhum certificado cobre. - O certificado automático funciona: ligue o
TRALSelfSignedPluginao balanceador. - Servidores de trás com
https://são chamados com TLS e retomam a sessão (a segunda conexão não paga o handshake inteiro).VerifyBackendconfere o certificado deles contra as autoridades do sistema (desligado por padrão: servidores internos costumam ter certificado próprio). - Os servidores de trás recebem
X-Forwarded-Proto: https.
- O corpo vai em fluxo nos dois sentidos, inclusive
chunked(passado como veio, com trailer): um upload de 1 GB passa com a mesma memória de um GET. Quando um lado não esvazia, o outro espera (contrapressão). - Cabeçalhos: saem os de salto a salto (
Connectione os que ele nomeia,Keep-Alive,Proxy-*...);AddForwarded(padrão) põeX-Forwarded-For,-Protoe-Host(oX-Forwarded-Forque chegou é trocado, ou acrescentado comKeepForwardedChain);Viapõe o cabeçalhoVia.PreserveHostpassa oHostdo cliente em vez do do servidor de trás. - O
Locationde um redirecionamento do servidor de trás volta relativo (com o prefixo da rota, quando foi tirado). -
Upgrade: websocket: depois do101os dois lados viram um túnel. - Conexões com os servidores de trás são mantidas e reaproveitadas entre pedidos.
- Um pedido que falhou antes de qualquer resposta vai ao próximo servidor
(
MaxAttempts) só se é idempotente e sem corpo. Nenhum disponível: 503; nenhum respondeu: 502; o servidor ficou mudo além deServerTimeout(ou doRequestTimeoutdo upstream): 504.
O balanceador lê os pedidos com o rigor da RFC 9112, para que ele e o servidor de trás nunca discordem de onde um pedido termina (contrabando de pedido):
| pedido | resposta |
|---|---|
Content-Length junto com Transfer-Encoding
|
400 |
dois Content-Length diferentes |
400 |
Transfer-Encoding que não termina em chunked, ou num HTTP/1.0 |
400 |
linha dobrada (começa com espaço), espaço antes dos dois pontos, \r ou \n solto no meio |
400 |
linhas terminadas só em \n
|
não é reconhecido: 408 depois de HeaderTimeout
|
HTTP/1.1 sem Host, ou com dois |
400 |
cabeçalho maior que MaxHeaderSize (16 KB) |
431 |
HTTP/2.0 em texto |
505 |
CONNECT |
405 |
Banco := TRALUpstream.Create(Self);
Banco.Servers.AddServer('tcp://10.0.0.20:5432');
Tcp := TRALBalancer.Create(Self);
Tcp.Mode := bmTCP;
Tcp.Port := 5432;
Tcp.Upstream := Banco;
Tcp.Active := True;Bytes nos dois sentidos, com meio fechamento (quem termina de mandar avisa o outro lado).
Com TLS que passa sem abrir, uma rota com HostName escolhe o grupo pelo nome que o
cliente pede no SNI - o balanceador lê o ClientHello e não tem certificado nenhum:
Tcp.Routes.AddRoute('a.exemplo.com', '', GrupoA);
Tcp.Routes.AddRoute('*.b.exemplo.com', '', GrupoB);Os plugins de validação ligados ao balanceador (Plugin.Server := Balanceador) julgam
cada pedido antes do repasse: listas de IP, força bruta, inundação,
limite de pedidos, TRALForwardedPlugin (para um
balanceador atrás de outro). O que eles recusam é respondido ali. O
TRALConcurrencyPlugin conta o pedido até a resposta terminar.
-
OnAccessé chamado no fim de cada pedido (no modo TCP, de cada conexão), numa thread do balanceador: grave ou enfileire ali, não mexa na tela.RALBalancerAccessLine(Entrada, 'combined')dá a linha no formato do NGINX/Apache;'json', um objeto por linha. -
StatsPath := '/status': o próprio balanceador responde a estatística (conexões, pedidos, e por servidor de cada upstream) em JSON, ou no formato do Prometheus com?format=prometheus. Proteja com uma lista de IPs. - Na IDE, o verbo Testar porta diz se a porta abre e os certificados carregam; o
Testar servidores do
TRALUpstreampede o caminho de saúde a cada servidor agora (TestServersem código).
Balanceador.Routes.AddRoute('', '/v2/', NovoGrupo);
Balanceador.Upstream := OutroGrupo;
Balanceador.Reload; // novos pedidos seguem isto; os em curso terminam como estavamReload também recarrega os certificados de SSL. As conexões abertas não caem: o
próximo pedido delas já segue as rotas novas. Um upstream que saiu de uso não é liberado
pelo balanceador (pedidos em curso podem usá-lo): libere depois de Active := False. O
RALProxy faz tudo isso a partir de um arquivo de configuração.
| propriedade | padrão | para quê |
|---|---|---|
ThreadCount |
0 (um por processador) | threads de poll
|
BufferSize |
16384 | bytes por buffer (um por sentido e conexão) |
MaxHeaderSize |
16384 | maior cabeçalho de pedido e de resposta |
HeaderTimeout |
30000 ms | tempo para o cliente mandar o cabeçalho inteiro |
IdleTimeout |
75000 ms | conexão mantida quieta entre pedidos |
ServerTimeout |
0 (o RequestTimeout do upstream) |
servidor de trás mudo |
TunnelTimeout |
600000 ms | TCP e WebSocket quietos nos dois sentidos |
MaxConnections |
0 (sem limite) | conexões de clientes ao mesmo tempo |
| Sintoma | Causa | Solução |
|---|---|---|
| 404 em tudo | nenhuma rota casou e Upstream vazio |
preencha Upstream ou confira HostName/PathPrefix
|
| 400 ou 408 para um cliente antigo | ele manda o pedido fora da RFC (linha dobrada, linhas só com \n) |
corrija o cliente: o balanceador não adivinha onde o pedido termina |
| 502 logo de cara | o servidor de trás recusa a conexão | confira o endereço e a porta da URL
|
| 504 | o servidor de trás demora mais que ServerTimeout
|
aumente ServerTimeout ou o RequestTimeout do upstream |
| o log trava a tela |
OnAccess mexe em componentes visuais |
enfileire a linha e leve à tela com um TTimer (veja o exemplo Balancer) |
| HTTPS não sobe | a OpenSSL não está ao lado do programa | dependências; o verbo Testar porta diz o motivo |
- Balanceador e proxy reverso (
TRALUpstream,TRALProxyModule) - RALProxy: o balanceador pronto, com arquivo de configuração
- Atrás de um proxy
- Exemplos:
Delphi/VCL/BalancereLazarus/LCL/Balancernos Samples da 2.0
Começar
Servidor
- Rotas e parâmetros
- Rotas avançadas: tipos, grupos, versões 🚧
- Ler o pedido e responder
- Resposta em fluxo 🚧
- Plugins 🚧
- Autenticação
- Banco de dados (DBWare)
- Servir site e arquivos
- Swagger e Postman
- Servidor SOAP 🚧
- HTTPS
- Criptografia ponto a ponto
- Segurança para produção
- Colocar no ar
- Desempenho
MQTT 🚧
- O que é e quando usar 🚧
- Cliente MQTT 🚧
- Broker MQTT 🚧
- MQTT-SN 🚧
- Ponte REST 🚧
- Segurança 🚧
- Rede ruim 🚧
Cliente
Motores
Avançado
Ajuda
- Problemas comuns
- Atualizar o Indy
- Várias versões do Delphi
- Vídeos e guias
- Módulos de terceiros
- Licenças
- Contribuir
- Roadmap e changelog
🚧 = em desenvolvimento, pode mudar