Entregar software rapidamente e, ao mesmo tempo, manter a confiabilidade é um desafio constante. À medida que a Databricks cresceu, também aumentou a complexidade de implementar alterações com segurança em centenas de serviços, várias clouds e milhares de cargas de trabalho de clientes. Os feature flags nos ajudam a gerenciar essa complexidade, separando a decisão de implantar o código da decisão de habilitá-lo. Essa separação permite que os engenheiros isolem falhas e mitiguem incidentes mais rapidamente, sem sacrificar a velocidade de entrega.
Um dos principais componentes da estratégia de estabilidade do Databricks é a nossa plataforma interna de feature flagging e experimentação, chamada "SAFE". Os engenheiros do Databricks usam o SAFE diariamente para lançar recursos, controlar o comportamento do serviço dinamicamente e medir a eficácia de seus recursos com experimentos A/B.
O SAFE foi iniciado com o objetivo "norte" de desacoplar totalmente os lançamentos de binários de serviço da ativação de recursos, permitindo que as equipes implementem recursos independentemente da implantação de seus binários. Isso permite muitos benefícios secundários, como a capacidade de disponibilizar um recurso de forma confiável e progressiva para grupos de usuários cada vez maiores, e mitigar rapidamente os incidentes causados por uma implementação.
Na escala da Databricks, atendendo a milhares de clientes corporativos em múltiplas clouds com uma superfície de produto em rápido crescimento, precisávamos de um sistema de sinalização de recurso que atendesse aos nossos requisitos exclusivos:
Após considerarmos cuidadosamente esses requisitos, finalmente optamos por construir um sistema de sinalização de recurso personalizado e interno. Precisávamos de uma solução que pudesse evoluir junto com nossa arquitetura e que fornecesse os controles de governança necessários para gerenciar flags com segurança em centenas de serviços e milhares de engenheiros. Alcançar nossas metas de escalabilidade e segurança com sucesso exigiu uma integração profunda com nosso modelo de dados de infraestrutura, frameworks de serviço e sistemas de CI.
No final de 2025, a SAFE tem aproximadamente 25 mil flags ativas, com 4 mil trocas de flags semanais. Em momentos de pico, a SAFE executa mais de 300 milhões de avaliações por segundo, tudo isso mantendo uma latência p95 de ~10μs para avaliações de flags.
Esta publicação explora como construímos o SAFE para atender a esses requisitos e os aprendizados que tivemos ao longo do caminho.
Para começar, vamos discutir uma jornada de usuário típica para uma flag SAFE. Em sua essência, um sinalizador de recurso é uma variável que pode ser acessada no fluxo de controle de um serviço, a qual pode assumir valores diferentes dependendo de condições controladas por uma configuração externa. Um caso de uso extremamente comum para sinalizadores de recurso é habilitar gradualmente um novo caminho de código de forma controlada, começando primeiro com uma pequena parte do tráfego e, gradualmente, habilitando-o em nível global.
Os usuários do SAFE primeiro começam definindo sua flag no código do serviço e a usam como um gate condicional para a lógica do novo recurso:
Em seguida, o usuário acessa a UI interna do SAFE, registra essa flag e seleciona um padrão para fazer o roll out dela. Este padrão define um plano de ramp up gradual que consiste em uma lista de estágios ordenados. O ramp up de cada estágio é feito lentamente por porcentagens. O usuário visualiza uma interface como esta após a criação da flag:
A partir daqui, o usuário pode liberar manualmente seu flag, uma fase de cada vez, ou programar para que as alterações de flag sejam criadas automaticamente. Internamente, a fonte da verdade para a configuração do flag é um arquivo jsonnet enviado para o monorepo do Databricks, que usa uma linguagem de domínio específico (DSL) leve para gerenciar a configuração do flag:
Quando os usuários alteram um flag na IU, o resultado dessa alteração é um Pull Request que precisa ser revisado por pelo menos mais um engenheiro. O SAFE também executa uma variedade de checagens pré-merge para proteger contra alterações inseguras ou não intencionais. Assim que a alteração for merge, o serviço do usuário aplicará a alteração e começará a emitir o novo valor dentro de 2 a 5 minutos após o merge do PR.
Além do caso de uso descrito acima para o lançamento de recursos, o SAFE também é usado para outros aspectos da configuração dinâmica de serviços, como: configurações dinâmicas de longa duração (por exemplo, tempos limite ou limites de taxa), controle de máquina de estado para migrações de infraestrutura ou para entregar pequenos blobs de configuração (por exemplo, políticas de registro direcionadas).

O SAFE fornece "SDKs" de cliente em várias linguagens com suporte interno, sendo o SDK do Scala o mais maduro e amplamente adotado. O SDK é essencialmente uma biblioteca de avaliação de critérios, combinada com um componente de carregamento de configuração. Para cada flag, há um conjunto de critérios que controlam qual valor o SDK deve retornar em Runtime. O SDK gerencia o carregamento do conjunto de configurações mais recente e precisa retornar rapidamente o resultado da avaliação desses critérios em Runtime.
Em pseudocódigo, os critérios internos se parecem com algo assim:
Os critérios podem ser modelados como algo semelhante a uma sequência de árvores de expressão Boolean. Cada expressão condicional precisa ser avaliada de forma eficiente para retornar um resultado rápido.
Para atender aos nossos requisitos de desempenho, o design do SDK do SAFE incorpora alguns princípios de arquitetura: (1) separação da entrega da configuração da avaliação e (2) separação das dimensões de avaliação estática e de Runtime.
Para atingir de forma confiável uma latência de avaliação inferior a um milissegundo em escala, o SAFE emprega a pré-avaliação de partes da árvore de expressão booleana que são estáticas. Quando um pacote de configuração do SAFE é entregue a um serviço, o SDK avalia imediatamente todas as dimensões estáticas em relação à representação na memória da configuração da flag. Isso produz uma árvore de configuração simplificada que contém apenas a lógica relevante para aquela instância de serviço específica.
Quando uma avaliação de flag é solicitada durante o processamento da solicitação, o SDK só precisa avaliar as dimensões de Runtimes restantes em relação a essa configuração pré-compilada. Isso reduz significativamente o custo computacional de cada avaliação. Como muitos flags usam apenas dimensões estáticas em suas árvores de expressão Boolean, muitos flags podem ser efetivamente pré-avaliados por completo.
Para entregar a configuração de forma confiável a todos os serviços da Databricks, o SAFE opera em conjunto com nossa plataforma interna de entrega de configuração dinâmica, a Zippy. Uma descrição detalhada da arquitetura Zippy fica para outra postagem, mas, em resumo, o Zippy usa uma arquitetura global/regional de várias camadas e armazenamento de blobs por nuvem para transportar blobs de configuração arbitrários de uma fonte central para (entre outras superfícies) todos os pods do Kubernetes em execução no Painel de Controle do Databricks.

O ciclo de vida de uma flag entregue é o seguinte:
De ponta a ponta, uma alteração de flag normalmente se propaga para todos os serviços dentro de 3 a 5 minutos após o merge de um PR.
Dentro do pipeline de entrega de flags, as configurações de flag assumem várias formas, sendo progressivamente traduzidas de configurações semânticas de alto nível e legíveis por humanos para versões compactas e legíveis por máquina, à medida que o flag se aproxima de ser avaliado.
Na interface voltada para o usuário, os flags são definidos usando Jsonnet com uma DSL personalizada para permitir configurações de flag arbitrariamente complicadas. Essa DSL tem recursos para casos de uso comuns, como configurar a liberação de um flag usando um padrão ou definir substituições específicas em fatias de tráfego.
Após o check-in, esta DSL é traduzida para um equivalente protobuf interno, que captura a intenção semântica da configuração. O backend do SAFE então traduz essa configuração semântica em uma árvore de expressão Boolean. Uma descrição protobuf desta árvore de expressão Boolean é entregue ao SDK do SAFE, que a carrega em uma representação na memória ainda mais compactada da configuração.

A maioria das alterações de estado das flags é iniciada a partir de uma UI interna para gerenciar as flags do SAFE. Esta UI permite que os usuários criem, modifiquem e aposentem flags por meio de um fluxo de trabalho que abstrai grande parte da complexidade do Jsonnet para alterações simples, ao mesmo tempo que fornece acesso à maior parte do poder da DSL para casos de uso avançados.
Uma IU rica também nos permitiu disponibilizar recursos adicionais de qualidade de vida, como a capacidade de programar a alternância de flags, suporte para verificações de integridade pós-merge e ferramentas de depuração para determinar alternâncias de flags recentes que afetaram uma determinada região ou serviço.
Todas as alterações de flag SAFE são criadas como PRs normais do Github e validadas por um extenso conjunto de validadores de pré-merge. Esse conjunto de validadores cresceu para abranger dezenas de verificações individuais, à medida que aprendemos mais sobre a melhor forma de nos protegermos contra alterações de flag potencialmente inseguras. Durante a introdução inicial do SAFE, as análises post-mortem de incidentes que foram causados ou mitigados por uma alteração de flag SAFE informaram muitas dessas verificações. Agora temos verificações que, por exemplo, exigem revisão especializada em alterações de grande blast radius, exigem que uma versão binária específica do serviço seja implantada antes que um flag possa ser ativado, evitam padrões sutis e comuns de configuração incorreta e assim por diante.
As equipes também podem definir suas próprias verificações de pré-merge específicas para a flag ou equipe, para aplicar invariantes em suas configurações.
Dado o papel crítico do SAFE na estabilidade do serviço, o sistema é projetado com várias camadas de resiliência para garantir a operação contínua, mesmo quando partes do pipeline de entrega falham.
O cenário de falha mais comum envolve interrupções no caminho de entrega da configuração. Se algo no caminho de entrega resultar em falha na atualização das configurações, os serviços simplesmente continuarão a usar sua última configuração conhecida até que o caminho de entrega seja restaurado. Essa abordagem de "fail static" garante que o comportamento do serviço existente permaneça estável mesmo durante interrupções no upstream.
Para cenários mais graves, mantemos vários mecanismos de fallback:

Dentro do próprio SDK do SAFE, o design defensivo garante que os erros de configuração tenham um impacto limitado. Se a configuração de uma flag específica estiver malformada, apenas essa única flag é afetada. O SDK também mantém o contrato de nunca lançar exceções e, em caso de falha, sempre reverte para o valor padrão do código, de modo que os desenvolvedores de aplicativos não precisam tratar a avaliação da flag como um processo falível. O SDK também alerta imediatamente os engenheiros de plantão quando ocorrem falhas de análise ou avaliação da configuração. Devido à maturidade do SAFE e à validação extensiva pré-merge, essas falhas são agora extremamente infrequentes em produção.
Essa abordagem em camadas para a resiliência garante que o SAFE se degrade de forma suave e minimiza o risco de se tornar um ponto único de falha.
Minimizar as dependências e o fallback redundante em camadas reduzem a carga operacional. Apesar de ser implantado e usado intensivamente por quase todas as superfícies de compute na Databricks, a carga operacional de manter o SAFE tem sido bastante gerenciável. Adicionar redundâncias em camadas, como o pacote de inicialização a frio e o comportamento de "falha estática" do SDK, tornou grande parte da arquitetura do SAFE autorregenerativa.
A experiência do desenvolvedor é fundamental. Escalar o "aspecto humano" de um sistema de flagging robusto exigiu um forte foco em UX. A SAFE é um sistema de missão crítica, frequentemente usado para mitigar incidentes. Por isso, criar uma UX amigável para trocar as flags durante emergências teve um grande impacto. Adotar uma mentalidade focada no produto levou a menos problemas pequenos, menos confusão e, por fim, a um menor tempo médio de recuperação (MTTR) para incidentes em toda a empresa.
Faça das "melhores práticas" o caminho de menor atrito. Um dos nossos maiores aprendizados foi que não se pode apenas documentar as melhores práticas e esperar que os engenheiros as sigam. Os engenheiros têm muitas prioridades concorrentes ao lançar recursos. O SAFE torna o caminho seguro o caminho fácil: liberações graduais exigem menos esforço e têm mais recursos de qualidade de vida disponíveis do que padrões de habilitação mais arriscados. Quando o sistema incentiva um comportamento mais seguro, a plataforma pode incentivar os engenheiros a adotar uma cultura de gerenciamento de mudanças responsável.
O SAFE é agora uma plataforma interna madura no Databricks e é amplamente utilizado. Os investimentos feitos em disponibilidade e experiência do desenvolvedor rendem frutos, pois vemos uma redução contínua tanto no tempo médio para resolução quanto no raio de impacto de incidentes de produção por meio do uso das flags do SAFE.
À medida que a superfície do produto da Databricks continua a se expandir, as primitivas de infraestrutura subjacentes a esses produtos também se expandem em abrangência e complexidade. Como resultado, tem havido um investimento significativo e contínuo para garantir que o SAFE ofereça suporte a todos os locais onde os engenheiros da Databricks escrevem e implantam código.
Se você tem interesse em dimensionar infraestruturas de missão crítica como esta, explore as vagas abertas na Databricks!
(Esta publicação no blog foi traduzida utilizando ferramentas baseadas em inteligência artificial) Publicação original
Engenharia
December 3, 2025/11 min de leitura
Soluções
December 30, 2025/5 min de leitura


