Como a Cloudflare construiu o Town Lake, sua plataforma de dados, e o agente de IA Skipper
A Cloudflare processa mais de um bilhão de eventos por segundo em uma rede que já passa de 330 cidades em mais de 120 países. Por trás de cada requisição HTTP, de cada invocação de Worker e de cada leitura no R2, existe uma quantidade absurda de dados sendo gerados o tempo todo. Só que, por muitos anos, esse mar de informação era difícil de acessar de forma simples e confiável.
Os dados ficavam espalhados em dezenas de bancos de produção, clusters de ClickHouse, streams em Kafka, buckets em nuvens externas, conjuntos no BigQuery e uma fila interminável de pipelines específicos. Coisas aparentemente simples, como responder quantos domínios que se cadastraram hoje já estão no Top 100 por tráfego, exigiam saber exatamente:
- em qual sistema consultar,
- quais credenciais usar,
- que linguagem de query escrever,
- e se o dado estava completo, amostrado ou com atraso de vários dias.
Na prática, isso tornava muito mais difícil extrair insights de qualidade.
Para atacar esse problema de frente, a Cloudflare criou duas ferramentas internas que hoje formam a espinha dorsal da estratégia de dados da empresa:
- Town Lake, a plataforma unificada de análise de dados;
- Skipper, um agente de inteligência artificial que roda em cima dela.
O Town Lake oferece uma interface única em SQL para praticamente tudo o que a Cloudflare sabe sobre seu tráfego e seus produtos. Já o Skipper permite que qualquer pessoa, com as permissões corretas, faça perguntas em linguagem natural e receba respostas auditáveis em segundos.
Do caos de dados à visão unificada
Quem já trabalhou em empresa em ritmo de hyper-growth sabe bem como é o cenário de data sprawl. No caso da Cloudflare, alguns sintomas eram claros:
- Sistemas demais, desconectados entre si. Um engenheiro de produto que quisesse investigar o problema de um cliente precisava acessar Postgres para metadados de conta, ClickHouse para eventos analíticos, BigQuery para agregações de uso, R2 para logs brutos e tópicos em Kafka para sinais em tempo real. Cada sistema com seu login, sua sintaxe e sua política de retenção.
- Dados amostrados em cenários em que isso não pode acontecer. Para dashboards, amostrar tráfego faz sentido. Mas para cobrança, segurança ou investigações sensíveis, não dá. O pipeline analítico da Cloudflare precisa lidar com centenas de milhões de eventos por segundo, mas faturamento exige contagem precisa, não uma estimativa.
- Dependência de fornecedores externos para dados internos críticos. Parte da camada de relatórios vinha de serviços rodando em outras nuvens, o que significava custo financeiro e também uma dependência forte de infraestrutura de terceiros para operar dados estratégicos.
- Dificuldade em encontrar a fonte de verdade. Mesmo com credenciais corretas, era preciso saber exatamente que tabela consultar, em qual cluster, com qual join, usando qual identificador interno. Muita coisa morava em conhecimento tribal, concentrado em poucas pessoas.
Além disso, a cultura interna tratava infraestrutura de dados como algo de bastidor, em vez de encarar isso como parte crítica da própria plataforma da Cloudflare.
O objetivo passou a ser bem direto: criar um lugar único onde qualquer pessoa com o perfil de acesso adequado pudesse responder perguntas como:
- Mostre os 100 maiores clientes por receita no último trimestre.
- Liste todos os eventos de pontuação de Bot Management com score maior que 0,9 nas últimas 48 horas vindo de um ASN específico.
- Encontre os 100 principais tickets de suporte de cobrança de clientes que já gastaram mais de 100 dólares.
Esse lugar precisava entregar dados frescos, precisos e não amostrados quando o assunto fosse sensível (como billing ou segurança) e, ao mesmo tempo, dados rápidos e possivelmente amostrados quando a necessidade fosse explorar ou montar dashboards.
Outro requisito básico: segurança e governança incluídas desde o primeiro dia. Isso significa:
- detecção automática de PII,
- tabelas sensíveis fechadas por padrão,
- acesso auditável,
- permissões com validade limitada no tempo.
E tudo isso deveria ser construído com base na própria plataforma da Cloudflare: R2 para armazenamento, Workers para computação, Cloudflare Access para autenticação, Workflows para orquestração. Se era para investir pesado em dados, faria sentido construir usando exatamente os produtos que a empresa oferece aos clientes.
Por fim, havia um objetivo mais ambicioso: uma interface que não exigisse conhecimento em SQL. A ideia era que qualquer pessoa autorizada conseguisse enxergar o fluxo de dados que passa pela rede da Cloudflare, não só analistas e engenheiros de dados.
Esse último desejo materializou o Skipper.
Town Lake: o lakehouse da Cloudflare
No núcleo da arquitetura de dados, a Cloudflare adotou o padrão de data lakehouse: um motor de consulta que lê de armazenamento de objetos, com uma camada de metadados que faz essa estrutura se comportar como um banco de dados. Essa plataforma ganhou o nome de Town Lake, inspirado em um lago urbano de Austin, no Texas.
Os componentes principais são:
Motor de consulta com Apache Trino
O Trino é o cérebro de execução. Com ele, uma única query SQL consegue unir, em tempo de execução, tabelas de Postgres, ClickHouse e dados armazenados em formato Iceberg no R2, sem precisar copiar ou materializar tudo em um sistema intermediário.
Exemplo: uma pergunta do tipo quem são os 100 maiores clientes pagantes por requisições de Workers nesta semana vira um plano de execução que:
- aplica filtros e agregações em ClickHouse,
- faz join com dimensões de contas em Postgres,
- combina tudo com rollups de faturamento em tabelas Iceberg no R2,
- e devolve o ranking em uma única passada.
Catálogo R2 Data Catalog com Apache Iceberg
O R2 Data Catalog é o serviço gerenciado que abriga os dados frios e mornos usando Apache Iceberg. O Iceberg traz recursos fundamentais:
- evolução de esquema sem quebrar quem consome,
- time travel, para consultar o estado de uma tabela em um momento passado,
- evolução de partição,
- compactação de dados conforme envelhecem.
Isso permite uma estratégia em que:
- uso por minuto da última semana é guardado em alta resolução,
- depois vira agregação horária,
- e, com o tempo, é consolidado em diários.
O custo de armazenamento acompanha a queda de recência, mas os dados continuam totalmente consultáveis. Arquivos Parquet no R2 são bem mais econômicos do que manter tudo isso em um banco OLAP quente.
DataHub como catálogo de metadados
O DataHub é o catálogo central. Ali vivem informações sobre:
- todas as tabelas e colunas,
- tipos de dados,
- donos e responsáveis,
- linhagem entre fontes e derivados,
- glossário e anotações humanas.
Quando alguém quer saber o que existe em uma tabela como townlake.dim.accounts, o DataHub responde com descrição, documentação de colunas, time responsável e até quais tabelas alimentam essa dimensão e quais dependem dela.
Lifeguard: controle de acesso e políticas
Lifeguard é o serviço de controle de acesso. Ele:
- guarda regras em D1,
- puxa, em tempo real, informações de usuários e grupos do sistema interno de identidade,
- gera uma política combinada em JSON que o Trino lê via HTTP.
O mesmo Lifeguard alimenta o Skipper e o gateway de acesso, garantindo que o bloqueio aconteça o mais cedo possível, antes mesmo de a query rodar.
Skimmer: detecção contínua de PII
O Skimmer atua como scanner constante para encontrar PII. Ele roda de forma contínua, amostra linhas de todas as colunas em todas as tabelas e usa Workers AI para classificar se cada coluna contém informação pessoal ou sensível.
O processo é em duas etapas:
- Um classificador rápido por coluna faz a triagem inicial.
- Se algo suspeito aparece, um segundo passo, mais agente e contextual, olha a tabela toda e pode até rodar queries via Trino para validar.
Os achados vão para o DataHub e também alimentam o allowlist do Lifeguard, permitindo que revisores humanos façam a aprovação fina.
Transformer: ELT em cima de Workflows
O Transformer é o motor de ELT construído sobre Cloudflare Workflows. Os usuários definem um DAG de transformações SQL usando YAML com:
- tabela alvo,
- modo de materialização,
- dependências,
- agendamento.
O Transformer compila esse grafo e executa tudo via Trino. O estado é gerenciado com Durable Objects, as definições vivem em R2 e o histórico de execuções é guardado em D1.
Ingestion: ponte entre sistemas operacionais e o lago
A camada de ingestão conecta bancos de operação ao Town Lake. Um orquestrador roda em Kubernetes, lê configurações de pipeline e dispara jobs curtos que:
- extraem dados de Postgres ou ClickHouse,
- transformam para Parquet,
- e carregam em tabelas Iceberg no R2.
Cada pipeline pode operar em modo full-replace ou incremental-append, dependendo da natureza da fonte.
Governança: fechado por padrão, com automação e revisão leve
Um risco óbvio de centralizar dados é criar uma superfície gigante de exposição. A abordagem tradicional costuma ser abrir tudo e restringir por exceção. A Cloudflare fez o oposto com o Town Lake: tudo nasce fechado.
Na prática funciona assim:
- quando um novo banco é conectado ao Trino ou uma nova tabela é criada,
- o Skimmer escaneia e classifica as colunas,
- registra o objeto em um allowlist central como pendente,
- ninguém acessa até um revisor aprovar a tabela e as colunas específicas.
Esse fluxo seria bem doloroso se fosse manual. Mas dois fatores tornam isso viável:
- Automação forte. O classificador de PII é bom em pegar tanto PII óbvia (e-mail, IP, nome, telefone) quanto dados sensíveis menos óbvios (tokens com certos prefixos, IDs opacos que permitem rastrear usuários). O revisor vê o que foi detectado e aprova, ajusta ou nega. Em geral, a revisão leva poucos segundos.
- Fluxo autoatendido. Se alguém tenta consultar uma tabela sem acesso, a mensagem não é apenas um seco permissão negada. A resposta indica que aquela tabela precisa de revisão e oferece o caminho para solicitar isso. O próprio Skipper ainda sugere qual grupo de RBAC faz sentido pedir acesso.
Outro detalhe importante: a descoberta de esquema é separada do acesso aos dados. As pessoas conseguem ver que uma tabela existe, mas colunas não revisadas ficam ocultas em comandos como DESCRIBE, SHOW COLUMNS e até em SELECT *. Isso evita quebrar dashboards antigos quando novas colunas ainda não foram revisadas.
Além disso, o acesso a PII é opt-in por sessão. Por padrão, o Trino mascara colunas sensíveis antes de qualquer resultado aparecer na tela. Se alguém precisa ver dados crus, por exemplo em uma investigação de fraude, ativa um flag na sessão, passa por checagem de permissão e cada query é registrada com detalhe.
Skipper: o agente de IA para conversar com os dados
Só ter o motor de queries não resolve tudo. SQL ainda é uma barreira para muita gente, e saber qual tabela usar em um mar com dezenas de milhares de opções não é trivial. A resposta para isso foi o Skipper, um agente conversacional de inteligência artificial desenhado para caminhar da pergunta em linguagem natural até a resposta validada, usando os dados reais, o código e o conhecimento institucional da Cloudflare.
O Skipper roda em cima do Town Lake e também em cima da plataforma de desenvolvedores da Cloudflare: Workers, Workers AI, Durable Objects, D1, R2, Workflows e KV.
Na interface, é um chat. Um exemplo clássico de pergunta:
Mostre os 10 clientes com maior custo de armazenamento R2 nos últimos 30 dias e a variação em relação aos 30 dias anteriores.
O Skipper então:
- busca as tabelas corretas usando o DataHub,
- puxa esquema e linhagem associada,
- escreve a query SQL mais adequada,
- submete essa query ao Trino,
- espera o resultado e gera uma tabela ou gráfico.
Se o usuário emenda com um:
Agora quebra por região e ignora contas internas da Cloudflare.
O Skipper mantém o contexto, ajusta a query, refaz a execução e devolve a nova visão. Se notar problemas óbvios, como um join que resultou em zero linhas ou um filtro que eliminou mais coisa do que deveria, ele próprio investiga, corrige e tenta novamente em um ciclo fechado de raciocínio.
Além da exploração ad hoc, o Skipper consegue empacotar visualizações em dashboards compartilháveis que podem ser incorporados em outras ferramentas internas. Também oferece recursos para construir grafos de transformação via Transformer e checar permissões via Lifeguard.
Como o Skipper evita alucinações com camadas de contexto
Um modelo de linguagem, se você só passa um prompt SQL e uma lista de nomes de tabela, é capaz de:
- inventar joins que não existem,
- usar colunas erradas,
- e retornar números muito confiantes – e completamente errados.
Nos primeiros testes internos, a Cloudflare viu isso de perto. A solução veio de uma arquitetura de contexto em múltiplas camadas que o agente acessa durante a geração de respostas.
Camada 1: metadados de esquema e uso
O DataHub sabe:
- todas as colunas e seus tipos,
- chaves primárias e estrangeiras,
- e quais tabelas costumam ser unidas com quais, com base em queries históricas.
Ferramentas como search_datasets e get_entity_details expõem isso ao Skipper.
Camada 2: anotações humanas
Equipes documentam as tabelas que mantêm. Quando o time responsável por dim.accounts anota que ali existe uma linha por conta e que cada conta pertence a um único cliente via customer_id, essa descrição vai para o DataHub e chega ao contexto do agente. Tags como curated indicam tabelas validadas que o Skipper deve priorizar, evitando espaços de scratch.
Camada 3: conhecimento derivado de código
Muito do significado real não mora no catálogo, mas no SQL que gera cada tabela. O pipeline Transformer publica um arquivo .meta.json para cada nó a cada execução bem-sucedida, alimentando o DataHub.
Assim, quando o Skipper olha para uma tabela como fct.billings_allocated, ele não vê só o esquema, mas também que:
- é uma tabela de fatos pré-juntada,
- montada a partir de
dim.accounts,dim.customerseseed.product_classification, - e que a coluna
alloc_amounté calculada comobilled_amount / 12para anuais ebilled_amountpara planos mensais.
Esse nível de nuance diferencia uma resposta correta de um chute bem formatado.
Camada 4: modelos de dados curados
A Cloudflare mantém um conjunto enxuto de páginas de modelo de dados, documentos curtos que explicam como pensar sobre faturamento, clientes, contas e zonas. Neles entram orientações como:
- preferir tabelas com tag curated,
- evitar tabelas de scratch ou marcadas como internal,
- buscar usando termos de modelo (como billing product revenue) em vez de linguagem solta.
O Skipper acessa esses documentos como recursos adicionais quando o tema da pergunta bate com um desses domínios.
Camada 5: introspecção em tempo real
Quando o resto não basta, o Skipper pode fazer inspeções ao vivo no Trino:
DESCRIBE tabela,SELECT DISTINCT coluna LIMIT 20,SELECT COUNT(*).
Isso é usado com cuidado, porque tem custo, mas serve como rede de segurança que evita muitos erros silenciosos.
Execução como código: menos chat, mais fluxo
Na maioria dos agentes com ferramentas, o padrão é definir dezenas de ferramentas no prompt, deixar o modelo chamá-las uma a uma e repetir contexto a cada rodada. Isso é verboso e sai caro. Para o servidor MCP do Skipper, a Cloudflare adotou o Code Mode.
Em vez de expor 30 ferramentas, a API expõe basicamente duas: search e execute. O modelo escreve um trecho de JavaScript que chama programaticamente toda a suíte de ferramentas do Skipper:
const datasets = await skipper.search_datasets({ query: "billing product revenue" })
const queryId = await skipper.start_query({ sql: "SELECT ..." })
const results = await skipper.fetch_results({ queryId, mode: "inject" })
return skipper.create_chart({ chartType: "bar", data: results.rows })
Esse código roda em um Worker dinâmico isolado. Com isso, o modelo descreve fluxos multi-etapa em uma única rodada, em uma linguagem em que ele já é bom. Fica mais rápido, mais barato e ainda deixa o fluxo audível como código.
Outro ponto central: tudo o que o Skipper faz roda como o usuário chamador. Se a pessoa não tem acesso a uma tabela, o agente também não tem. Se a query salva é compartilhada, a checagem de permissão acontece na hora da visualização, não na hora do salvamento.
Casos de uso reais dentro da Cloudflare
Depois de consolidado, o Town Lake e o Skipper passaram a ser usados em vários domínios internos.
Billing e uso faturável
Esse foi o caso de uso que puxou o projeto. O Billable Usage Dashboard, o painel que mostra para clientes pay as you go quanto eles devem pagar, é alimentado por um pipeline de medição cujo source of truth são tabelas Iceberg no R2 consultadas via Trino. A API do dashboard lê as mesmas linhas compactas de (date, account_id, metric_name, usage) que o sistema de faturamento usa, garantindo que o número visto pelo cliente bate com o número na fatura.
Consultas ligadas a billing representam mais da metade de todas as queries servidas pelo Town Lake. Aqueles blocos antigos de 200 ou 300 linhas de SQL usados para fazer rollups de receita por cliente hoje foram condensados em consultas muito menores, bem mais legíveis.
Business intelligence
Perguntas como top 100 clientes por receita ou quantos domínios que se cadastraram hoje já estão no top 100 passaram a levar cerca de três segundos no Skipper. O mesmo vale para uma série de dúvidas de negócio que antes viravam ticket de Jira e esperavam dias até alguém com tempo livre montar a query correta.
Segurança e análise de ameaças
O time de Bot Management usa o Town Lake para consultar eventos de pontuação de modelos de machine learning com score maior que 0,9 nas últimas 48 horas, com filtros por ASN e geografia. Pesquisadores de ameaças construíram seus próprios kits de consulta em cima da plataforma, e áreas de Trust & Safety aproveitam os sinais para apoiar o combate a abuso e comportamento malicioso.
Suporte ao cliente
Coisas que antes eram projetos de vários dias, como encontrar os 100 principais tickets de cobrança de clientes que já gastaram mais de 100 dólares, passaram a ser consultas rápidas no Skipper, liberando o time para focar na análise em vez de montar pipeline ad hoc.
Algumas lições aprendidas
Alguns aprendizados chamaram atenção ao longo do caminho:
- Menos instrução detalhada, melhor resultado. Prompts muito prescritivos, dizendo passo a passo que ferramenta usar, derrubaram a qualidade das respostas. O modelo se saiu melhor com orientações de alto nível, escolhendo o fluxo sozinho.
- Ferramentas sobrepostas confundem o modelo. Ter versões demais de ferramentas parecidas fez o Skipper chamar a opção errada com frequência. Simplificar e dar um motivo único para cada ferramenta ajudou bastante.
- Código carrega o significado. Os maiores ganhos de precisão vieram quando a equipe começou a ingerir o SQL que produz as tabelas, não só o esquema em si. Pequenos detalhes de regra de negócio aparecem ali, não nas descrições de coluna.
- Memória faz diferença. Existe uma cauda longa de correções do tipo tem que filtrar assim ou ignore sempre essas tabelas. Sem camada de memória, o agente precisa reaprender isso conversa após conversa.
- A parte entediante é a que mais dói. Trino e Iceberg não são exatamente novidades. O difícil, e que consome mais energia, são as coisas consideradas chatas: controle de acesso linha a linha, allowlist fechado por padrão, auditoria de query, credenciais com tempo de vida, pipelines idempotentes, evolução de esquema controlada. É isso que faz a plataforma ser segura de verdade.
Próximos passos para a plataforma de dados e o Skipper
A Cloudflare segue ampliando a superfície do agente. O Skipper já funciona como servidor MCP integrado a IDEs compatíveis e o próximo passo é aprofundar a presença em chats internos e sistemas de tickets. A ideia é que perguntar para os dados se torne o primeiro reflexo de quem está:
- investigando um incidente,
- desenhando um novo projeto,
- ou só validando uma hipótese rápida.
Em paralelo, a empresa está investindo pesado no pipeline Transformer. A visão é que qualquer time consiga construir um conjunto de dados curado com alguns arquivos SQL e um .meta.json, implantar isso como um Workflow, ter agendamento e monitoramento automáticos e ver tudo aparecer, já integrado, no DataHub e no Skipper.
Do lado do motor de análise, o R2 SQL, engine serverless e distribuída da própria Cloudflare, vem ganhando recursos rapidamente. À medida que ele amadurece, várias partes do fluxo do Town Lake devem migrar para esse novo componente, mantendo o mesmo conceito de lakehouse, mas em uma base ainda mais integrada com o restante da plataforma.
No fim das contas, a aposta é simples: o próximo grande produto provavelmente vai nascer de alguém olhando para os dados e enxergando algo que ninguém tinha percebido ainda. O Town Lake, a plataforma de dados que o sustenta e o agente de inteligência artificial Skipper existem justamente para garantir que essa pessoa consiga chegar lá.
