Resumo da minha leitura do capítulo que monta o vocabulário do livro, e um paralelo com um sistema em que trabalhei.
Este texto é o resumo da minha leitura do capítulo 1 de Designing Data-Intensive Applications, segunda edição, de Martin Kleppmann e Chris Riccomini (O’Reilly, 2025). As ideias são dos autores. A seleção, a ordem, as opiniões e o paralelo do final são meus.
O capítulo abre com uma frase de Thomas Sowell: “não existem soluções, só trade-offs”. Não ensina algoritmo, estrutura de dados nem protocolo. Ele monta a postura mental que os autores cobram do leitor: diante de uma decisão de arquitetura de dados, a pergunta certa não é “qual é a melhor tecnologia”, e sim “o que eu ganho e o que eu pago com cada opção, no meu contexto”. O capítulo organiza isso em quatro tensões: operacional contra analítico, nuvem contra self-hosting, distribuído contra um nó só, e negócio contra direitos das pessoas.
O que é uma aplicação data-intensive
Uma aplicação é data-intensive quando gerenciar dados é um dos principais desafios do seu desenvolvimento. O contraste é com aplicações compute-intensive, em que a dificuldade está em paralelizar um cálculo enorme. Nas data-intensive as dores são outras: volume, mudança dos dados ao longo do tempo, consistência sob falha e concorrência, alta disponibilidade.
Quase ninguém constrói isso do zero. A aplicação é montada com blocos padronizados: banco de dados para guardar e reencontrar, cache para lembrar o resultado de uma operação cara, índice de busca para filtrar por palavra, processamento de stream para reagir a eventos, processamento em lote para triturar volumes acumulados. O trabalho de quem projeta é escolher esses blocos e colá-los com código. Fica difícil quando nenhuma ferramenta resolve sozinha e é preciso combinar várias mantendo tudo coerente.
Os autores marcam logo no início: muita confusão em projeto de dados vem de pessoas diferentes quererem coisas diferentes dos mesmos dados, sem que isso esteja escrito em lugar nenhum.
O livro trata de backend, e lembra que o código da aplicação costuma ser stateless: o que precisa sobreviver entre requisições vai para o cliente ou para a infraestrutura de dados.
Operacional contra analítico
O capítulo começa pelas pessoas. Engenheiros de backend constroem serviços que leem e alteram dados. Analistas geram relatórios para a gestão decidir. Cientistas de dados procuram padrões e constroem funcionalidades sobre eles. Os dois últimos fazem analytics: olham dados gerados por outros e, em geral, não os modificam. Daí a divisão que organiza o capítulo.
Sistemas operacionais são onde os dados nascem; o código lê e modifica conforme a ação do usuário. Sistemas analíticos guardam uma cópia somente leitura desses dados, otimizada para o processamento que análise exige.
O padrão de acesso operacional é o OLTP: busca poucos registros por chave, grava a partir da ação de alguém que está esperando a resposta. O analítico é o OLAP: varre um número enorme de registros e devolve agregados.
| Propriedade | Operacional (OLTP) | Analítico (OLAP) |
|---|---|---|
| Leitura | poucos registros por chave | agregação sobre muitos registros |
| Escrita | cria, atualiza e apaga registros individuais | carga em massa ou stream de eventos |
| Consulta | fixa, embutida no código | arbitrária, exploração ad hoc |
| O que o dado representa | o estado atual | o histórico de eventos |
| Tamanho típico | gigabytes a terabytes | terabytes a petabytes |
Adaptada da Tabela 1-1 do livro.
Usuário de OLTP não escreve SQL livre, por segurança e desempenho; no analítico, SQL livre é a regra. Existe ainda uma terceira categoria, real-time analytics: agregações embutidas no produto, com ingestão em tempo real e resposta de baixa latência.
Data warehouse, data lake e o que veio depois
A separação física nasceu no fim dos anos 1980. Uma empresa grande tem dezenas ou centenas de sistemas OLTP, cada um com seu time. Consultá-los diretamente para análise sofre de quatro problemas: silos, esquema errado para o trabalho, impacto em produção e segurança. O data warehouse é a cópia somente leitura de todos eles, alimentada por ETL: extrair, transformar, carregar.
Cientistas de dados pedem o que SQL atende mal: feature engineering para modelos e dados não estruturados como texto e imagem. A resposta foi o data lake, um repositório que guarda cópia de qualquer dado útil sem impor formato, modelo ou esquema, sobre armazenamento barato de objetos. O lake virou parada intermediária entre a operação e o warehouse, guardando o dado bruto para cada consumidor transformar como precisa. Os autores chamam isso de princípio do sushi: dado cru é melhor.
Três movimentos fecham o quadro: governança pesa tanto quanto a análise; dados chegam como eventos e o stream responde em segundos; e existe o caminho de volta, o reverse ETL, com o modelo treinado no lake indo para produção.
Sobre HTAP, sistemas que prometem OLTP e análise na mesma caixa: muitos são, por dentro, um OLTP acoplado a um analítico separado, e não substituem o warehouse, porque cada serviço tem seu banco e a empresa tem um warehouse só para cruzar todos. Quanto maior a escala, mais especializados ficam os sistemas.
Sistema de registro e dado derivado
É a distinção mais útil do capítulo, na minha leitura.
O sistema de registro guarda a versão autoritativa. Todo dado novo é escrito primeiro ali; cada fato aparece uma vez. Se outro sistema discordar dele, quem está certo é o sistema de registro. Um sistema de dados derivados contém o que se obtém transformando dados de outro lugar: cache, índice, view materializada, dado desnormalizado, até um modelo de ML treinado. Se perder dado derivado, você recria a partir da fonte.
flowchart LR
IN([entrada]) -->|grava primeiro| SOR[(sistema de registro)]
SOR -->|deriva| CACHE[(cache)]
SOR -->|deriva| IDX[(índice)]
SOR -->|deriva| DW[(warehouse)]
DW -->|treina| ML[modelo]
CACHE -. perdeu? recria .-> SOR
Dado derivado é redundante, e é ele que dá desempenho às leituras. Duas observações finas: sistemas analíticos são quase sempre derivados, enquanto um serviço operacional mistura os dois; e nenhum banco é por natureza registro ou derivado, o papel depende do uso. Ser explícito sobre o que deriva de quê desfaz emaranhados. E quando um dado deriva de outro, é preciso um processo para propagar mudanças. Muitos bancos foram desenhados como se fossem o único sistema da aplicação e não ajudam nisso.
Nuvem contra self-hosting
A regra prática para build ou buy: o que é competência central fica em casa; o rotineiro vai para fornecedor. Com software há duas decisões separadas, quem constrói e quem opera, e elas formam um espectro: sob medida e operado por você; de prateleira no seu hardware ou numa VM; serviço gerenciado; SaaS acessado só por API.
Usar um serviço de nuvem é terceirizar a operação. Os provedores dizem que isso economiza; os autores respondem com “depende”. Self-hosting tende a ser mais barato quando você já sabe operar o sistema e a carga é previsível. Nuvem tende a ganhar quando você precisa de algo que não sabe operar, quando a carga varia muito e, em especial, para análise de dados grandes, que pede muito processamento por poucos segundos. O maior problema da nuvem é a falta de controle: funcionalidade que falta, serviço que cai, bug que você não consegue diagnosticar sem acesso aos logs do servidor, serviço descontinuado ou encarecido, lock-in, risco geopolítico, compliance.
Cloud native e a separação entre storage e compute
Além do modelo econômico, a nuvem mudou como sistemas de dados são construídos. A ideia central do cloud native é construir serviços de alto nível sobre serviços de nuvem de nível mais baixo. O exemplo principal é o object storage: API mais limitada que um sistema de arquivos, mas que esconde as máquinas, distribui os dados e não perde nada quando um disco falha.
O conceito técnico mais importante da seção, para mim, é este. No modelo tradicional, disco é durável e a mesma máquina armazena e processa. Na nuvem, o disco local de uma VM é cache efêmero. A alternativa, o disco virtual destacável, não é um disco: é um serviço em outras máquinas emulando um dispositivo de blocos, e cada I/O vira uma chamada de rede. Por isso sistemas cloud native evitam discos virtuais e gerenciam valores pequenos num serviço separado, guardando blocos grandes no object storage. O resultado é a desagregação: storage e compute viram responsabilidades distintas, e analisar implica transferir dados pela rede.
flowchart LR
subgraph T[tradicional]
N1[servidor] --- D1[(disco local)]
end
subgraph C[cloud native]
C1[compute 1] <-->|rede| OS[(object storage)]
C2[compute N] <-->|rede| OS
C1 <--> META[(valores pequenos)]
end
Sobre operação: DevOps e SRE não mudaram o objetivo, mudaram processo e ferramenta. Na nuvem, planejamento de capacidade vira planejamento financeiro e otimização de desempenho vira otimização de custo. O cliente continua precisando de operação, só que para escolher, integrar e migrar serviços; segurança da aplicação e investigação de degradação não se terceirizam. Nas palavras dos autores, a necessidade de operação é tão grande quanto sempre foi.
Distribuído contra um nó só
O livro lista nove motivos para distribuir: distribuição inerente, chamadas entre serviços de nuvem, tolerância a falhas, escalabilidade, latência, elasticidade, hardware especializado, conformidade legal e sustentabilidade. E lista o preço.
Toda chamada de rede pode falhar, e o pior caso é o timeout sem resposta: você não sabe se o outro lado recebeu, então tentar de novo pode não ser seguro. Rede é lenta comparada a memória; com muito dado, costuma ser mais rápido levar a computação até o dado. Mais nós nem sempre é mais rápido, e o capítulo cita um programa single-threaded numa máquina só que superou um cluster de mais de cem núcleos. Troubleshooting fica difícil. E consistência entre serviços vira problema da aplicação, porque transação distribuída é rara em microsserviços.
flowchart TD
Q1{usuários em dispositivos diferentes<br/>ou dado em outro serviço?} -->|sim| D1[já é distribuído: trate rede, timeout, retry]
Q1 -->|não| Q2{precisa sobreviver à queda<br/>de uma máquina?}
Q2 -->|sim| D2[distribua por tolerância a falhas]
Q2 -->|não| Q3{dado ou carga excede<br/>uma máquina grande?}
Q3 -->|sim| D3[distribua por escala]
Q3 -->|não| S[fique num nó só]
Roteiro meu, derivado dos motivos do capítulo: distribua por um motivo concreto, não por padrão.
A conclusão dos autores é direta: fazer numa máquina só costuma ser muito mais simples e barato, e bancos como DuckDB e SQLite aguentam muita carga num nó.
Sobre microsserviços, a frase que mais vale guardar: são principalmente uma solução técnica para um problema de pessoas. Permitem que times avancem sem coordenar entre si, o que vale muito numa empresa grande e é overhead numa pequena. A regra de dados é clara: cada serviço com seu banco. Banco compartilhado transforma o esquema inteiro em parte da API e deixa a consulta de um serviço derrubar o desempenho dos outros. O custo: testar exige subir dependências, cada serviço pede infraestrutura própria, e evoluir API quebra cliente.
Serverless leva a cobrança por uso para a execução do código, ao custo de limite de tempo, runtime restrito e cold start.
Lei e sociedade
A última seção lembra que arquitetura de dados não é decidida só por requisito técnico. Desde 2018 o GDPR dá às pessoas controle sobre seus dados; a LGPD faz o mesmo aqui. E sistemas automatizados decidem quem recebe crédito, quem é chamado para entrevista, quem é suspeito.
O exemplo concreto é o direito ao esquecimento. Muitos sistemas de dados são construídos sobre estruturas imutáveis, como logs append-only. Como apagar um dado no meio de um arquivo que não deveria mudar? Como apagar o que já entrou num dado derivado, como o conjunto de treino de um modelo? A lei, de propósito, não prescreve tecnologia; define princípios.
O custo de guardar dados não é só a fatura do storage: é vazamento, multa e risco para as próprias pessoas, quando o dado pode revelar comportamento criminalizado em algum lugar. Daí a minimização de dados, que vai na contramão do “guarde tudo” do big data: coletar para um propósito explícito, não reaproveitar para outro, não manter além do necessário.
O que eu levo do capítulo
- OLTP e OLAP diferem no padrão de acesso, no público e no que o dado representa. A separação é física por quatro motivos, e o lake virou a parada intermediária.
- Saber o que é sistema de registro e o que é derivado simplifica qualquer arquitetura. O papel depende do uso, não da ferramenta.
- Nuvem ou self-hosting depende da competência do time e da previsibilidade da carga. O que mudou de verdade foi a separação entre storage e compute.
- Distribuir é inevitável às vezes, mas não tenha pressa em distribuir o que cabe numa máquina. Microsserviços resolvem um problema de times e cobram em complexidade.
- Regulação de privacidade é requisito de arquitetura, não anexo jurídico.
Um paralelo da vida real
Trabalhei num sistema transacional de alto volume, dezenas de milhões de contas e milhões de lançamentos por dia. O banco primário era o sistema de registro. Em volta dele, tudo era derivado: um cache de saldos, uma réplica de leitura, os eventos publicados para outros serviços, a cópia que alimentava análise. Em teoria, tudo reconstruível a partir da fonte. Na prática, a pergunta “o que deriva de quê” foi a que mais resolveu discussão de arquitetura, porque dizia quem estava certo quando dois lugares discordavam.
A frase do capítulo que mais doeu foi a de que dado derivado exige um processo para propagar mudanças, e que os bancos não ajudam nisso. Esse processo, no meu caso, foi o padrão outbox: a linha de negócio e o evento gravados na mesma transação, um job drenando a tabela para o broker. Escrevi sobre a escolha em CDC ou outbox e sobre o rastro que ela deixa no APM em Trace distribuído através do outbox. Lendo o capítulo depois, entendi que eu estava resolvendo exatamente o problema que ele nomeia: manter dado derivado coerente com o sistema de registro sem transação distribuída.
A segunda lição que eu já tinha pago antes de ler foi a do disco virtual. Um lote anual sobre esse banco, gerenciado na nuvem, não bateu em CPU nem no plano de consulta. Bateu no teto de IOPS do disco. Cada leitura era uma chamada de rede, exatamente como o capítulo descreve, e o limite não aparecia em nenhuma métrica do banco, só na documentação do SKU. Se eu tivesse lido a seção sobre separação entre storage e compute antes, teria procurado esse teto no primeiro dia, não na primeira madrugada.
Referências
- Martin Kleppmann e Chris Riccomini. Designing Data-Intensive Applications, 2ª edição. O’Reilly, 2025. Capítulo 1, “Trade-Offs in Data Systems Architecture”.
- Jeff Dean, “Latency Numbers Every Programmer Should Know”, compilação de Peter Norvig e Jonas Bonér: https://gist.github.com/jboner/2841832
- Regulamento (UE) 2016/679 (GDPR), artigo 17, direito ao apagamento: https://eur-lex.europa.eu/eli/reg/2016/679/oj
- Lei nº 13.709/2018 (LGPD): https://www.planalto.gov.br/ccivil_03/_ato2015-2018/2018/lei/l13709.htm
- DataOps Manifesto: https://dataopsmanifesto.org/
Comentários
Os comentários ficam no GitHub Discussions; entre com sua conta do GitHub para participar.