Como escalar de 1 a 100 usuários

Muitas startups passaram por isso: multidões de novos usuários se cadastram todos os dias e a equipe de desenvolvimento luta para manter o serviço funcionando.

É um problema interessante de se ter, mas há poucas informações claras na Web sobre como dimensionar cuidadosamente um aplicativo Web do nada para centenas de milhares de usuários. Normalmente existem soluções contra incêndio ou soluções para gargalos (e muitas vezes ambas). Portanto, as pessoas usam técnicas bastante clichês para transformar seu projeto amador em algo realmente sério.

Vamos tentar filtrar as informações e anotar a fórmula básica. Vamos escalar nosso novo site de compartilhamento de fotos, Graminsta, passo a passo, de 1 para 100 usuários.

Vamos anotar quais ações específicas precisam ser tomadas quando o público aumenta para 10, 100, 1000, 10 e 000 pessoas.

1 usuário: 1 máquina

Quase todos os aplicativos, seja um site ou um aplicativo móvel, possuem três componentes principais:

  • API
  • banco de dados
  • cliente (próprio aplicativo móvel ou site)

O banco de dados armazena dados persistentes. A API atende solicitações para e em torno desses dados. O cliente transmite dados ao usuário.

Cheguei à conclusão de que é muito mais fácil falar em escalar uma aplicação se, do ponto de vista arquitetônico, as entidades cliente e API estiverem completamente separadas.

Quando começamos a construir um aplicativo, todos os três componentes podem ser executados no mesmo servidor. De certa forma, isso é semelhante ao nosso ambiente de desenvolvimento: um engenheiro executa o banco de dados, a API e o cliente na mesma máquina.

Em teoria, poderíamos implantá-lo na nuvem em uma única instância DigitalOcean Droplet ou AWS EC2, conforme mostrado abaixo:
Como escalar de 1 a 100 usuários
Dito isso, se houver mais de um usuário em um site, quase sempre faz sentido dedicar uma camada de banco de dados.

10 usuários: movendo o banco de dados para um nível separado

Dividir o banco de dados em serviços gerenciados como Amazon RDS ou Digital Ocean Managed Database nos servirá bem por muito tempo. É um pouco mais caro do que a auto-hospedagem em uma única máquina ou instância EC2, mas com esses serviços você obtém muitas extensões úteis prontas para uso que serão úteis no futuro: backup multirregional, réplicas de leitura, backup automático backups e muito mais.

Esta é a aparência do sistema agora:
Como escalar de 1 a 100 usuários

100 usuários: movendo o cliente para um nível separado

Felizmente, nossos primeiros usuários gostaram muito do nosso aplicativo. O tráfego está se tornando mais estável, então é hora de mover o cliente para um nível separado. Deve-se notar que separação entidades é um aspecto fundamental da construção de um aplicativo escalável. À medida que uma parte do sistema recebe mais tráfego, podemos particioná-la para controlar como o serviço é dimensionado com base em padrões de tráfego específicos.

É por isso que gosto de pensar no cliente como algo separado da API. Isso torna muito fácil pensar em desenvolver para múltiplas plataformas: web, web móvel, iOS, Android, aplicativos de desktop, serviços de terceiros, etc.

Por exemplo, agora nossos usuários costumam pedir para lançar um aplicativo móvel. Se você separar as entidades cliente e API, isso ficará mais fácil.

Esta é a aparência de tal sistema:

Como escalar de 1 a 100 usuários

1000 usuários: adicionar balanceador de carga

Coisas estão melhorando. Os usuários do Graminsta estão enviando cada vez mais fotos. O número de inscrições também está crescendo. Nosso único servidor API está tendo dificuldades para acompanhar todo o tráfego. Precisa de mais ferro!

O balanceador de carga é um conceito muito poderoso. A ideia principal é colocar um balanceador de carga na frente da API e ele distribuir o tráfego para instâncias de serviço individuais. É assim que escalamos horizontalmente, ou seja, adicionamos mais servidores com o mesmo código, aumentando o número de solicitações que podemos processar.

Colocaremos balanceadores de carga separados na frente do cliente web e na frente da API. Isso significa que você pode executar várias instâncias executando código de API e código de cliente web. O balanceador de carga direcionará as solicitações para o servidor menos carregado.

Aqui temos outra vantagem importante – redundância. Quando uma instância falha (talvez sobrecarregada ou travada), ficamos com outras que continuam respondendo às solicitações recebidas. Se houvesse apenas uma instância funcionando, em caso de falha, todo o sistema travaria.

O balanceador de carga também fornece escalonamento automático. Podemos configurá-lo para aumentar o número de instâncias antes do pico de carga e diminuí-lo quando todos os usuários estiverem dormindo.

Com um balanceador de carga, o nível da API pode ser dimensionado quase indefinidamente, simplesmente adicionando novas instâncias à medida que o número de solicitações aumenta.

Como escalar de 1 a 100 usuários

Observação. No momento, nosso sistema é muito semelhante ao que empresas de PaaS como Heroku ou Elastic Beanstalk na AWS oferecem imediatamente (e é por isso que são tão populares). Heroku coloca o banco de dados em um host separado, gerencia um balanceador de carga com escalonamento automático e permite hospedar o cliente web separadamente da API. Este é um ótimo motivo para usar o Heroku para projetos em estágio inicial ou startups - você obtém todos os serviços básicos prontos para uso.

10 usuários: CDN

Talvez devêssemos ter feito isso desde o início. Processar solicitações e aceitar novas fotos está começando a sobrecarregar nossos servidores.

Nesta fase, você precisa utilizar um serviço em nuvem para armazenar conteúdo estático - imagens, vídeos e muito mais (AWS S3 ou Digital Ocean Spaces). Em geral, nossa API deve evitar lidar com coisas como servir imagens e fazer upload de imagens para o servidor.

Outra vantagem da hospedagem em nuvem é o CDN (a AWS chama esse complemento de Cloudfront, mas muitos provedores de armazenamento em nuvem o oferecem imediatamente). O CDN armazena automaticamente nossas imagens em vários data centers ao redor do mundo.

Embora nosso data center principal possa estar localizado em Ohio, se alguém solicitar uma imagem do Japão, o provedor de nuvem fará uma cópia e a armazenará em seu data center japonês. A próxima pessoa que solicitar esta imagem no Japão a receberá muito mais rápido. Isso é importante quando trabalhamos com arquivos grandes, como fotos ou vídeos, que demoram muito para serem baixados e transmitidos para todo o planeta.

Como escalar de 1 a 100 usuários

100 usuários: dimensionando a camada de dados

O CDN ajudou muito: o tráfego está crescendo a toda velocidade. O famoso videoblogger Mavid Mobrick acabou de se cadastrar conosco e postou sua “história”, como dizem. Graças ao balanceador de carga, o uso de CPU e memória nos servidores de API é mantido baixo (dez instâncias de API em execução), mas estamos começando a ter muitos tempos limite nas solicitações... de onde vêm esses atrasos?

Investigando um pouco as métricas, vemos que a CPU do servidor de banco de dados está 80-90% carregada. Estamos no limite.

Dimensionar a camada de dados é provavelmente a parte mais difícil da equação. Os servidores de API atendem solicitações sem estado, então simplesmente adicionamos mais instâncias de API. Nariz por maioria bancos de dados não podem fazer isso. Falaremos sobre sistemas populares de gerenciamento de banco de dados relacional (PostgreSQL, MySQL, etc.).

cache

Uma das maneiras mais fáceis de aumentar o desempenho do nosso banco de dados é introduzir um novo componente: a camada de cache. O método de armazenamento em cache mais comum é um armazenamento de registros de valores-chave na memória, como Redis ou Memcached. A maioria das nuvens possui uma versão gerenciada destes serviços: Elasticache na AWS e Memorystore no Google Cloud.

Um cache é útil quando um serviço faz muitas chamadas repetidas ao banco de dados para recuperar as mesmas informações. Essencialmente, acessamos o banco de dados apenas uma vez, armazenamos as informações no cache e não as tocamos novamente.

Por exemplo, em nosso serviço Graminsta, toda vez que alguém acessa a página de perfil da estrela Mobrik, o servidor API consulta o banco de dados em busca de informações de seu perfil. Isso acontece repetidamente. Como as informações do perfil do Mobrik não mudam a cada solicitação, ele é excelente para armazenamento em cache.

Armazenaremos em cache os resultados do banco de dados no Redis por chave user:id com um período de validade de 30 segundos. Agora, quando alguém acessa o perfil do Mobrik, primeiro verificamos o Redis e, se os dados estiverem lá, simplesmente os transferimos diretamente do Redis. Agora as solicitações para o perfil mais popular do site praticamente não carregam nosso banco de dados.

Outra vantagem da maioria dos serviços de cache é que eles são mais fáceis de escalar do que os servidores de banco de dados. Redis possui um modo Redis Cluster integrado. Semelhante a um balanceador de carga1, ele permite distribuir o cache Redis em várias máquinas (em milhares de servidores, se necessário).

Quase todos os aplicativos de grande escala usam cache; é uma parte absolutamente integrante de uma API rápida. Processamento de consultas mais rápido e código mais produtivo são importantes, mas sem cache é quase impossível escalar um serviço para milhões de usuários.

Ler réplicas

Quando o número de consultas ao banco de dados aumentou muito, mais uma coisa que podemos fazer é adicionar réplicas de leitura no sistema de gerenciamento de banco de dados. Com os serviços gerenciados descritos acima, isso pode ser feito com um clique. A réplica de leitura permanecerá atual no banco de dados principal e estará disponível para instruções SELECT.

Aqui está nosso sistema agora:

Como escalar de 1 a 100 usuários

Próximas Etapas

À medida que o aplicativo continua a ser dimensionado, continuaremos a separar os serviços para escalá-los de forma independente. Por exemplo, se começarmos a usar Websockets, faz sentido colocar o código de processamento dos Websockets em um serviço separado. Podemos colocá-lo em novas instâncias por trás de nosso próprio balanceador de carga, que pode aumentar ou diminuir com base em conexões Websockets abertas e independentemente do número de solicitações HTTP.

Também continuaremos a combater as restrições ao nível da base de dados. É neste estágio que é hora de estudar o particionamento e a fragmentação do banco de dados. Ambas as abordagens exigem sobrecarga adicional, mas permitem dimensionar o banco de dados quase indefinidamente.

Também queremos instalar um serviço de monitoramento e análise como New Relic ou Datadog. Isso o ajudará a identificar consultas lentas e entender onde melhorias são necessárias. À medida que expandimos, queremos nos concentrar em encontrar gargalos e eliminá-los, geralmente usando algumas das ideias das seções anteriores.

fontes

Este post é inspirado em um dos meus posts favoritos sobre alta escalabilidade. Queria deixar o artigo um pouco mais específico para as etapas iniciais dos projetos e desvinculá-lo de um fornecedor. Não deixe de ler se estiver interessado neste tópico.

Notas de rodapé

  1. Embora semelhante em termos de distribuição de carga entre múltiplas instâncias, a implementação subjacente de um cluster Redis é muito diferente de um balanceador de carga. [retornar]

Como escalar de 1 a 100 usuários

Fonte: habr.com

Adicionar um comentário