🚀 Oferta especial: 60% OFF no CrazyStack - Últimas vagas!Garantir vaga →
Guia Completo

Guia Completo Escalabilidade Web

Do básico ao avançado: técnicas para escalar aplicações web

Arquitetura Moderna

Escalando Aplicações Web Do Zero ao Milhão

Domine os conceitos de system design: microserviços, load balancing, caching, sharding e arquiteturas distribuídas para aplicações que suportam milhões de usuários.

1M+
Usuários Suportados
100%
Alta Disponibilidade
0%
Single Point of Failure
Escalabilidade
infraestrutura-inicial.ts
// API monolítica com DB local export const server = { api: 'api.meusite.com', backend: 'Node.js | Java | Python', database: 'Localhost', status: 'acoplado e falho' }

Fundamentos da Arquitetura Escalável

Entenda como evoluir de uma arquitetura básica para uma estrutura resiliente e escalável por meio da separação de responsabilidades e eliminação de pontos únicos de falha.

Separação de Serviços

Aplicação e banco de dados devem estar em servidores distintos. Isso evita disputa por recursos e melhora a escalabilidade individual de cada parte.

Redundância e Alta Disponibilidade

Uma arquitetura robusta deve ter capacidade de failover automático com múltiplas instâncias para tolerância a falhas.

Técnicas Essenciais

Componentes cruciais para rodar aplicações robustas e altamente escaláveis

Escala Horizontal

Crie múltiplas instâncias da sua aplicação para distribuir requisições e eliminar gargalos

Load Balancer

Distribui o tráfego entre servidores automaticamente e melhora a performance

Isolamento de Falhas

Evite que falhas em um ponto prejudiquem toda a aplicação

Estratégias de Escalabilidade

Use as estratégias certas no momento certo para dar um passo além em sua arquitetura.

Escala Vertical

Adiciona mais recursos (CPU, memória) ao servidor. Funciona por um tempo, mas tem limite físico e não elimina pontos únicos de falha.

Escala Horizontal

Duplica instâncias da aplicação em servidores diferentes para distribuir requisições e garantir alta disponibilidade.

Arquitetura Prática

Implementações reais de padrões de escalabilidade usando Node.js, Docker e Kubernetes.

Load Balancer com NGINX

 # nginx.conf
              upstream backend {
                server 192.168.1.10:3000 weight=3;
                server 192.168.1.11:3000 weight=2;
                server 192.168.1.12:3000 weight=1;
                server 192.168.1.13:3000 backup;
              }
              
              server {
                listen 80;
                location / {
                  proxy_pass http://backend;
                  proxy_set_header Host $host;
                  proxy_set_header X-Real-IP $remote_addr;
                  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                  
                  # Health check
                  proxy_connect_timeout 3s;
                  proxy_send_timeout 3s;
                  proxy_read_timeout 3s;
                }

Configuração de load balancer com peso diferenciado e servidor backup para failover automático. Inclui health checks e timeouts para detecção rápida de falhas.

Cache Distribuído com Redis


                const redis = require('redis');
              const client = redis.createCluster({
                rootNodes: [
                  { host: 'redis-1.cluster.local', port: 6379 },
                  { host: 'redis-2.cluster.local', port: 6379 },
                  { host: 'redis-3.cluster.local', port: 6379 }
                ],
                defaults: {
                  socket: {
                    reconnectStrategy: (retries) => Math.min(retries * 50, 500)
                  }
                }
              });
              
              // Cache com TTL automático
              const cacheUser = async (userId, userData) => {
                const key = `user:${userId}`;
                await client.setEx(key, 3600, JSON.stringify(userData)); // 1 hora
              };
              
              // Cache invalidation pattern
              const invalidateUserCache = async (userId) => {
                const patterns = [`user:${userId}`, `user:${userId}:*`];
                for (const pattern of patterns) {
                  const keys = await client.keys(pattern);
                  if (keys.length > 0) await client.del(keys);
                }
              };{
              

Sistema de cache distribuído com cluster Redis, incluindo estratégias de TTL, invalidação de cache e recuperação automática de conexões.

Microserviços Arquitetura

Service Discovery


                  // consul-service.js
              const consul = require('consul')();
              
              const registerService = async (name, port) => {
                const serviceId = `${name}-${process.env.HOSTNAME}`;
                
                await consul.agent.service.register({
                  id: serviceId,
                  name: name,
                  port: port,
                  address: process.env.HOSTNAME,
                  check: {
                    http: `http://${process.env.HOSTNAME}:${port}/health`,
                    interval: '10s',
                    timeout: '3s',
                    deregistercriticalserviceafter: '30s'
                  }
                });
                
                console.log(`Service ${name} registered with ID: ${serviceId}`);
              };
              
              const discoverService = async (serviceName) => {
                const services = await consul.health.service(serviceName);
                return services[0].map(s => ({
                  host: s.Service.Address,
                  port: s.Service.Port
                }));
              };
              

Circuit Breaker


                 class CircuitBreaker {
                constructor(options = {}) {
                  this.failureThreshold = options.failureThreshold || 5;
                  this.resetTimeout = options.resetTimeout || 10000;
                  this.failureCount = 0;
                  this.state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN
                  this.nextAttempt = Date.now();
                }
              
                async call(fn, ...args) {
                  if (this.state === 'OPEN') {
                    if (Date.now() < this.nextAttempt) {
                      throw new Error('Circuit breaker is OPEN');
                    }
                    this.state = 'HALF_OPEN';
                  }
              
                  try {
                    const result = await fn(...args);
                    this.onSuccess();
                    return result;
                  } catch (error) {
                    this.onFailure();
                    throw error;
                  }
                }
              
                onSuccess() {
                  this.failureCount = 0;
                  this.state = 'CLOSED';
                }
              
                onFailure() {
                  this.failureCount++;
                  if (this.failureCount >= this.failureThreshold) {
                    this.state = 'OPEN';
                    this.nextAttempt = Date.now() + this.resetTimeout;
                  }
                }
              }
              

Database Scaling

Sharding Strategy


                  // sharding-strategy.js
              const getShardKey = (userId) => {
                // Consistent hashing para distribuição uniforme
                const hash = require('crypto').createHash('md5').update(userId.toString()).digest('hex');
                return parseInt(hash.substring(0, 8), 16) % SHARD_COUNT;
              };
              
              const shardConfig = {
                0: { host: 'db-shard-0.cluster.local', port: 5432 },
                1: { host: 'db-shard-1.cluster.local', port: 5432 },
                2: { host: 'db-shard-2.cluster.local', port: 5432 },
                3: { host: 'db-shard-3.cluster.local', port: 5432 }
              };
              
              const getConnection = (userId) => {
                const shardId = getShardKey(userId);
                return connectionPool[shardId];
              };
              
              // Query cross-shard para agregações
              const aggregateAcrossShards = async (query) => {
                const promises = Object.keys(shardConfig).map(shardId => {
                  const conn = connectionPool[shardId];
                  return conn.query(query);
                });
                
                const results = await Promise.all(promises);
                return results.reduce((acc, result) => acc.concat(result.rows), []);
              };
              

Read Replicas com Failover


              const dbConfig = {
                master: { host: 'db-master.cluster.local', port: 5432 },
                replicas: [
                  { host: 'db-replica-1.cluster.local', port: 5432 },
                  { host: 'db-replica-2.cluster.local', port: 5432 },
                  { host: 'db-replica-3.cluster.local', port: 5432 }
                ]
              };
              
              class DatabaseRouter {
                constructor() {
                  this.replicaIndex = 0;
                  this.healthCheck();
                }
              
                async write(query, params) {
                  return await this.masterConnection.query(query, params);
                }
              
                async read(query, params) {
                  const replica = this.getHealthyReplica();
                  try {
                    return await replica.query(query, params);
                  } catch (error) {
                    console.warn('Replica failed, falling back to master');
                    return await this.masterConnection.query(query, params);
                  }
                }
              
                getHealthyReplica() {
                  // Round-robin entre réplicas saudáveis
                  const healthy = this.replicas.filter(r => r.healthy);
                  if (healthy.length === 0) return this.masterConnection;
                  
                  const replica = healthy[this.replicaIndex % healthy.length];
                  this.replicaIndex++;
                  return replica;
                }
              
                async healthCheck() {
                  setInterval(async () => {
                    for (const replica of this.replicas) {
                      try {
                        await replica.query('SELECT 1');
                        replica.healthy = true;
                      } catch (error) {
                        replica.healthy = false;
                      }
                    }
                  }, 5000);
                }
                

Links Referência

System Design Resources

Ferramentas e Tecnologias

Quer dominar System Design?

Construa aplicações robustas, escaláveis e prontas para o mundo real