LMAX: 6 milhões de transações por segundo com uma única thread
Martin Fowler, autor de diversos livros essenciais sobre arquitetura e desenvolvimento de sistemas corporativos, publicou recentemente em seu blog uma descrição detalhada da arquitetura da plataforma financeira LMAX. Também apresentou como foi desenvolvida a plataforma de modo a atingir uma impressionante taxa de 6 milhões de transações por segundo, usando apenas uma thread, usando hardware comum:
A medição de 6 milhões de transações por segundo foi realizada em um servidor Dell Nehalem quad core dual socket de 3Ghz com 32 GB RAM.
A plataforma financeira LMAX foi apresentada em 2010, nos QCon de Londres e de São Francisco, este último com gravação do InfoQ. As apresentações tiveram grande repercussão em sites e blogs sobre arquitetura de sistemas.
As plataformas financeiras em geral têm requisitos complexos, mas esta tinha um novo complicador. Ao invés de ser vendida para poucos clientes corporativos, seria oferecida a clientes no varejo, com uma expectativa de altíssimo volume de transações por segundo.
Tendo lidado com diversos problemas de desempenho no desenvolvimento de um sistema de apostas esportivas, a equipe do LMAX decidiu explorar arquiteturas alternativas às soluções tradicionais envolvendo coordenação de sessões com bancos de dados relacionais.
Paralelismo e filas
O primeiro protótipo da arquitetura, com foco em paralelismo, foi construído usando o modelo de atores. Neste modelo ao invés de se controlar a concorrência com as primitivas tradicionais (Mutex, Semaforo etc.), são utilizados objetos de alto nível como atores e mensagens.
Apesar de ter sua origem na década de 70, o modelo de atores tem ganhado popularidade apenas recentemente, devido a dificuldades apresentadas no controle de concorrência entre múltiplos núcleos de processamento, como os encontrados nas CPUs modernas. No entanto, o modelo já é cidadão de primeira classe em linguagens como Scala e Erlang.
A equipe do LMAX foi até a raiz do problema na avaliação do desempenho do protótipo e observou que o gerenciamento de filas pelos atores é ineficiente do ponto de vista de uso do cache interno do processador, cujo acesso é muito mais rápido que o acesso à RAM. Fowler comenta:
Para colocar alguma informação em uma fila, é preciso (obviamente) escrever naquela fila. De modo similar, para retirar dados da fila, deve-se escrever na fila para realizar a remoção. Há portanto uma contenção de escrita: mais que um cliente pode precisar escrever na mesma estrutura de dados. Para lidar com esse tipo de contenção em filas, normalmente utilizam-se travas (locks). Mas se uma trava é usada, isso pode causar uma troca de contexto com o kernel e quando isso ocorre, o processador provavelmente perderá os dados em seus caches.
A conclusão foi que, para otimização do cache, é necessário que apenas um núcleo do processador escreva em uma dada região de memória. Devido a esta restrição, surgiram duas decisões importantes. A primeira foi criar uma nova estrutura para controle de concorrência sem travas, batizada de "Disruptor". A segunda foi investigar o quão rápido pode ser o processamento da lógica de negócio em uma única thread, se não for usado o controle de concorrência.
Disruptor
A estrutura de controle Disruptor funciona como uma fila circular para múltiplos clientes. Nessa fila, tudo o que é adicionado pelos produtores é disponibilizado paralelamente aos consumidores. São utilizados apenas contadores simples, ao invés de travas, para garantir que o limites de leitura não sejam ultrapassados.
No caso do LMAX, todo evento produzido é processado por três consumidores antes de chegar à lógica de negócio (veja a figura): o journaler, o replicator e o unmarshaller:
- O papel do journaler é persistir todos os eventos. Para isso, não é usado um banco de dados, e sim apenas arquivos sequenciais, cujo acesso no disco é muito eficiente.
- O replicator retransmite os eventos para nós redundantes, que são usados para alta disponibilidade.
- O unmarshaller desserializa os eventos para objetos Java, que serão consumidos pela lógica de negócio.

O artigo de Fowler descreve em mais detalhes os componentes e suas possíveis variações. A empresa LMAX (que deu nome à arquitetura) disponibilizou o Disruptor como um framework sob licença Apache no Google Code, mostrando inovação considerável em um mercado que é geralmente "segredista".
Dave Farley, co-autor do livro Continuous Delivery e membro da empresa LMAX, apresenta em seu blog mais detalhes sobre a lógica de negócio, que é implementada em interfaces e objetos comuns, possibilitando o uso de modelos orientados a objetos ricos e flexíveis. Farley conclui:
Orgulho-me da nossa infraestrutura tecnológica, mas para mim o ganho real não é o grau de sofisticação da arquitetura, mas sim o quanto ela libertou a equipe para se concentrar nos problemas de negócio que somos pagos pra resolver.
Thread única
Com a arquitetura descrita, o processamento da lógica de negócio pode ser executado em apenas uma thread, pois os Disruptors gerenciam I/O e concorrência. Os Disruptors e o cache "aquecido" – que é acessado o máximo possível antes de se se buscar na memória principal – foram fatores essenciais para se atingir o altíssimo desempenho medido.
Fowler ressalta ainda o quanto os testes de desempenho foram importantes para se chegar a tais resultados, mas alerta:
Criar código de testes de alto desempenho pode ser tão difícil quanto escrever código para produção. É comum obter resultados falsos, devido aos testes não serem tão rápidos quanto o componente sob medição.
Aplicações
Na sua conclusão, Martin Fowler apresenta considerações importantes sobre como podemos aproveitar a arquitetura LMAX em nossos sistemas. Apesar de o cenário da LMAX ser um tanto particular e extremo, as decisões e componentes utilizados são comuns em arquiteturas modernas.
Manter os dados em memória RAM e usar o disco apenas para restauração e backup, por exemplo, é uma estratégia comum em produtos de grid e noSQL, como Infinispan, Coherence, Prevayler, entre outros. A maneira como os eventos são utilizados é semelhante ao sistema CQRS, apesar de este não ser usado explicitamente pelo LMAX. (Para uma introdução ao CQRS, veja o artigo de Fowler sobre o assunto e essa palestra de Pedro Teixeira, realizada no ultimo QCon São Paulo.)
Mesmo que a sua arquitetura seja menos estrita e use muito menos recursos, os dilemas e decisões enfrentados pela LMAX são certamente instrutivos e reaproveitáveis em diversas situações.
Leandro
by
leandro moreira
Thread única?
by
Fernando Lozano
Além disso, a arquiteura exige que existam outras instâncias do conjunto disruptors + business processors rodando em paralelo, para que não haja perda de serviço em caso de problemas com uma das instâncias, o que obrigaria a uma potencialmente demorada re-execução de toda a fila de eventos.
A equipe do LMAX também gera snapshots diários de cada instância e reinicia cada uma para manter um nível de serviço alto. TODO o estado do sistema está contido no último smapshot + fila de eventos posteriores, não existe nenhum outro armazenamento persistente nesta arquitetura, em especial não existe um BD.
O LMAX é uma arquitetura muito interessante e de sucesso comprovado, mas não pensem que é trivial trabalhar hoje em dia com qualquer arquitetura diferente do modelo transacional baseado em bancos de dados relacionais. ;-)
Re: Thread única?
by
Julio Faerman
Re: Thread única?
by
Fernando Lozano
Eu concordo que o artigo original não deixa claro se são 6M transações considerando apenas o business processor ou se considerando a arquitetura como um todo, mas eu não vejo como poderia ser diferente (de considerar tudo).
Re: Thread única?
by
Fernando Lozano
Re: Thread única?
by
José Filipe Neis
De qualquer maneira, não acho que o número de tps é o ponto mais importante do artigo. O throughput dos caras vai ser algo assustador de qualquer maneira. A grande sacada, a meu ver, está numa maneira melhor de trabalhar com os locks. Como o Fernando colocou no comentário anterior, não é simples, mas cenários de alto volume (como o do LMAX) tem sérias dificuldades pra rodar com o tradicional modelo de BD relacional (na verdade, o volume não precisa nem ser tão alto assim :)).
Re: Thread única?
by
Julio Faerman
Re: Thread única?
by
Julio Faerman
Conteúdo educacional
Mobilidade: Frameworks, SOs e o Mercado
Ricardo Ogliari 23 Mai, 2013
Caminhos de uma estratégia mobile
Sérgio Lopes 23 Mai, 2013
Complexidade organizacional no Século 21
Alexandre Magno 16 Mai, 2013

Olá visitante
Você precisa cadastrar-se no InfoQ Brasil ou Login para enviar comentários. Há muitas vantagens em se cadastrar.Obtenha o máximo da experiência do InfoQ Brasil.
Dê sua opinião