Pular para o conteúdo

Papers

Event Sourcing

Martin Fowler · martinfowler.com (artigo), 2005

O problema: saber onde estamos não diz como chegamos aqui

Fowler parte de uma observação simples. Consultar o estado de uma aplicação responde bem à pergunta sobre como o mundo está agora, mas há situações em que também queremos saber como chegamos até ali. A proposta do Event Sourcing é garantir que toda mudança no estado da aplicação fique registrada como uma sequência de eventos. Com esse registro, além de consultar os eventos, dá para reconstruir estados passados e usar o log como base para ajustar o estado automaticamente quando surgem mudanças retroativas. O exemplo do artigo é um sistema de rastreamento de navios. No modelo simples, um serviço recebe chamadas de chegada e partida de porto e atualiza diretamente a localização do navio, de modo que só o estado final fica guardado. Com Event Sourcing, o serviço cria um objeto de evento que descreve a mudança e o processa para atualizar o navio. Visto só como processamento, isso parece uma camada de indireção sem utilidade; a diferença aparece no que persiste. Passam a existir duas coisas guardadas: o estado da aplicação e o log de eventos. Fowler admite que ver por onde o navio passou é um ganho pequeno, porque um histórico de portos no próprio objeto ou um arquivo de log comum também dariam isso. O ponto decisivo é outro: todas as mudanças nos objetos de domínio são iniciadas pelos eventos, e é essa garantia que permite construir funcionalidades em cima do log.

O que o log de eventos permite: rebuild, consulta temporal e replay

Como toda mudança nasce de um evento, o artigo lista três facilidades construídas sobre o log. A primeira é a reconstrução completa: o estado da aplicação pode ser descartado por inteiro e refeito reexecutando os eventos do log numa aplicação vazia. A segunda é a consulta temporal: para conhecer o estado em qualquer ponto do tempo, parte-se conceitualmente de um estado em branco e reexecutam-se os eventos até certo instante ou certo evento. Fowler sugere ir além e considerar várias linhas do tempo, de forma análoga a ramificações em um sistema de controle de versão. A terceira é o replay de eventos. Se descobrimos que um evento passado estava incorreto, podemos calcular as consequências revertendo esse evento e os posteriores e depois reaplicando o evento corrigido e os seguintes; a alternativa é descartar o estado e reproduzir todo o log com o evento correto no lugar. A mesma técnica serve para eventos que chegaram fora de ordem, problema comum em sistemas que se comunicam por mensagens assíncronas. Fowler cita o controle de versão como exemplo corrente: usa consultas temporais com frequência e, no caso do Subversion, reconstrução completa ao fazer dump e restore entre repositórios. Ele diz não conhecer nenhum que faça replay, por não se interessarem por isso. Aplicações corporativas com Event Sourcing, segundo ele, são mais raras, embora tenha visto algumas.

Snapshots e onde guardar o estado

O jeito mais simples de usar Event Sourcing é calcular qualquer estado pedido partindo de um estado vazio e aplicando os eventos. Fowler observa que isso é lento, principalmente quando há muitos eventos. Como, em muitas aplicações, o mais comum é pedir estados recentes, uma alternativa mais rápida é guardar o estado atual e construir as capacidades especiais do Event Sourcing por cima dele. Como o estado é totalmente derivável do log, ele pode ser mantido em cache em qualquer lugar, em memória ou em disco. O artigo descreve um sistema usado durante o dia de trabalho que começa a manhã a partir de um snapshot da noite anterior e mantém o estado corrente em memória. Se cair, ele reproduz os eventos desde o armazenamento noturno. No fim do dia pode-se gerar um novo snapshot, e novos snapshots podem ser feitos a qualquer momento, em paralelo, sem parar a aplicação em execução. Há também uma escolha sobre o sistema de registro oficial. Ele pode ser o log de eventos ou o estado atual. No segundo caso, com o estado num banco de dados, os eventos servem apenas para auditoria e processamento especial. No primeiro, o log é o registro oficial e os bancos de dados podem ser construídos a partir dele sempre que necessário.

Os custos: reversão, sistemas externos e mudanças de código

Uma parte grande do artigo trata das complicações. Primeiro, reverter eventos: é mais simples quando o evento é expresso como diferença (somar 10 à conta) do que como valor final (definir a conta como 110), pois neste último caso não há informação para recuperar o valor anterior. Se o evento não for uma diferença, ele precisa guardar o que for preciso para reverter, como valores anteriores. Fowler lembra que tudo isso também pode ser feito voltando a um snapshot passado e reproduzindo os eventos; a reversão só pesa na eficiência, quando desfazer poucos eventos custa menos do que reaplicar muitos. Segundo, sistemas externos: como replays acontecem à vontade, mensagens de atualização enviadas a sistemas externos, que não distinguem processamento real de replay, dariam errado. A solução é encapsular esses sistemas em um Gateway que sabe se o processador está em replay e, em rebuilds e consultas temporais, costuma bastar desativá-lo, sem que a lógica de domínio perceba. Consultas externas também afetam o resultado: ao reproduzir um evento de 5 de dezembro, queremos a taxa de câmbio daquele dia, não a atual. Opções são consultar dados históricos ou fazer o gateway lembrar as respostas. Terceiro, mudanças de código: novas funcionalidades e correções de bugs no que é interno podem ser aplicadas reprocessando os eventos (com gateways externos, é preciso rastrear a diferença entre o que aconteceu com o bug e sem ele), mas as regras que mudam com o tempo precisam entrar no próprio modelo de domínio. Fowler avisa que o comportamento bitemporal pode ficar muito bagunçado.

Quando usar: auditoria, depuração e arquitetura com muitos leitores

Fowler reconhece que empacotar toda mudança como evento é um estilo de interface com o qual nem todos se sentem à vontade, então a técnica não é uma escolha natural e só vale a pena se houver retorno. Um retorno óbvio é o log de auditoria, útil também para suporte, que pode acompanhar o que um usuário fez; o autor nota, porém, que mecanismos de log comuns também resolveriam isso. Outro uso é a depuração: reproduzir os eventos reais em um ambiente de teste para ver exatamente o que aconteceu, com a possibilidade de parar, voltar e reproduzir, como num depurador, inclusive para testes em paralelo antes de colocar uma atualização em produção. O artigo afirma que Event Sourcing é a base de Parallel Models e Retroactive Events, padrões que o exigem, e que é muito difícil adaptá-lo depois a um sistema que não nasceu assim; por isso, se esses padrões forem prováveis, vale adotá-lo desde já. Há ainda uma possibilidade arquitetural: um sistema com muitos leitores e poucos escritores poderia ser um cluster com bancos em memória atualizados por um fluxo de eventos, enquanto as atualizações vão para um sistema mestre que as aplica e transmite os eventos resultantes. A contrapartida é que os leitores podem ficar defasados em relação ao mestre. Fowler também adverte que o texto é material em rascunho de meados dos anos 2000, sem correções posteriores.

Veja as ideias em ação

Pratique na escola de System Design os desenhos que usam este paper.