Como escalar de 1 a 100.000 usuários

Muitas startups passaram por isso: multidões de novos usuários são registrados todos os dias, e a equipe de desenvolvimento está lutando para apoiar o trabalho do serviço.

Esse é um problema agradável, mas há poucas informações claras na Web sobre como dimensionar com precisão um aplicativo Web de zero a centenas de milhares de usuários. Geralmente, existem soluções de incêndio ou a eliminação de gargalos (e geralmente ambos). Portanto, as pessoas usam truques bastante estereotipados para dimensionar seu projeto amador em algo realmente sério.

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

Anotaremos quais ações específicas precisam ser feitas ao aumentar o público para 10, 100, 1000, 10 000 e 100 000 pessoas.

1 usuário: 1 carro


Quase todo aplicativo, seja um site ou aplicativo mĂłvel, possui trĂŞs componentes principais:

  • API
  • base de dados
  • cliente (aplicativo para celular ou site)

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

Cheguei à conclusão de que é muito mais fácil falar sobre dimensionar um aplicativo se, do ponto de vista da arquitetura, as entidades clientes e as APIs estiverem completamente separadas.

Quando começamos a criar um aplicativo, todos os três componentes podem ser executados no mesmo servidor. De certa forma, isso nos lembra nosso ambiente de desenvolvimento: um engenheiro executa o banco de dados, a API e o cliente no mesmo computador.

Teoricamente, poderíamos implantá-lo na nuvem em uma instância do DigitalOcean Droplet ou AWS EC2, como mostrado abaixo:

Com isso dito, se o site tiver mais de um usuário, quase sempre faz sentido destacar o nível do banco de dados.

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


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

É assim que o sistema agora parece:

100 usuários: levando o cliente a um nível separado


Felizmente, nosso aplicativo realmente gostou dos primeiros usuários. 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 a separação de entidades é um aspecto essencial da criação de um aplicativo escalável. Como uma parte do sistema recebe mais tráfego, podemos dividi-lo para controlar o dimensionamento do serviço com base em padrões de tráfego específicos.

É por isso que gosto de representar o cliente separadamente da API. Isso facilita muito o desenvolvimento de várias plataformas: Web, Web móvel, iOS, Android, aplicativos de desktop, serviços de terceiros etc. Todos eles são apenas clientes que usam a mesma API.

Por exemplo, agora nossos usuários geralmente solicitam o lançamento de um aplicativo móvel. A separação de entidades clientes e APIs facilita isso.

Aqui está a aparência do sistema:



1000 usuários: adicionar balanceador de carga


As coisas estão indo bem. Os usuários do Graminsta estão carregando mais e mais fotos. O número de registros também está crescendo. Nosso servidor API solitário tem dificuldade em gerenciar todo o tráfego. Precisa de mais ferro!

O balanceador de carga é um conceito muito poderoso. A idéia principal é colocar o balanceador na frente da API e distribuir o tráfego entre instâncias de serviço individuais. Essa é a maneira do dimensionamento horizontal, ou seja, adicionamos mais servidores com o mesmo código, aumentando o número de solicitações que podemos processar.

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

Aqui temos outra vantagem importante - redundância. Quando uma instância falha (possivelmente sobrecarrega ou trava), ainda temos outras que ainda respondem a solicitações recebidas. Se uma única instância funcionasse, no caso de uma falha, todo o sistema cairia.

O balanceador de carga também fornece dimensionamento automático. Podemos configurá-lo para aumentar o número de instâncias antes do pico de carregamento e reduzir quando todos os usuários dormem.

Com um balanceador de carga, o nível da API pode ser escalado para o infinito, apenas adicionamos novas instâncias à medida que o número de solicitações aumenta.


. , PaaS, Heroku Elastic Beanstalk AWS ( ). Heroku , - API. , Heroku — .

10 000 : CDN


Talvez devesse ter sido feito desde o começo. Processar solicitações e tirar novas fotos estão começando a carregar muito nossos servidores.

Nesta fase, você precisa usar um serviço de 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 processar coisas como o upload de imagens e o upload de imagens para um servidor.

Outra vantagem da hospedagem na nuvem é sua CDN (na AWS, esse complemento é chamado Cloudfront, mas muitos serviços de armazenamento na nuvem o oferecem imediatamente). A CDN armazena em cache automaticamente nossas imagens em vários data centers ao redor do mundo.

Embora nosso centro de dados principal possa estar localizado em Ohio, mas se alguém solicitar uma imagem do Japão, o provedor de nuvem fará uma cópia e salvará em seu centro de dados japonês. A próxima pessoa a solicitar esta imagem no Japão receberá muito mais rapidamente. Isso é importante quando trabalhamos com arquivos grandes, como fotos ou vídeos, que levam muito tempo para serem carregados e transmitidos por todo o planeta.



100.000 usuários: escala no nível de dados


A CDN realmente ajudou: o tráfego está crescendo a toda velocidade. O famoso video blogueiro, Maid Mobrick, acaba de se registrar conosco e postar sua história, como eles dizem. Graças ao balanceador de carga, o nível de CPU e uso de memória nos servidores da API é mantido baixo (dez instâncias da API estão em execução), mas estamos começando a receber muitos tempos limite para solicitações ... de onde vieram esses atrasos?

Após uma pequena escavação nas métricas, vemos que a CPU no servidor de banco de dados está carregada de 80 a 90%. Estamos no limite.

Escalar a camada de dados é provavelmente a parte mais difícil da equação. Os servidores de API atendem solicitações sem estado, portanto, apenas adicionamos mais instâncias de API. Mas com maisbancos de dados não são bem-sucedidos. Discutiremos os populares sistemas de gerenciamento de banco de dados relacional (PostgreSQL, MySQL, etc.).

Armazenamento em cache


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

O cache é útil quando um serviço faz muitas chamadas repetidas para o banco de dados para obter as mesmas informações. De fato, acessamos o banco de dados apenas uma vez, salvamos as informações no cache - e não tocamos mais nele.

Por exemplo, em nosso serviço Graminsta, toda vez que alguém acessa a página de perfil do Mobric star, o servidor da API solicita informações de seu perfil no banco de dados. Isso acontece repetidamente. Como as informações de perfil da Mobrick não mudam a cada solicitação, elas são ótimas para armazenar em cache.

Armazenaremos em cache os resultados do banco de dados no Redis por chave, user:idcom um período de validade de 30 segundos. Agora, quando alguém entra no perfil de Mobrick, primeiro verificamos o Redis e, se os dados estiverem lá, simplesmente transferimos diretamente do Redis. Agora, as consultas ao 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 dimensionar do que os servidores de banco de dados. O Redis possui um modo de cluster Redis Cluster interno. Como um balanceador de carga1 1, permite distribuir o cache Redis em várias máquinas (em milhares de servidores, se necessário).

Quase todos os aplicativos de larga escala usam cache; essa é uma parte absolutamente integrante da API rápida. Processamento de solicitação mais rápido e código mais produtivo - tudo isso é importante, mas sem um cache é quase impossível dimensionar o serviço para milhões de usuários.

Lendo réplicas


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

Aqui está o nosso sistema agora:



Ações futuras


À medida que o aplicativo continua em escala, continuaremos a separar os serviços para escalá-los independentemente. Por exemplo, se começarmos a usar Websockets, faz sentido extrair o código de processamento dos Websockets para um serviço separado. Podemos colocá-lo em novas instâncias atrás de nosso próprio balanceador de carga, que pode ser ampliado ou diminuído dependendo das conexões abertas dos Websockets e independentemente do número de solicitações HTTP.

Também continuamos a lutar contra as restrições no nível do banco de dados. É nesta fase que chegou a hora de estudar o particionamento e o sharding do banco de dados. Ambas as abordagens exigem sobrecarga adicional, mas permitem que você dimensione o banco de dados quase até o infinito.

Também queremos instalar um serviço de monitoramento e análise como New Relic ou Datadog. Isso identificará consultas lentas e entenderá onde é necessário melhorar. À medida que escalamos, queremos nos concentrar em encontrar gargalos e resolvê-los - geralmente usando algumas idéias das seções anteriores.

Fontes


Esta postagem foi inspirada em uma das minhas postagens favoritas de alta escalabilidade . Eu queria concretizar um pouco o artigo para as etapas iniciais dos projetos e desatá-lo de um fornecedor. Certifique-se de ler se você está interessado neste tópico.

Notas de rodapé


  1. Apesar das semelhanças em termos de balanceamento de carga em várias instâncias, a implementação básica do cluster Redis é muito diferente do balanceador de carga. [para retornar]



Source: https://habr.com/ru/post/undefined/


All Articles