19 pontos por xguru 2020-08-10 | 3 comentários | Compartilhar no WhatsApp
<p>Um texto que explica muito bem as vantagens do Envoy em relação ao Nginx na Dropbox, que lida com dezenas de milhões de conexões simultâneas, milhões de requisições por segundo e largura de banda na casa dos terabytes<br /> <br /> Antes: nginx (versão open source) + python2 + Jinja2 + YAML <br /> → mesmo que só uma coisa mudasse, era preciso redeploy de tudo<br /> → as partes dinâmicas eram desenvolvidas em Lua<br /> → a lógica complexa era tratada no Bandaid, um proxy em Go<br /> <br /> Isso funcionou bem por quase 10 anos, mas já não se encaixa bem no ambiente atual<br /> → as APIs internas e externas (privadas) estão migrando gradualmente de REST para gRPC, então precisam de recursos de transcoding no proxy<br /> → Protocol Buffers virou o padrão interno de definição de serviços <br /> → todos os softwares são compilados e testados com Bazel, independentemente da linguagem<br /> → os funcionários participam bastante das comunidades open source dos principais projetos de infraestrutura <br /> <br /> O Nginx também era caro de manter do ponto de vista operacional<br /> → a lógica de geração de config era flexível demais e estava espalhada entre YAML, Jinja2 e Python<br /> → o monitoramento era uma mistura de Lua / parsing de logs / monitoramento baseado em sistema<br /> → a dependência crescente de módulos de terceiros afetava estabilidade/desempenho e gerava custo com upgrades frequentes <br /> → o deploy e o gerenciamento de processos do nginx são bem diferentes dos demais serviços. Dependem bastante de coisas fora do sistema padrão, como syslog e logrotate<br /> <br /> Por isso, pela primeira vez em 10 anos, decidiram procurar um substituto para o Nginx<br /> <br /> * Por que não migrar para o Bandaid (proxy em Go desenvolvido pela Dropbox)? * <br /> → Go consome mais recursos do que C/C++. <br /> → a stack TLS do Go não suporta FIPS (Federal Information Processing Standards dos EUA)<br /> → por ser uma ferramenta interna, não é possível contar com suporte da comunidade externa <br /> <br /> Agora: migração para uma infraestrutura de tráfego baseada em Envoy <br /> <br /> ----- Pontos em que o Envoy foi melhor que o Nginx ------<br /> <br /> * Desempenho *<br /> <br /> A arquitetura do Nginx é event-driven / multiprocesso. Suporta SO_REUSEPORT &amp; EPOLLEXCLUSIVE<br /> Embora seja baseada em event loop, não é totalmente non-blocking. Ao abrir arquivos ou gravar logs, o event loop pode parar. (mesmo com `aio`, `aio_write` e threadpool ativados)<br /> Isso gerava latência de cauda e, às vezes, atrasos de vários segundos<br /> <br /> O Envoy também tem arquitetura event-driven, mas baseada em threads em vez de processos <br /> Suporta SO_REUSEPORT (com suporte a filtro BPF) e event loop via libevent <br /> Não há I/O bloqueante no event loop. O logging de eventos também é implementado de forma non-blocking.<br /> <br /> Na teoria, parecia que os dois teriam características de desempenho parecidas, e na prática isso se confirmou na maioria dos testes de workload.<br /> Mas o Nginx mostrou latência maior na long tail. O motivo era a interrupção do event loop quando havia muito I/O.<br /> <br /> Sem coleta de estatísticas, o Nginx tinha desempenho parecido com o Envoy, mas a ferramenta interna de coleta de métricas em Lua deixava o Nginx 3x mais lento em testes de alto RPS. (isso por causa do `lua_shared_dict`, sincronizado por mutex). Havia problemas na forma como a Dropbox coletava estatísticas, mas eles desistiram de reimplementar isso de forma eficiente. (porque preveram que instrumentar o interior do Nginx dificultaria upgrades futuros)<br /> <br /> De todo modo, como o Envoy não tinha esses problemas, depois da migração foi possível liberar até 60% dos servidores que antes eram usados pelo Nginx.<br /> <br /> * Observabilidade *<br /> <br /> A versão gratuita do Nginx oferece apenas 7 estatísticas no módulo stub status <br /> Como isso obviamente era insuficiente, eles usavam um handler `log_by_lua` para expor mais métricas.<br /> Também havia um parser de `error.log` para exportar erros e um exporter separado para expor estados internos do nginx.<br /> <br /> Uma configuração básica do Envoy já fornece milhares de métricas diferentes em formato Prometheus <br /> Desde informações de tráfego do proxy até estado interno do servidor,<br /> estatísticas por cluster / upstream / virtual host e métricas downstream TCP/HTTP/TLS por listener etc.<br /> <br /> Junto com essas várias estatísticas, o Envoy também permite plugar Tracing Providers.<br /> Isso é útil não só para o time de tráfego, mas também para desenvolvedores de aplicações.<br /> <br /> Por fim, o Envoy consegue fazer streaming de access logs via gRPC.<br /> Isso reduz a carga de manter a bridge syslog-to-hive do time de tráfego.<br /> Rodar um serviço gRPC comum é bem mais fácil e seguro do que acoplar listeners TCP/UDP customizados.<br /> <br /> * Integração *<br /> <br /> A integração do Nginx é muito “Unix-like”. A configuração é bem estática.<br /> Depende de arquivos para config, certificados TLS, allowlist/blocklist etc.<br /> Isso é simples e compatível com versões anteriores, então dá para automatizar com alguns scripts shell,<br /> mas, conforme o sistema cresce, testabilidade e padronização vão ficando cada vez mais importantes.<br /> <br /> O Envoy tem sua própria abordagem para esse tipo de integração.<br /> Ele oferece uma API chamada xDS, incentivando o uso de protobuf e gRPC.<br /> O Envoy encontra recursos dinâmicos consultando esse xDS.<br /> <br /> - O xDS já está evoluindo para além do Envoy como a Universal Data Place API (UDPA), tentando virar o padrão de facto para load balancers L4/L7, e, pela experiência deles, isso está caminhando bem. Eles também estão tentando usar UDPA no Katran, o load balancer L4 eBPF/XDP, não só no Envoy.<br /> <br /> Como a Dropbox já integra seus serviços internamente via gRPC, isso se encaixa muito melhor.<br /> <br /> * Configuração *<br /> <br /> O Nginx tem como grande vantagem arquivos de configuração fáceis para humanos lerem. <br /> Mas essa vantagem vai se perdendo à medida que a configuração fica mais complexa e passa a ser gerada automaticamente.<br /> Na Dropbox, como era gerada por Python2, Jinja2 e YAML, o modelo de dados acabou ficando confuso e complexo.<br /> <br /> O Envoy tem um modelo de dados unificado para configuração. Todos os valores são definidos em Protocol Buffers. Isso resolve problemas de modelagem de dados e adiciona informação de tipo às configs.<br /> Como protobuf já é muito usado internamente na Dropbox, a integração fica fácil <br /> <br /> * Extensibilidade * <br /> <br /> Para expandir o Nginx, é preciso escrever módulos em C. Para criar módulos seguros, são necessários desenvolvedores sêniores. Ele até oferece interfaces em Perl / JS para módulos mais leves, mas elas são muito limitadas. Por isso, o caminho mais comum acaba sendo via `lua-nginx-module`. <br /> <br /> O principal mecanismo de extensão do Envoy é por plugins em C++, e embora a documentação não seja tão boa quanto a do nginx, isso é bem simples. Isso se deve a interfaces limpas e bem comentadas, além de C++14 e da biblioteca padrão <br /> <br /> O grande diferencial do Envoy em relação a outros web servers é o suporte a WebAssembly (WASM).<br /> Isso permite desenvolver extensões em várias linguagens, como Rust. <br /> A Dropbox ainda não usa WASM, mas isso pode mudar no futuro se houver suporte ao Go SDK para proxy-wasm<br /> <br /> * Build e testes *<br /> <br /> O Nginx usa por padrão configuração customizada baseada em shell e build baseado em `make`. É simples e ótimo, mas integrar isso a um monorepo compilado com Bazel exige bastante esforço <br /> O Nginx tem testes de integração em Perl, mas não tem testes unitários.<br /> <br /> O Envoy já usa um sistema de build baseado em Bazel e foi integrado facilmente ao monorepo deles.<br /> Também oferece testes unitários com gtest/gmock e framework de testes de integração<br /> <br /> * Segurança *<br /> <br /> O código do Nginx é bem pequeno e tem poucas dependências externas, então não apresenta muitas vulnerabilidades de segurança.<br /> <br /> O Envoy tem muito mais código, então naturalmente parece ter mais superfície de ataque. Para compensar isso, o Envoy depende fortemente de práticas modernas de segurança, usando AddressSanitizer, ThreadSanitizer, MemorySanitizer etc. <br /> <br /> * Recursos * <br /> <br /> Essa parte tem bastante opinião subjetiva, então vale considerar isso ao ler<br /> <br /> O Nginx começou como um web server para servir arquivos estáticos com pouquíssimos recursos. <br /> Ou seja, suas funções principais são static serving, caching e range caching<br /> Do ponto de vista de proxy, o Nginx carece bastante de recursos que a infraestrutura atual exige. <br /> Não faz conexão HTTP/2 com backends, não funciona como proxy gRPC multiplexado, não faz gRPC transcoding etc.<br /> Como usa um modelo de licença open core, alguns recursos importantes ficam fora da “versão comunitária”<br /> <br /> O Envoy, por outro lado, já nasceu como proxy de ingress/egress e é muito usado em ambientes com alta carga de gRPC.<br /> Os recursos de web service ainda são bem básicos. Ele não serve arquivos, o cache ainda está em desenvolvimento e ainda não suporta brotli etc. <br /> Para esse tipo de ambiente, eles ainda usam setups com Nginx tendo o Envoy como upstream cluster <br /> A expectativa é que, quando o Envoy passar a suportar cache HTTP, esses ambientes de serving estático também possam migrar <br /> <br /> O Envoy oferece muitos recursos ligados a gRPC<br /> - proxying de gRPC<br /> - HTTP/2 para backends<br /> - bridge gRPC → HTTP (+ reverso) <br /> - gRPC-WEB <br /> - transcoder JSON para gRPC<br /> <br /> Além disso, o Envoy também pode ser usado como proxy de saída <br /> - Egress Proxy<br /> - service discovery de software de terceiros com a biblioteca Courier gRPC <br /> <br /> * Comunidade *<br /> <br /> O desenvolvimento do Nginx é centralizado e, em grande parte, fechado. <br /> O desenvolvimento do Envoy é aberto e descentralizado. Acontece via issues/PRs no GitHub, além de bastante atividade em mailing lists e Slack </p><p>----- Estado atual da migração na Dropbox -----<br /> <br /> Eles estão operando Nginx e Envoy juntos há meio ano e migrando o tráfego gradualmente via DNS <br /> A migração não foi totalmente sem problemas: houve pequenos incidentes, mas nenhuma falha grave.<br /> Também organizaram soluções para problemas causados por comportamentos “unusual” ou “non-RFC” (veja o texto original para os detalhes)<br /> <br /> ** Próximos passos **<br /> <br /> - HTTP/3: o Envoy também começou a oferecer suporte experimental. Eles pretendem testar isso após atualizar o kernel Linux para acelerar UDP<br /> - load balancer interno baseado em xDS e Outlier Detection<br /> - extensões Envoy baseadas em WASM <br /> - substituir o Bandaid (proxy em Go) por Envoy <br /> - aplicar Envoy também em apps mobile com Envoy Mobile</p>

3 comentários

 
baeba 2020-08-13
<p>Obrigado por resumir um conteúdo tão bom<br /> de forma simples.<br /> Agradeço.</p>
 
before30 2020-08-11
<p>Obrigado. :)</p>
 
loslch 2020-08-11
<p>A organização detalhada e até os comentários gentis ajudaram muito na compreensão. Obrigado :)</p>