Armazenamento de arquivos em nuvem: S3, uploads e CDN sem dor de cabeça
Guardar arquivos parece a parte fácil de um SaaS, até deixar de ser. O primeiro protótipo salva os uploads no disco do servidor, funciona, e ninguém pensa mais nisso. Aí o produto cresce: o servidor enche, um segundo servidor não enxerga os arquivos do primeiro, um upload grande derruba a memória da aplicação, a conta de banda dispara, e um usuário mal-intencionado envia um executável disfarçado de imagem. O que era trivial vira uma fonte constante de incidentes. Armazenar arquivos direito é uma disciplina de infraestrutura, e ela tem soluções bem estabelecidas.
Este guia cobre o armazenamento de arquivos em nuvem sem dor de cabeça: por que o object storage substitui o disco local, como receber uploads sem sobrecarregar a aplicação, como validar e organizar o que entra, e como servir e pagar por isso de forma eficiente. O foco é a infraestrutura de arquivos, um tema distinto do pipeline de otimização de imagens no front-end.
Por que não guardar no servidor
Salvar arquivos no disco da própria aplicação é o erro de origem. Ele falha por vários motivos ao mesmo tempo:
- Não escala horizontalmente. Com vários servidores, o arquivo salvo em um não existe nos outros. O usuário faz upload em um servidor e o download cai em outro, que não tem o arquivo.
- Some com o servidor. Se a instância é substituída (o que acontece o tempo todo na nuvem), os arquivos vão junto.
- Compete por recurso. Disco e I/O do servidor de aplicação são disputados com o trabalho que ele deveria fazer: atender requisições.
A solução é o object storage (armazenamento de objetos), do qual o Amazon S3 é o padrão de mercado, com equivalentes em toda nuvem. Em vez de arquivos em um disco, você guarda objetos em buckets, cada objeto endereçado por uma chave, acessível por HTTP, com durabilidade altíssima e escala praticamente ilimitada. O armazenamento deixa de ser problema do servidor de aplicação e vira um serviço dedicado.
Uploads sem passar pela aplicação: presigned URLs
O segundo erro clássico é fazer o arquivo passar pela aplicação no upload: o navegador envia para o seu servidor, que então repassa ao storage. Isso desperdiça banda e memória do servidor e trava com arquivos grandes.
A técnica correta é a presigned URL (URL pré-assinada). O fluxo:
- O navegador pede à sua aplicação permissão para enviar um arquivo.
- A aplicação gera uma URL temporária e assinada, que autoriza o upload direto para o bucket, por um curto período e com regras específicas.
- O navegador envia o arquivo direto ao storage, sem passar pelo seu servidor.
Assim, o arquivo nunca toca a sua aplicação: ela só emite a permissão. O upload não consome recursos do servidor, escala naturalmente e funciona bem mesmo com arquivos enormes. O mesmo padrão vale para download: uma presigned URL dá acesso temporário a um objeto privado, sem expor o bucket inteiro.
Arquivos grandes: multipart upload
Enviar um arquivo de vários gigabytes em uma única requisição é frágil: se a conexão cai aos 90%, tudo recomeça do zero. O multipart upload resolve isso quebrando o arquivo em partes enviadas separadamente, muitas vezes em paralelo, e recombinadas no storage ao final.
Os ganhos são diretos: se uma parte falha, só ela é reenviada, não o arquivo todo; as partes sobem em paralelo, acelerando o upload; e uploads muito grandes tornam-se viáveis e confiáveis. Para arquivos acima de alguns megabytes, o multipart é o caminho padrão.
Validar o que entra
Aceitar upload sem validação é abrir a porta para problemas de segurança e de custo. Um bucket que recebe qualquer coisa vira depósito de malware, de arquivos gigantes que estouram a conta, ou de conteúdo que não deveria estar ali. Cuidados essenciais:
- Valide o tipo de arquivo de verdade. Não confie na extensão nem no tipo declarado pelo cliente, que são facilmente forjados. Verifique o conteúdo real do arquivo.
- Limite o tamanho. Defina um teto, aplicado inclusive na própria presigned URL, para impedir uploads abusivos.
- Isole o que é público do que é privado. Documentos de um usuário jamais devem ficar acessíveis a outros. Use permissões e caminhos que reflitam a propriedade.
- Gere as chaves você mesmo. Não use o nome de arquivo do usuário como chave, para evitar colisões e injeções. Prefira identificadores gerados.
Classes de armazenamento e lifecycle
Nem todo arquivo tem o mesmo valor com o tempo. Uma foto de perfil é acessada toda hora; um log de auditoria de dois anos atrás, quase nunca. Object storage oferece classes de armazenamento com preços diferentes: as quentes, caras e de acesso instantâneo, para o que é usado com frequência; as frias e de arquivamento, muito mais baratas, para o que raramente se acessa.
As regras de lifecycle automatizam a economia. Você define políticas como "mover para a classe fria depois de 30 dias sem acesso" ou "apagar depois de um ano", e o storage executa sozinho. Sem lifecycle, o custo só cresce, porque tudo fica para sempre na classe mais cara. Com ele, os dados envelhecem para camadas mais baratas de forma automática.
Servir arquivos via CDN
Servir arquivos direto do bucket para o usuário final é lento e caro. Lento porque o bucket vive em uma região, longe de muitos usuários; caro porque a banda de saída do storage tem um preço. A solução é colocar uma CDN na frente do bucket.
A CDN cacheia os arquivos em nós de borda espalhados pelo mundo, então o usuário baixa do ponto mais próximo, com latência muito menor. E, como a maioria das requisições é atendida pelo cache da CDN, o bucket é acessado com muito menos frequência, o que reduz o custo de banda de origem. Para qualquer arquivo servido em volume (imagens, vídeos, downloads), a CDN na frente do storage é padrão, não luxo.
O custo dos arquivos
O armazenamento de arquivos tem três dimensões de custo que precisam ser entendidas para não gerar surpresa na fatura.
| Dimensão | O que é | Como controlar |
|---|---|---|
| Armazenamento | Quanto você guarda, por tempo | Lifecycle e classes frias |
| Requisições | Número de operações de leitura e escrita | Cache na CDN, menos idas ao bucket |
| Transferência (egress) | Banda de saída para fora da nuvem | CDN na frente, reduzindo egress da origem |
A transferência de saída costuma ser o custo mais subestimado e o que mais surpreende. Servir muito conteúdo direto do storage para a internet gera egress caro; a CDN na frente é a principal defesa, porque atende do cache e poupa a origem.
Arquivos são infraestrutura, não um detalhe
Lidar com arquivos em um SaaS parece simples e é traiçoeiro: o caminho fácil (salvar no servidor, subir pela aplicação, servir do bucket) falha em escala, em custo e em segurança. O caminho maduro usa object storage dedicado, uploads diretos por presigned URL, multipart para arquivos grandes, validação rigorosa do que entra, lifecycle para envelhecer dados e uma CDN para servir rápido e barato. Cada peça resolve um problema real que aparece quando o volume cresce. Tratar arquivos como a infraestrutura que eles são, desde cedo, é o que evita a longa fila de incidentes que surge quando eles são tratados como detalhe.
Seus uploads passam pela aplicação, incham o servidor ou geram contas de banda inesperadas? Na ConstructorTI, desenhamos a infraestrutura de arquivos do jeito certo, com object storage, presigned URLs, validação, lifecycle e entrega via CDN. Se lidar com arquivos virou fonte de incidentes ou de custo fora de controle, fale com a nossa engenharia e receba um diagnóstico da sua camada de armazenamento.