Executando verificação de segurança...
12

Do "Internauta" à Escalabilidade Extrema ou Uma Breve História do C10k

Introdução ou As Raízes do C10K

No final dos anos 90, o problema C10K surgiu como um desafio que testava os limites do que as arquiteturas de servidores podiam suportar. Era um teste de capacidade e eficiência: um servidor web poderia servir 10.000 páginas estaticas ao "mesmo" tempo? Essa questão, brilhantemente discutida por Dan Kegel, tornou-se um ponto de referência para programadores e engenheiros, moldando o futuro das aplicações em rede e o design de servidores, banco de dados e sistemas operacionais.

Na época a Internet ainda estava em sua infância e o "internauta" era a pessoa que navegava pela rede, desbravando novos territórios. Esses aventureiros começavam a se amontuar e o problema do C10K refletia diretamente essa realidade emergente, onde os sites mais visitados da Internet começavam a demandar por este tipo de tráfego, algo complemente inimaginável poucos anos antes.

A expressão "internauta" caiu em desuso, assim como os servidores que não conseguem lidar com a alta concorrência de acessos. Entretanto naquele tempo, os servidores, enfrentavam limitações severas impostas tanto pelos sistemas operacionais quanto pela falta de conhecimento e ferramentas em arquitetura massivamente escaláveis. A programação síncrona e bloqueante era a norma, e poucos entendiam como os servidores podiam, de forma eficiente, lidar com milhares de conexões simultâneas.

As Soluções

O artigo de Kegel se destaca como um dos mais significativos na história da Internet. Ele não apenas identificou as barreiras que impediam os servidores de atingirem eficiência em grande escala, mas também discutiu todas as estratégias empregadas na época para superá-las.

A programação orientada a eventos - como adotada pelo Node.js e Nginx - era uma dessas estratégias, representando uma mudança de paradigma de como o software de servidor deveria tratar as conexões de rede, quando o padrão era um fork para cada conexão.

Além de outras técnicas tradicionais como o uso eficiente de threads e multiplexação de E/S, estes pioneiros fizeram coisas, que à primeira vista, podem parecer absurdas como incorporar o código do servidor diretamente no kernel ou utilizar implmentações customizadas de stacks TCP/IP. Entretanto considerando que epoll e pthread ainda não faziam parte do Linux essas ideias mostram como em muitos casos, a criatividade é o único obstáculo entre uma solução funcional e a falta de recursos.

Do 10k ao 10m e a Armadilha da Escalabilidade Extrema

A jornada da Internet nos trouxe a um ponto em que lidar com 10.000 conexões já não é mais um problema - agora, falamos o desafio é lidar com 10 milhões. Esta evolução não é apenas um testemunho do avanço da tecnologia, mas também um reflexo do crescimento exponencial na demanda por serviços online.

É aqui que mora a armadilha da escalabilidade extrema: muitos desenvolvedores caem na tentação de sobreengenharia, adotando soluções desenhadas para operações de magnitude muito maior do que a necessária. Para a grande maioria das aplicações, lidar com 10.000 conexões simultâneas - o velho problema C10K - ainda é um marco muito distante da demanda real, mesmo que seja um objetivo atingível.

Não há necessidade de projetar cada aplicativo como se fosse lidar com 10 milhões de solicitações; essa é uma realidade reservada a um grupo seleto de gigantes da tecnologia. Para a maioria das aplicações web, particularmente aquelas direcionadas para uma região específica, demográfico ou mercado de nicho, o problema do C10K seria um limite que raramente, se é que alguma vez, precisariam ultrapassar. Ao invés de replicar as complexas pilhas das 'big techs', compreenda profundamente o problema do C10k e nunca mais se preocupe se a sua aplicação poderá lidar com a carga dos usuários.

Conclusão ou A Importância dos Fundamentos e o Baixo Nível

Embora as tecnologias e as linguagens de programação evoluam, com desenvolvedores hoje usando desde JavaScript com Node.js ou Bun, até Rust com Tokyo ou Go com goroutines. Ou PHP com Apache ou threads em Java, uma verdade perdura: no nível mais básico, o código executado em um servidor web acaba, de uma forma ou de outra, traduzindo-se em chamadas de sistema fundamentais como epoll ou pthreads.

Estas são as estradas sobre as quais a moderna computação concorrente e assíncrona é fundamentada, independentemente das abstrações de alto nível fornecidas por linguagens e frameworks modernos. Compreender estas chamadas, é entender a mecânica essencial da programação concorrente no nível do sistema operacional. Não importa quão alta seja a abstração, os fundamentos permanecem relevantes. O uso eficiente dessas chamadas de sistema é o que permite otimizar suas aplicações para desempenho, mesmo trabalhando em níveis de abstrações muito mais altos.

Assim, ao desenvolver soluções, lembre-se de que a escalabilidade eficaz está enraizada na compreensão de como o trabalho é feito nas camadas fundamentais do software. Uma base sólida em princípios de ciência da computação, em conhecimentos de sistemas operacionais e redes de computadores são inestimáveis para qualquer desenvolvedor que deseje construir aplicações robustas e escaláveis, seja para 10k ou para 10m de usuários.

Debate

Obrigado por acompnhar até aqui, à medida que refletimos sobre o problema C10K e sua expansão para 10 milhões, convido você a compartilhar suas experiências:

  • Qual foi o maior número de solicitações concorrentes que você já precisou gerenciar? Como foi essa experiência e quais estratégias você utilizou para lidar com esse volume de tráfego?

  • Você poderia explicar, no nível mais baixo possível, como a ferramenta que você utiliza para construir aplicações lida com a concorrência? Quais são os mecanismos fundamentais em jogo, e como isso influencia o desempenho e a escalabilidade da sua aplicação?

3

Vou começar:

Qual foi o maior número de solicitações concorrentes que você já precisou gerenciar? Como foi essa experiência e quais estratégias você utilizou para lidar com esse volume de tráfego?

Aqui vou apenas deixar o video do mestre Akita: Minha Saga da Rinha de Backend

Você poderia explicar, no nível mais baixo possível, como a ferramenta que você utiliza para construir aplicações lida com a concorrência? Quais são os mecanismos fundamentais em jogo, e como isso influencia o desempenho e a escalabilidade da sua aplicação?

No Go, as goroutines são as unidades fundamentais de concorrência. Elas são gerenciadas pelo runtime scheduler da própria linguagem, que as multiplexa com um número menor de threads do sistema operacional. O runtime do Go cria algumas pthreads, e as goroutines são escalonadas nessas threads.

De certa forma, o modelo de concorrência do Go pode ser visto como um tipo de thread pool a nível da linguagem, abstraindo toda a complexidade da alocação de tarefas em recursos. Assim oferece uma maneira extremamente simples e eficiente de executar muitas tarefas de forma concorrente.