A Pilha Transacional Moderna

A Pilha Transacional Moderna

A moderna pilha transacional PlatoBlockchain Data Intelligence. Pesquisa vertical. Ai.

Os bancos de dados transacionais têm sido o componente mais crítico do design de aplicativos. Por que? Porque um banco de dados estável geralmente é o ponto de aplicação final para correção em um mundo confuso e distribuído. Sem eles, pagaríamos a mais e a menos. Perderíamos passageiros tentando voltar do aeroporto para casa e perderíamos itens em nossos carrinhos de compras. Nossas contas online seriam perdidas, duplicadas ou corrompidas e ficariam inoperáveis. 

Na verdade, o banco de dados transacional (geralmente chamado de OLTP — abreviação de processamento de transações online — banco de dados) tem sido tão central para o desenvolvimento de aplicativos que, ao longo do tempo, consumiu cada vez mais funcionalidade do aplicativo. No entanto, os microsserviços e outras arquiteturas de aplicativos modernos introduziram novas complexidades no design de aplicativos: os desenvolvedores precisavam gerenciar dados em diferentes serviços e garantir a consistência entre eles, o que os forçou a criar internamente mecanismos complexos de sincronização e processamento de dados. 

E assim, como uma indústria, estamos vendo uma consciência crescente de que as garantias transacionais são necessárias fora do modelo tradicional. estamos vendo o surgimento de sistemas que estendem fortes garantias transacionais além do banco de dados, para os próprios aplicativos distribuídos

Temos rastreado essas soluções nos últimos anos. Geralmente, eles se esforçam para permitir o gerenciamento transacional do estado em um grande aplicativo distribuído, sem criar desafios de dimensionamento e ao mesmo tempo fornecer um ambiente de programação moderno. 

Achamos que essas soluções se dividem em duas categorias. Uma categoria é orquestração do fluxo de trabalho. Isso basicamente garante que um bloco de código será executado até a conclusão, mesmo em caso de falha. Portanto, ele pode ser usado com o objetivo de gerenciar uma máquina de estado distribuída de forma determinística sem ficar instável. A segunda categoria é banco de dados + fluxo de trabalho, que estende o design de banco de dados OLTP tradicional, permitindo a execução de código arbitrário para a mesma finalidade. 

Essa ainda é uma área muito incipiente e há muita confusão em torno da nomenclatura, de como cada ferramenta é usada na prática e de quem deve usá-la. Para ajudar a entender melhor, perguntamos aos profissionais das principais organizações de engenharia sobre sua pilha transacional e como eles estão pensando sobre três conceitos principais para cargas de trabalho transacionais: estado do aplicativo, lógica de negócios e dados de negócios. 

Antes de examinar essas novas pilhas, porém, aqui está uma rápida digressão semi-técnica para ajudar a entender como chegamos aqui.

Transações, garantias e aplicativos modernos 

A versão mais aproximada é esta: há um conjunto de tarefas — transações — que você quer fazer todas ou nada. Qualquer coisa intermediária (ter feito parcialmente) terminará em um estado corrompido. É difícil garantir nada em um sistema distribuído, mas os bancos de dados funcionam bem com transações. Portanto, a maneira mais fácil de lidar com garantias em muitos sistemas é apenas fazer a maioria das transações e deixar o banco de dados lidar com elas.

Aplicativos modernos são grandes sistemas distribuídos com muitos usuários fazendo muitas coisas. Portanto, mesmo mantendo o estado do aplicativo consistente (como rastrear onde diferentes usuários estão em um fluxo de check-out) se transforma em um problema de transação distribuída. Nas arquiteturas monolíticas tradicionais, o gerenciamento de transações usando SQL com um banco de dados OLTP era um tanto eficaz. Mas no novo e complexo mundo dos microsserviços interagindo por meio de APIs de alto nível (por exemplo, REST ou gRPC), as necessidades transacionais tornaram-se distribuídas por natureza. 

No entanto, muitas empresas que estão migrando para microsserviços não fizeram muito para estender garantias transacionais fortes além do banco de dados. E, na prática, isso é quase sempre OK. Mas, à medida que os aplicativos aumentam, as inconsistências nos dados aumentam, assim como os bugs resultantes e os erros não reconciliados nos dados corporativos. O que, claro, pode ser extremamente problemático. Isso força os desenvolvedores de aplicativos a lidar com uma ampla gama de cenários de falha e estratégias de resolução de conflitos e a garantir a consistência do estado criando suas próprias estratégias por meio de diferentes padrões de arquitetura.

Definições

Dados comerciais (“dados”) refere-se aos dados críticos de negócios tradicionalmente armazenados em um banco de dados OLTP para persistência e processamento (por exemplo, informações de perfil do usuário, como nome, endereço, pontuação de crédito, etc.).

Estado do aplicativo refere-se ao estado atual do sistema; o estado do aplicativo é determinado por um valor armazenado em um sistema de armazenamento de dados e em qual etapa a execução do programa está em uma máquina de estado finito (por exemplo, o estado de um pedido, como “pedido recebido”, “estoque verificado”, “crédito verificado ,” “enviado,” “devolvido”).

Logíca de negócios refere-se à parte do programa que trata de como o aplicativo realmente funciona ou o que ele faz, em vez de detalhes de execução (por exemplo, “Se user_income > $100K & credit_score >650 ⇒ mortgage_approved = TRUE”).

Para os propósitos desta discussão, é importante distinguir o estado do aplicativo e os dados de negócios. Por exemplo, saber que um cliente inseriu seu cartão de crédito, mas não fez o check-out, é o estado do aplicativo. Os dados do cartão de crédito e os itens do carrinho do aplicativo são os dados do negócio. 

A moderna pilha transacional PlatoBlockchain Data Intelligence. Pesquisa vertical. Ai.

Em um fluxo típico, uma solicitação vem do front-end, é autenticada e, em seguida, é roteada por meio de um gateway de API ou GraphQL para o endpoint relevante. 

Esse único endpoint de API agora precisa orquestrar dezenas ou centenas de microsserviços para entregar a transação comercial ao cliente final. É aqui que os desenvolvedores geralmente agrupam tudo em blobs de lógica de negócios e, em seguida, usam uma combinação de filas, caches e mecanismos de repetição codificados à mão para obter os dados no banco de dados - esperamos que sejam confirmados como uma transação completa.

À medida que a escala do aplicativo aumenta, também aumenta a complexidade do gerenciamento de filas e caches, bem como o número de arestas vivas na lógica de reconciliação quando surgem problemas. 

A ascensão de pilhas transacionais centradas no fluxo de trabalho e centradas no banco de dados

OK, então as transações são importantes. LAMP em um banco de dados não era suficiente para escala. E uma bola de pelo gigante de filas e lógica de repetição é muito frágil. Para lidar com isso, temos visto, nos últimos anos, o surgimento de novas soluções que trazem de volta a sanidade à lógica transacional. Elas podem ser categorizadas aproximadamente como abordagens centradas no fluxo de trabalho ou abordagens centradas no banco de dados.

Até o momento, os mecanismos de fluxo de trabalho funcionam principalmente no estado do aplicativo, e não nos dados de negócios, e geralmente exigem alguma complexidade ao integrar com bancos de dados tradicionais. Abordagens centradas em banco de dados adicionam lógica de aplicativo junto com dados de negócios, mas ainda não têm a mesma sofisticação de execução de código dos mecanismos de fluxo de trabalho. 

O diagrama abaixo fornece um esboço aproximado de como as abordagens centradas no fluxo de trabalho e/ou no banco de dados são usadas em um aplicativo Javascript/Typescript, supondo que ambos estejam em uso. Embora sejam peças distintas dessa arquitetura hoje, vimos os primeiros sinais de uma tendência em que os bancos de dados estão incorporando recursos de fluxo de trabalho e os fluxos de trabalho estão começando a adotar armazenamento durável. Essa fusão de recursos indica que as linhas entre as duas abordagens estão se tornando menos nítidas e menos distintas nas arquiteturas modernas. 

A moderna pilha transacional PlatoBlockchain Data Intelligence. Pesquisa vertical. Ai.

Abordagens centradas no fluxo de trabalho em detalhes 

Um fluxo de trabalho é simplesmente blocos de código executados com base em eventos, ou cronômetros, que envolvem a máquina de estado do aplicativo. O fluxo de trabalho transacional garante a execução do código com fortes garantias, evitando estados parciais ou não intencionais no aplicativo. Os desenvolvedores escrevem a lógica e o mecanismo de fluxo de trabalho lida com transações, mutações e idempotência. Diferentes mecanismos de fluxo de trabalho fazem diferentes compensações em termos de quanto dos detalhes da transação são expostos aos desenvolvedores. 

Como exemplo, abaixo está uma representação visual de um fluxo de trabalho de check-out em execução no Orkes (Condutor): 

A moderna pilha transacional PlatoBlockchain Data Intelligence. Pesquisa vertical. Ai.

Tem duas abordagens grosseiras pelo qual os mecanismos de fluxo de trabalho ganham força. Em um (tipificado por Temporal.io), os desenvolvedores escrevem código usando linguagens de programação de back-end padrão (por exemplo, Go ou Java) e o o sistema garantirá que o código seja executado até a conclusão, mesmo durante uma falha. Nesse modelo, a pilha de chamadas de programa é mantida mesmo se o código estiver aguardando a conclusão de uma chamada de bloqueio (por exemplo, leitura ou gravação). Para fazer isso, o tempo de execução da linguagem é modificado para impedir a execução parcial do código durante falhas. A vantagem dessa abordagem é que os desenvolvedores podem escrever em linguagens familiares e depurar facilmente com uma pilha de chamadas mantida. Vemos essa abordagem mais popular entre as equipes de back-end que lidam com aplicativos grandes e sofisticados. 

A desvantagem é que geralmente requer muito trabalho de integração e código wrapper para expor interfaces úteis e seguras aos desenvolvedores de aplicativos. Outra desvantagem é que ele depende de uma camada de execução personalizada em vez da linguagem simples, e há casos extremos em que a execução será diferente do tempo de execução da linguagem nativa. Portanto, embora os desenvolvedores possam usar linguagens com as quais estão familiarizados, eles ainda precisam entender como o sistema subjacente funciona.  

A outra abordagem, que é mais popular entre os desenvolvedores de aplicativos (particularmente Typescript/Javascript), é que o mecanismo de fluxo de trabalho servir como um orquestrador de funções assíncronas (por exemplo, Ingest, Defer e Trigger). Nesse modelo, eventos ou funções de terceiros são direcionados para o mecanismo de fluxo de trabalho, que despachará a lógica registrada pelos programadores da aplicação, que devem devolver o controle quando surgir a necessidade de bloquear em outra função assíncrona. A vantagem é que este é um método muito mais leve de integração em um programa. Também força estrutura suficiente no código para que a equipe que trabalha nele possa entendê-lo mais facilmente. No entanto, essa abordagem pode ser mais difícil de depurar sem suporte de ferramentas, portanto, a depuração tende a ser específica da plataforma.

Os mecanismos de fluxo de trabalho são particularmente poderosos porque permitem a adoção gradual por aplicativos existentes. Eles podem ser aplicados de forma fragmentada a determinados fluxos de trabalho com pegada mínima. Dito isso, as duas maiores deficiências dos mecanismos de fluxo de trabalho decorrem do fato de que eles não se estendem ao banco de dados. Como resultado, não há uma única fonte de verdade que possa ser consultada no estado do aplicativo e nos dados de negócios. Além disso, a semântica transacional geralmente é diferente da semântica do banco de dados, exigindo que os desenvolvedores de aplicativos lidem com as condições de borda. 

Embora não seja a norma hoje, queremos ilustrar as arquiteturas conceituais de como os fluxos de trabalho podem, em muitos casos, ser usados ​​como armazenamentos de dados persistentes:

Exemplos de arquiteturas somente de fluxo de trabalho

A moderna pilha transacional PlatoBlockchain Data Intelligence. Pesquisa vertical. Ai.

Arquitetura somente de fluxo de trabalho: aplicativos JavaScript

A moderna pilha transacional PlatoBlockchain Data Intelligence. Pesquisa vertical. Ai.

Arquitetura somente de fluxo de trabalho: aplicativos que usam microsserviços

Abordagens centradas em banco de dados em detalhes 

As abordagens centradas no banco de dados começam com um banco de dados, mas o estendem para oferecer suporte à execução de código arbitrário para permitir fluxos de trabalho juntamente com o gerenciamento de dados. Eles fazem isso dando controle aos programadores para que possam tomar decisões explícitas sobre mutações, transações e idempotência para blocos de código regulares — essencialmente expondo a semântica OLTP diretamente. O programador é responsável por manter a lógica de negócios e os dados de negócios separados do estado do aplicativo. 

De fato, a visão pura do banco de dados é que o estado do aplicativo sempre pode ser derivado dos dados de negócios. Isso geralmente é feito armazenando o estado do aplicativo como um conjunto de transações que modificam os dados de negócios no banco de dados. É mais fácil pensar nisso como um banco de dados que pode executar blocos de código com as mesmas garantias fortes dos sistemas de fluxo de trabalho descritos acima. 

Internamente, chamamos isso de plataforma transacional de lógica de aplicativo (ALTP) abordagem porque, em última análise, estende as transações OLTP para o aplicativo. Mas o que realmente caracteriza o ALTP é que, para aplicativos novos, ele pode eliminar totalmente a necessidade de os desenvolvedores de aplicativos gerenciarem diretamente a infraestrutura de back-end.  

Pela lente do ALTP, a abordagem mais usada começou com o Firebase, que oferece uma "experiência de back-end" de serviço completo incluindo autenticação, armazenamento de dados, bancos de dados e muito mais. Firebase e participantes mais recentes, como Supabase, continuam sendo plataformas muito populares para projetos greenfield. E enquanto eles tendem a permanecer fiéis às suas raízes OLTP - e, portanto, não oferecem suporte à execução de código arbitrário para funções de back-end transacionais - o Supabase já está começando a adicionar suporte para fluxos de trabalho.

O Mercado Pago não havia executado campanhas de Performance anteriormente nessas plataformas. Alcançar uma campanha de sucesso exigiria ofertas ALTP de última geração como o Convex permitem a execução de código arbitrário como uma transação ao lado do banco de dados. Essas ofertas permitem a gravação de código totalmente compatível com transações em uma linguagem normal (por exemplo, Javascript/Typescript), em que um único bloco de código pode ler, gravar e alterar dados — tanto o estado do aplicativo quanto os dados de negócios. De certa forma, ele fornece aos desenvolvedores uma única fonte de verdade que pode ser consultada e fornece fluxos de trabalho primitivos, como assinaturas. 

O ALTP resolve o problema que os mecanismos de fluxo de trabalho têm ao serem desacoplados do banco de dados, mas, como resultado, exige que os usuários confiem em sua oferta de banco de dados em vez de um OLTP padrão para obter os benefícios. Como resultado, vemos principalmente as equipes adotarem o ALTP para aplicativos novos, em vez de integrá-lo a back-ends complexos existentes.

A moderna pilha transacional PlatoBlockchain Data Intelligence. Pesquisa vertical. Ai.

O diagrama acima é um amálgama de muitos operadores com os quais conversamos. Alguns usarão apenas um mecanismo de fluxo de trabalho. Alguns usarão apenas uma abordagem centrada no banco de dados. Mas muitos usarão os dois — especialmente quando estão começando a adotar fluxos de trabalho. Atualmente, os usuários de mecanismos de fluxo de trabalho tendem a ser equipes de back-end que lidam com aplicativos grandes e complexos, embora também tenhamos visto muitas equipes full-stack adotando-os. As soluções de back-end como serviço tendem a ser mais amigáveis ​​ao desenvolvedor de aplicativos e são mais comumente usadas quando o aplicativo direciona a seleção de tecnologia. 

A convergência

Está ficando claro que as abordagens centradas no fluxo de trabalho e as abordagens centradas no banco de dados estão em rota de colisão. A principal razão para isso é que, embora o estado do aplicativo e o estado do banco de dados sejam logicamente distintos, eles dependem um do outro, e um sistema que não cobre ambos é complexo de corrigir e depurar.  

Por exemplo, considere um mecanismo de fluxo de trabalho sendo usado para rastrear a máquina de estado para o processo de checkout de um usuário e esse usuário está adicionando um item a um carrinho. Normalmente, os mecanismos de fluxo de trabalho garantem que uma etapa de código seja executada mesmo em caso de falha. No entanto, pode haver instâncias em que o mecanismo precise executar novamente uma determinada etapa durante uma falha porque não há certeza absoluta de que a etapa foi totalmente concluída. Se essa etapa envolver a gravação de dados de negócios em um banco de dados tradicional (neste caso, o item no carrinho) e o banco de dados não estiver ciente da repetição duplicada, ele terminará com uma entrada duplicada. 

Existem duas maneiras de lidar com isso. Uma maneira é enviar o problema para o desenvolvedor do aplicativo, que usará um nonce fornecido pelo sistema de fluxo de trabalho para garantir que apenas um item seja gravado. Mas isso pressupõe que o desenvolvedor entenda a idempotência, que é notoriamente difícil de acertar, e isso evita muito da mágica de ter um sistema de fluxo de trabalho. A outra maneira é vincular o mecanismo de fluxo de trabalho a um banco de dados que esteja ciente da semântica transacional do fluxo de trabalho. Isso ainda não aconteceu, mas não é difícil acreditar que acontecerá. 

Por outro lado, as abordagens centradas no banco de dados percebem que o fluxo de trabalho geral é realmente útil para os desenvolvedores de aplicativos. E então estamos começando a ver bancos de dados (como o Convex) — que suportam funções de banco de dados tradicionais como consultas, mutações, índices, etc. — implementam funcionalidades como agendamento e assinaturas. Isso permite que sejam usados ​​como mecanismos de fluxo de trabalho. Ou seja, permitem a execução de blocos de código arbitrários com fortes garantias. 

Como disse Ian Livingstone (que forneceu feedback sobre esta peça), “É o clássico 'Você traz a lógica do aplicativo para o banco de dados ou o banco de dados para a lógica do aplicativo?' jogando de novo ... desta vez causado pela quebra do monólito. Tendo essa dicotomia por décadas, é claro que ambos os modelos persistirão no curto prazo. É muito menos claro que continuará sendo o caso a longo prazo. 

Agradecimentos especiais a Charly Poly (Defer), Dan Farrelly (Inngest), David Khourshid (Stately), Ian Livingstone (Cape Security), Enes Akar (Upstash), James Cowling (Convex), Jamie Turner (Convex), Paul Copplestone (Supabase ), Sam Lambert (PlanetScale), Tony Holdstock-Brown (Inngest), Matt Aitken (Trigger) por revisar esta postagem e dar feedback. Além disso, agradecemos a Benjamin Hindman (Reboot), Fredrik Björk (Grafbase), Glauber Costa (Chiselstrike), Guillaume Salles (Liveblocks), Maxim Fateev (Temporal), Steven Fabre (Liveblocks) e Viren Baraiya (Orkes) por nos ajudar com a pesquisa.

* * *

As opiniões expressas aqui são as do pessoal individual da AH Capital Management, LLC (“a16z”) citadas e não são as opiniões da a16z ou de suas afiliadas. Certas informações aqui contidas foram obtidas de fontes de terceiros, inclusive de empresas do portfólio de fundos administrados pela a16z. Embora retiradas de fontes consideradas confiáveis, a16z não verificou essas informações de forma independente e não faz representações sobre a precisão duradoura das informações ou sua adequação a uma determinada situação. Além disso, esse conteúdo pode incluir anúncios de terceiros; a16z não revisou tais anúncios e não endossa nenhum conteúdo de publicidade neles contido.

Este conteúdo é fornecido apenas para fins informativos e não deve ser considerado como aconselhamento jurídico, comercial, de investimento ou fiscal. Você deve consultar seus próprios conselheiros sobre esses assuntos. As referências a quaisquer valores mobiliários ou ativos digitais são apenas para fins ilustrativos e não constituem uma recomendação de investimento ou oferta para fornecer serviços de consultoria de investimento. Além disso, este conteúdo não é direcionado nem destinado ao uso por quaisquer investidores ou potenciais investidores, e não pode, em nenhuma circunstância, ser invocado ao tomar uma decisão de investir em qualquer fundo administrado pela a16z. (Uma oferta para investir em um fundo a16z será feita apenas pelo memorando de colocação privada, contrato de subscrição e outra documentação relevante de tal fundo e deve ser lida na íntegra.) Quaisquer investimentos ou empresas de portfólio mencionados, referidos ou descritos não são representativos de todos os investimentos em veículos administrados pela a16z, e não pode haver garantia de que os investimentos serão rentáveis ​​ou que outros investimentos realizados no futuro terão características ou resultados semelhantes. Uma lista de investimentos feitos por fundos administrados por Andreessen Horowitz (excluindo investimentos para os quais o emissor não deu permissão para a a16z divulgar publicamente, bem como investimentos não anunciados em ativos digitais negociados publicamente) está disponível em https://a16z.com/investments /.

Os gráficos e gráficos fornecidos são apenas para fins informativos e não devem ser considerados ao tomar qualquer decisão de investimento. O desempenho passado não é indicativo de resultados futuros. O conteúdo fala apenas a partir da data indicada. Quaisquer projeções, estimativas, previsões, metas, perspectivas e/ou opiniões expressas nestes materiais estão sujeitas a alterações sem aviso prévio e podem diferir ou ser contrárias às opiniões expressas por outros. Consulte https://a16z.com/disclosures para obter informações adicionais importantes.

Carimbo de hora:

Mais de Andreessen Horowitz