Saudações! Este é um pequeno artigo que responde às perguntas: “o que é enviado?”, “por que é necessário?” e "por onde começar?".
O que é isto
Envoy é um balanceador L4-L7 escrito em C++, focado em alto desempenho e disponibilidade. Por um lado, este é de alguma forma um análogo do nginx e do haproxy, comparável em desempenho a eles. Por outro lado, é mais orientado para a arquitetura de microsserviços e não possui funcionalidade pior que os balanceadores java e go, como zuul ou traefik.
Tabela de comparação de haproxy/nginx/envoy, não afirma ser a verdade absoluta, mas dá uma visão geral.
nginx
haproxy
enviado
Traefik
estrelas no github
11.2 mil/espelho
1.1 mil/espelho
12.4k
27.6k
escrito em
C
C
C + +
go
API
não
apenas soquete/empurrar
plano de dados/pull
puxar
verificação de saúde ativa
não
sim
sim
sim
Rastreamento aberto
plug-in externo
não
sim
sim
JWT
plug-in externo
não
sim
não
extensão
Lua/C
Lua/C
Lua/C++
não
Porquê
Este é um projeto jovem, faltam muitas coisas, algumas no início do alfa. Mas enviado, também por ser jovem, está se desenvolvendo rapidamente e já possui muitos recursos interessantes: configuração dinâmica, muitos filtros prontos, uma interface simples para escrever seus próprios filtros.
As áreas de aplicação decorrem disso, mas primeiro existem 2 antipadrões:
- Recuo estático.
O fato é que neste momento enviado sem suporte de cache. Os caras do Google estão tentando isso
Por enquanto, use nginx para estática.
- Configuração estática.
Você pode usá-lo, mas enviado Não foi para isso que foi criado. Os recursos em uma configuração estática não serão expostos. São muitos momentos:
Ao editar a configuração no yaml, você se enganará, repreenderá os desenvolvedores pela verbosidade e pensará que as configurações do nginx/haproxy, embora menos estruturadas, são mais concisas. Essa é a questão. A configuração do Nginx e Haproxy foi criada para edição manual e enviado para geração a partir do código. Toda a configuração está descrita em
Cenários de implantação Canary, b/g e muito mais são normalmente implementados apenas em uma configuração dinâmica. Não estou dizendo que isso não possa ser feito estaticamente, todos nós fazemos isso. Mas para isso é necessário usar muletas, em qualquer um dos balanceadores, em enviado incluindo
Tarefas para as quais o Envoy é indispensável:
- Balanceamento de tráfego em sistemas complexos e dinâmicos. Isto inclui a malha de serviço, mas não é necessariamente a única.
- A necessidade de funcionalidade de rastreamento distribuído, autorização complexa ou outra funcionalidade disponível em enviado pronto para uso ou convenientemente implementado, mas no nginx/haproxy você precisa estar cercado por lua e plug-ins duvidosos.
Ambos, se necessário, proporcionam alto desempenho.
Как это работает
O Envoy é distribuído em binários apenas como uma imagem docker. A imagem já contém um exemplo de configuração estática. Mas estamos interessados nisso apenas para compreender a estrutura.
configuração estática envoy.yaml
static_resources:
listeners:
- name: listener_0
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 10000
filter_chains:
- filters:
- name: envoy.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: "/"
route:
host_rewrite: www.google.com
cluster: service_google
http_filters:
- name: envoy.router
clusters:
- name: service_google
connect_timeout: 0.25s
type: LOGICAL_DNS
# Comment out the following line to test on v6 networks
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: service_google
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: www.google.com
port_value: 443
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.api.v2.auth.UpstreamTlsContext
sni: www.google.com
Configuração dinâmica
Para qual problema estamos procurando uma solução? Você não pode simplesmente recarregar a configuração do balanceador de carga sob carga; surgirão “pequenos” problemas:
- Validação de configuração.
A configuração pode ser grande, pode ser muito grande, se sobrecarregarmos tudo de uma vez, as chances de ocorrer um erro em algum lugar aumentam.
- Conexões duradouras.
Ao inicializar um novo ouvinte, você precisa cuidar das conexões em execução no antigo; se as alterações ocorrerem com frequência e houver conexões de longa duração, você terá que procurar um compromisso. Olá, entrada do Kubernetes no nginx.
- Verificações de saúde ativas.
Se tivermos verificações de integridade ativas, precisaremos verificar todas elas na nova configuração antes de enviar o tráfego. Se houver muitos upstreams, isso leva tempo. Olá haproxy.
Como isso é resolvido em enviadoAo carregar a configuração dinamicamente, de acordo com o modelo do pool, você pode dividi-la em partes separadas e não reinicializar a parte que não foi alterada. Por exemplo, um ouvinte cuja reinicialização é cara e raramente muda.
Configuração enviado (do arquivo acima) possui as seguintes entidades:
- ouvinte — ouvinte pendurado em um ip/porta específico
- host virtual - host virtual por nome de domínio
- estrada - regra de equilíbrio
- cacho — um grupo de upstreams com parâmetros de balanceamento
- Ponto final — endereço da instância upstream
Cada uma dessas entidades e algumas outras podem ser preenchidas dinamicamente; para isso, a configuração especifica o endereço do serviço de onde a configuração será recebida. O serviço pode ser REST ou gRPC, gRPC é preferível.
Os serviços são nomeados respectivamente: LDS, VHDS, RDS, CDS e EDS. Você pode combinar configuração estática e dinâmica, com a limitação de que um recurso dinâmico não pode ser especificado em um recurso estático.
Para a maioria das tarefas basta implementar os três últimos serviços, eles são chamados de ADS (Aggregated Discovery Service), por
A configuração assume o seguinte formato:
configuração dinâmica envoy.yaml
dynamic_resources:
ads_config:
api_type: GRPC
grpc_services:
envoy_grpc:
cluster_name: xds_clr
cds_config:
ads: {}
static_resources:
listeners:
- name: listener_0
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 10000
filter_chains:
- filters:
- name: envoy.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
stat_prefix: ingress_http
rds:
route_config_name: local_route
config_source:
ads: {}
http_filters:
- name: envoy.router
clusters:
- name: xds_clr
connect_timeout: 0.25s
type: LOGICAL_DNS
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: xds_clr
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: xds
port_value: 6565
Quando você executa enviado com esta configuração, ele se conectará ao plano de controle e tentará solicitar a configuração RDS, CDS e EDS. Como ocorre o processo de interação é descrito
Em resumo, enviado envia uma solicitação indicando o tipo de recurso solicitado, a versão e os parâmetros do nó. Em resposta, recebe um recurso e uma versão; se a versão no plano de controle não mudou, ele não responde.
Existem 4 opções de interação:
- Um fluxo gRPC para todos os tipos de recursos, o status completo do recurso é enviado.
- Fluxos separados, em perfeitas condições.
- Um fluxo, estado incremental.
- Fluxos separados, estado incremental.
O xDS incremental permite reduzir o tráfego entre o plano de controle e enviado, isso é relevante para configurações grandes. Mas isso complica a interação: a solicitação contém uma lista de recursos para cancelar e assinar.
Nosso exemplo usa ADS - um fluxo para RDS, CDS, EDS e modo não incremental. Para ativar o modo incremental, você precisa especificar api_type: DELTA_GRPC
Como a solicitação contém parâmetros de nó, podemos enviar diferentes recursos ao plano de controle para diferentes instâncias enviado, isso é conveniente para construir uma malha de serviço.
Aquecer
На enviado na inicialização ou ao receber uma nova configuração do plano de controle, o processo de aquecimento de recursos é iniciado. É dividido em aquecimento do ouvinte e aquecimento do cluster. O primeiro é lançado quando há alterações no RDS/LDS, o segundo quando há alterações no CDS/EDS. Isso significa que se apenas os upstreams mudarem, o ouvinte não será recriado.
Durante o processo de aquecimento, são esperados recursos dependentes do plano de controle durante o tempo limite. Se o tempo limite ocorrer, a inicialização não será bem-sucedida e o novo ouvinte não começará a escutar na porta.
Ordem de inicialização: EDS, CDS, verificação de saúde ativa, RDS, LDS. Com as verificações de integridade ativas habilitadas, o tráfego subirá somente após uma verificação de integridade bem-sucedida.
Se o ouvinte foi recriado, o antigo entra no estado DRAIN e será excluído após todas as conexões serem fechadas ou o tempo limite expirar --drain-time-s
, padrão 10 minutos.
Para ser continuado.
Fonte: habr.com