Por uma logística sem servidores, baseada em eventos usando blockchain
05/01/2021
Neste breve artigo tentarei detalhar a mudança de paradigma pela qual a plataforma de softwares que criamos na Dedalog vem passando. Uma mudança precipitada por nossa visão de longo prazo de um futuro altamente competitivo e com demandas de escala do e-commerce brasileiro.
A Dedalog é uma startup de logística que presta serviço de Fulfillment para o e-commerce brasileiro. Ou seja: estoca, embala e envia pedidos para os clientes. Apesar de parecer simples, o stack tecnológico necessário para garantir uma operação veloz, confiável e escalável não é trivial.
Partimos de algumas premissas operacionais e estruturais para elaborar esta nova arquitetura de software:
alta confiabilidade e precisão dos dados de posição de estoque e na gestão de pedidos, já que armazenamos e sincronizamos pedidos de terceiros e precisamos operar seguindo normas fiscais e contábeis específicas para nossa operação de logística;
elasticidade na capacidade de processamento de pedidos, considerando que a sazonalidade no e-commerce é marcante e não queremos pagar por uma alta capacidade provisionada nos períodos de baixa demanda;
assincronia dos processos internos para evitar que longas cadeias de eventos fiquem bloqueadas ou funções essenciais do sistema demorem para executar caso sejam chamadas uma a uma de maneira síncrona;
flexibilidade na modelagem de dados e esquemas de eventos (schemas) que são transmitidos pelo sistema para poder abrigar novos casos de usos e permitir a segregação entre a camada de registro e a camada de consulta do sistema (mais conhecido como CQRS).
O ponto de partida e estrutura central da nossa arquitetura é o Amazon QLDB. Um banco de dados lançado pela AWS há pouco mais de um ano cujas características se encaixam nas nossas premissas. Vejamos:
O QLDB, ao contrário dos bancos de dados relacionais, é schemaless: ao criar uma tabela no QLDB você não precisa definir previamente quais serão as "colunas" dos seus dados já que ele funciona no modelo de documentos (MongoDB é a referência tradicional para este tipo de modelo). Isto permite que os dados/eventos que serão gravados nesta base de dados possam ter estruturas completamente diferentes entre si, sem estarem sujeitos a um "esquema" rígido e pré-definido pela aplicação.
Este banco de dados oferece também um serviço de streaming acoplado ao Kinesis onde todas as alterações são propagadas na forma de eventos e podem ser consumidas simultaneamente e de forma assíncrona por vários micro serviços com responsabilidades distintas. Por exemplo: um item no armazém é vendido e fica com zero unidades em estoque. Este evento - ou melhor, esta cadeia de eventos: novo pedido → reserva de itens do pedido no estoque → nova posição de estoque - é gravado no QLDB e transmitido imediatamente através do Kinesis. Um micro serviço que está acoplado a este streaming é acionado e sua função é enviar uma mensagem por whatsapp para o lojista dono daquele item, avisando que o produto esgotou e que ele precisa fazer uma reposição imediatamente.
Estas características poderiam ser resolvidas facilmente com o DynamoDB, porém o que diferencia o QLDB de outras soluções é seu parentesco com as frameworks de blockchain. O QLDB "fornece um log de transações transparente, imutável e criptograficamente verificável" que, ao contrário das aplicações tradicionais de blockchain de consenso descentralizado, pertence a uma "autoridade central confiável". Ele resolve o problema de escalabilidade que um sistema descentralizado apresenta ao mesmo tempo que fornece a imutabilidade e verificação criptográfica do histórico completo de transações efetuadas nos dados. Escala e confiabilidade.
Além do recurso de imutabilidade e verificação criptográfica à la blockchain (mais detalhes técnicos aqui sobre como o sistema cria esta blockchain através de hash SHA-256 e Merkle trees), outra grande diferença se comparado ao DynamoDB é que todas as operações de escrita no QLDB são transacionais e trazem automaticamente controle de conflitos de simultaneidade (o OCC). Se usado corretamente (não funciona para qualquer modelo de dados!) este banco de dados pode funcionar naturalmente como a "fonte da verdade" do estado dos seus dados.
Colocando o QLDB no centro da nossa arquitetura, passamos em seguida para a modelagem da orquestração do fluxo de eventos que atravessam o sistema.
Todos os eventos que circulam pela arquitetura possuem esquemas (schema) pré-definidos através de JSON Schemas (modelo inspirado no pessoal da Hello Retail da Nordstrom). Cada chamada da API que inclui um evento deve ser descrita através de um json. Este json deve obedecer um schema válido para poder ser aceito e então propagar-se através da arquitetura. A orquestração interna da plataforma também obedece este sistema de schemas, onde cada evento é transportado através dos streamings do Kinesis que, por sua vez, vão desencadear uma sequência de novos eventos que serão consumidos por camadas de micro serviços que poderão executar suas funções. Assim chegamos a uma arquitetura EDA (Event-driven Architecture) com a premissa do Event Sourcing (que, na definição de Martin Fowler, "é o sistema que captura todas as mudanças do estado de uma aplicação na forma de uma sequência de eventos").
Por fim, este fluxo de eventos é agregado e transformado para podermos criar a camada de consulta da nossa arquitetura. É nela onde estão os bancos de dados (DynamoDB e Aurora) utilizados para a leitura do estado da aplicação na forma como nossos clientes ou equipes internas precisam. Sejam eles nossos endpoints de cotação de frete em tempo real, nas notificação push de posição de estoque dos produtos de um fornecedor ou endpoints de séries temporais para análises de curvas de demandas de uma loja.
Uma visão resumida da nossa arquitetura na AWS, com a separação entre:
o que chamamos de camada da fonte da verdade, onde as operações de insert e update dos eventos são efetuadas;
a camada intermediária, o streaming de eventos, com os eventos validados pela fonte de verdade, a partir da qual uma orquestra de micro serviços opera constantemente para executar tarefas assíncronas baseadas no tipo de eventos que escutam;
e a camada de consulta, onde o estado atual das informações fica disponível para serem consultados através de chamadas API.
É claro que, como em qualquer escolha de stack, você deve abrir mão de algumas coisas para se beneficiar de outras. Este desenho apresenta vários desafios e dificuldades que não elaborei aqui. Uma visão mais aprofundada de cada camada com seus principais agentes e eventos e os problemas intrínsecos a estas escolhas ficam para um próximo artigo.
Resumo do stack utilizado:
- Amazon QLDB
- QLDB Stream
- Kinesis Streams
- DynamoDB
- Aurora
- Lambdas
- S3
- API Gateway
- Serverless Framework