O Slideshare usa cookies para melhorar a funcionalidade e o desempenho, e fornecer publicidade relevante. Se continuar a navegar no site, você concorda com o uso de cookies neste site. Veja o nosso Contrato de Usuário e Política de Privacidade. O Slideshare usa cookies para melhorar a funcionalidade e o desempenho, e fornecer publicidade relevante. Se continuar a navegar no site, você concorda com o uso de cookies neste site. Consulte nossa Política de Privacidade e Contrato de Usuário para obter detalhes. Explore todos os seus tópicos favoritos no aplicativo SlideShare Obtenha o aplicativo SlideShare para Salvar para Mais tarde, mesmo offline Continuar para o site móvel Fazer o upload de inscrição de login Toque toque para diminuir o zoom Arquitetura de sistema de negociação de renda fixa Compartilhe este SlideShare LinkedIn Corporation copy 2017A arquitetura LMAX Nos últimos Anos, continuamos ouvindo que o almoço gratuito é superior a 1 - não podemos esperar aumentos na velocidade individual da CPU. Então, para escrever código rápido, precisamos usar explicitamente múltiplos processadores com software concorrente. Esta não é uma boa notícia - escrever código concorrente é muito difícil. Locks e semaforos são difíceis de argumentar e difíceis de testar - o que significa que estamos gastando mais tempo nos preocupando com a satisfação do computador do que estamos resolvendo o problema do domínio. Vários modelos de concorrência, como atores e memória transacional de software, visam tornar isso mais fácil - mas ainda há um fardo que apresenta erros e complexidade. Então eu fiquei fascinado ao ouvir sobre uma conversa no QCon London, em março do ano passado, da LMAX. LMAX é uma nova plataforma de comércio financeiro de varejo. A inovação comercial é que é uma plataforma de varejo - permitindo que qualquer pessoa troque em uma variedade de produtos derivados financeiros2. Uma plataforma de negociação como essa precisa uma latência muito baixa - os negócios devem ser processados rapidamente porque o mercado está se movendo rapidamente. Uma plataforma de varejo acrescenta complexidade porque tem que fazer isso para muitas pessoas. Assim, o resultado é mais usuários, com muitos negócios, todos os quais precisam ser processados rapidamente.3 Dado o deslocamento para o pensamento multi-core, esse tipo de desempenho exigente naturalmente sugeriria um modelo de programação explicitamente concorrente - e de fato esse era o seu ponto de partida. Mas o que chamou a atenção das pessoas no QCon foi que não era onde eles acabaram. Na verdade, eles acabaram fazendo toda a lógica de negócios para sua plataforma: todos os negócios, de todos os clientes, em todos os mercados - em um único tópico. Um tópico que processará 6 milhões de pedidos por segundo usando hardware de commodities.4 Processando lotes de transações com baixa latência e nenhuma das complexidades do código concorrente - como posso resistir a cavar para isso Felizmente, outra diferença que LMAX tem para outras empresas financeiras é essa Eles estão bastante felizes em falar sobre suas decisões tecnológicas. Então, agora, a LMAX está em produção por um tempo, é hora de explorar seu design fascinante. Estrutura geral Figura 1: arquitetura LMAXs em três blobs Em um nível superior, a arquitetura possui três interruptores de saída de disruptor de entrada de processador de lógica de negócios de peças. Como o próprio nome indica, o processador de lógica de negócios lida com toda a lógica de negócios na aplicação. Como eu indiquei acima, ele faz isso como um programa java single-threaded que reage a chamadas de método e produz eventos de saída. Conseqüentemente, é um programa java simples que não requer qualquer estrutura de plataforma para executar além da JVM em si, o que permite que ele seja executado facilmente em ambientes de teste. Embora o Business Logic Processor possa ser executado em um ambiente simples para testes, há uma coreografia bastante mais envolvente para executá-lo em uma configuração de produção. As mensagens de entrada precisam ser retiradas de um gateway de rede e desmarcadas, replicadas e registradas no diário. As mensagens de saída precisam ser empacotadas para a rede. Essas tarefas são tratadas pelos disruptores de entrada e saída. Ao contrário do Business Logic Processor, estes são componentes concorrentes, uma vez que envolvem operações IO que são lentas e independentes. Eles foram projetados e construídos especialmente para LMAX, mas eles (como a arquitetura geral) são aplicáveis em outros lugares. Business Logic Processor Mantendo tudo em memória O Business Logic Processor recebe mensagens de entrada sequencialmente (na forma de uma invocação de método), executa lógica de negócios e emite eventos de saída. Ele opera totalmente na memória, não há banco de dados ou outra loja persistente. Manter todos os dados na memória tem dois benefícios importantes. Em primeiro lugar, é rápido - não há banco de dados para fornecer IO lento para acessar, nem há nenhum comportamento transacional a ser executado, já que todo o processamento é feito sequencialmente. A segunda vantagem é que simplifica a programação - não há mapeamento objeto-racional para fazer. Todo o código pode ser escrito usando o modelo de objeto Javas sem ter que comprometer o mapeamento para um banco de dados. Usar uma estrutura na memória tem uma conseqüência importante - o que acontece se tudo falhar Mesmo os sistemas mais resilientes são vulneráveis a alguém que puxa o poder. O coração de lidar com isso é Event Sourcing - o que significa que o estado atual do Business Logic Processor é inteiramente derivável processando os eventos de entrada. Enquanto o fluxo de eventos de entrada for mantido em uma loja durável (que é um dos trabalhos do disruptor de entrada), você sempre pode recriar o estado atual do mecanismo de lógica de negócios, repetindo os eventos. Uma boa maneira de entender isso é pensar em um sistema de controle de versão. Os sistemas de controle de versão são uma seqüência de compromissos, em qualquer momento você pode construir uma cópia de trabalho aplicando esses compromissos. Os VCSs são mais complicados do que o Business Logic Processor porque eles devem suportar ramificações, enquanto o Business Logic Processor é uma seqüência simples. Então, em teoria, você sempre pode reconstruir o estado do Business Logic Processor reprocessando todos os eventos. Na prática, no entanto, isso levaria muito tempo se você precisasse girar um. Assim, assim como nos sistemas de controle de versão, o LMAX pode fazer instantâneos do status Business Logic Processor e restaurar a partir dos instantâneos. Eles tomam um instantâneo todas as noites durante períodos de baixa atividade. Reiniciar o processador de lógica de negócios é rápido, um reinício completo - incluindo reiniciar a JVM, carregar um instantâneo recente e reproduzir um dia de revistas - demora menos de um minuto. Os instantâneos tornam a criação de um novo processador de lógica de negócios mais rápido, mas não é suficientemente rápido se um processador de lógica de negócios falhar às 2pm. Como resultado, o LMAX mantém múltiplos processadores de lógica de negócios executando o tempo todo6. Cada evento de entrada é processado por vários processadores, mas todos, exceto um processador, têm sua saída ignorada. Se o processador ao vivo falhar, o sistema muda para outro. Essa habilidade para lidar com o failover é outro benefício de usar o Sourcing de eventos. Por causa do evento em réplicas, eles podem alternar entre os processadores em questão de micro-segundos. Além de tirar instantâneos todas as noites, eles também reinician os Processadores de lógica de negócios todas as noites. A replicação permite que eles façam isso sem tempo de inatividade, então eles continuam a processar negócios 247. Para obter mais informações sobre o Sourcing de Eventos, veja o padrão de rascunho no meu site há alguns anos atrás. O artigo está mais focado em lidar com relacionamentos temporais do que com os benefícios que o LMAX usa, mas explica a idéia central. A Sourcing de eventos é valiosa porque permite que o processador funcione inteiramente na memória, mas tem outra vantagem considerável para o diagnóstico. Se ocorrer algum comportamento inesperado, a equipe copia a seqüência de eventos para o ambiente de desenvolvimento e os reproduz. Isso permite que eles examinem o que aconteceu muito mais facilmente do que é possível na maioria dos ambientes. Esta capacidade de diagnóstico se estende ao diagnóstico de negócios. Existem algumas tarefas comerciais, como no gerenciamento de riscos, que requerem cálculos significativos que não são necessários para processar ordens. Um exemplo é obter uma lista dos 20 maiores clientes por perfil de risco com base em suas atuais posições de negociação. A equipe lida com isso girando um modelo de domínio replicado e executando a computação lá, onde não interferirá com o processamento da ordem do núcleo. Esses modelos de domínio de análise podem ter modelos de dados variantes, manter conjuntos de dados diferentes na memória e executar em máquinas diferentes. Ajuste do desempenho Até agora, eu expliquei que a chave da velocidade do Business Logic Processor está fazendo tudo de forma seqüencial, na memória. Apenas fazendo isso (e nada realmente estúpido) permite que os desenvolvedores escrevam código que pode processar 10K TPS7. Eles então descobriram que concentrar-se nos elementos simples de um bom código poderia trazer isso para a gama de 100K TPS. Isso só precisa de código bem-feito e de pequenos métodos - essencialmente isso permite que o Hotspot faça um melhor trabalho de otimização e que as CPUs sejam mais eficientes no armazenamento em cache do código como sendo executado. Demorou um pouco mais de astúcia para subir de outra ordem de grandeza. Há várias coisas que a equipe LMAX encontrou útil para chegar lá. Um deles era escrever implementações personalizadas das coleções java que foram projetadas para serem amigáveis com o cache e cuidadoso com o lixo8. Um exemplo disto é o uso de longas java primitivas como chaves hashmap com uma implementação de mapa com suporte de matriz especialmente escrita (LongToObjectHashMap). Em geral, eles descobriram que a escolha das estruturas de dados muitas vezes faz uma grande diferença, a maioria dos programadores apenas agarra qualquer lista usada pela última vez em vez de pensar em qual implementação é a certa para este contexto.9 Outra técnica para alcançar esse nível superior de desempenho é colocar Atenção no teste de desempenho. Percebi há muito tempo que as pessoas falam muito sobre técnicas para melhorar o desempenho, mas a única coisa que realmente faz a diferença é testá-lo. Mesmo os bons programadores são muito bons na construção de argumentos de desempenho que acabam sendo errados, então os melhores programadores preferem perfis e casos de teste para especulação.10 A equipe LMAX também descobriu que os testes de escrita em primeiro lugar são uma disciplina muito eficaz para testes de desempenho. Modelo de programação Este estilo de processamento apresenta alguns constrangimentos na forma como você escreve e organiza a lógica de negócios. O primeiro deles é que você deve provocar qualquer interação com serviços externos. Uma chamada de serviço externo será lenta, e com um único segmento irá interromper toda a máquina de processamento de pedidos. Como resultado, você não pode fazer chamadas para serviços externos dentro da lógica do negócio. Em vez disso, você precisa finalizar essa interação com um evento de saída e aguarde outro evento de entrada para recuperá-lo novamente. Eu uso um exemplo simples não-LMAX para ilustrar. Imagine que você está fazendo um pedido de geléia com cartão de crédito. Um sistema de varejo simples levaria as informações do seu pedido, usaria um serviço de validação de cartão de crédito para verificar seu número de cartão de crédito e depois confirmaria seu pedido - tudo dentro de uma única operação. O thread que processa seu pedido seria bloqueado enquanto esperava que o cartão de crédito fosse verificado, mas esse bloco não seria muito longo para o usuário, e o servidor sempre pode executar outro segmento no processador enquanto aguarda. Na arquitetura LMAX, você dividiria essa operação em duas. A primeira operação capturaria as informações da ordem e terminaria enviando um evento (validação do cartão de crédito solicitada) à empresa de cartão de crédito. O Business Logic Processor continuaria processando eventos para outros clientes até receber um evento validado por cartão de crédito em seu fluxo de eventos de entrada. Ao processar esse evento, realizaria as tarefas de confirmação para essa ordem. Trabalhar neste tipo de estilo assíncrono orientado por eventos, é algo incomum - embora o uso de assíncrono para melhorar a capacidade de resposta de uma aplicação seja uma técnica familiar. Ele também ajuda o processo de negócios a ser mais resiliente, pois você precisa ser mais explícito ao pensar sobre as diferentes coisas que podem acontecer com o aplicativo remoto. Uma segunda característica do modelo de programação reside no tratamento de erros. O modelo tradicional de sessões e transações de banco de dados fornece uma capacidade útil de gerenciamento de erros. Se alguma coisa der errado, é fácil descartar tudo o que aconteceu até agora na interação. Os dados da sessão são transitórios e podem ser descartados, com o custo de alguma irritação para o usuário, se no meio de algo complicado. Se ocorrer um erro no lado do banco de dados, você pode reverter a transação. As estruturas de memória interna de LMAX são persistentes em todos os eventos de entrada, portanto, se houver um erro, é importante não deixar essa memória em um estado inconsistente. No entanto, não há nenhuma instalação automática de reversão. Como conseqüência, o time LMAX dá muita atenção para garantir que os eventos de entrada sejam totalmente válidos antes de qualquer mutação do estado persistente na memória. Eles descobriram que o teste é uma ferramenta chave para liberar esses tipos de problemas antes de entrar em produção. Interruptores de entrada e saída Embora a lógica comercial ocorra em um único segmento, há uma série de tarefas a serem feitas antes que possamos invocar um método de objeto comercial. A entrada original para o processamento sai do fio na forma de uma mensagem, esta mensagem precisa ser desmarcada em uma forma conveniente para Business Logic Processor para usar. A Sourcing de Eventos depende de manter um diário durável de todos os eventos de entrada, então cada mensagem de entrada precisa ser registrada em uma loja durável. Finalmente, a arquitetura depende de um cluster de Business Logic Processors, por isso temos que replicar as mensagens de entrada nesse cluster. Da mesma forma, no lado da saída, os eventos de saída precisam ser empacotados para transmissão pela rede. Figura 2: As atividades realizadas pelo disruptor de entrada (usando a notação do diagrama de atividade UML) O replicador e o jornalista envolvem IO e, portanto, são relativamente lentos. Depois de toda a ideia central do Business Logic Processor, é que evita fazer qualquer IO. Também estas três tarefas são relativamente independentes, todas elas precisam ser feitas antes que o Processador de lógica comercial funcione em uma mensagem, mas pode ser feito em qualquer ordem. Então, ao contrário do Processador de lógica comercial, onde cada troca muda o mercado para negócios subsequentes, existe um ajuste natural para a concorrência. Para lidar com essa concorrência, a equipe LMAX desenvolveu um componente especial de concorrência, que eles chamam de Disruptor 11. A equipe LMAX lançou o código-fonte do Disruptor com uma licença de código aberto. Em um nível bruto, você pode pensar em um Disruptor como um gráfico multicast de filas em que os produtores colocam objetos que são enviados a todos os consumidores para consumo paralelo através de filas separadas. Quando você olha para dentro, você percebe que essa rede de filas é realmente uma única estrutura de dados - um buffer de anel. Cada produtor e consumidor tem um contador de seqüência para indicar qual slot no buffer está trabalhando atualmente. Cada consumidor de produtor escreve seu próprio contador de seqüência, mas pode ler os outros contadores de seqüência. Desta forma, o produtor pode ler os contadores dos consumidores para garantir que o slot que deseja escrever esteja disponível sem bloqueios nos contadores. Do mesmo modo, um consumidor pode garantir que ele apenas processa mensagens depois que outro consumidor é feito com ele assistindo os contadores. Figura 3: O disruptor de entrada coordena um produtor e quatro consumidores. Os interruptores de saída são semelhantes, mas eles só têm dois consumidores seqüenciais para empacotamento e saída.12 Os eventos de saída são organizados em vários tópicos, para que as mensagens possam ser enviadas para apenas os receptores interessados neles. Cada tópico tem seu próprio disruptor. Os disruptores que eu descrevi são usados em um estilo com um produtor e vários consumidores, mas isso não é uma limitação do design do disruptor. O disruptor também pode trabalhar com vários produtores, neste caso, ele ainda não precisa de bloqueios.13 Um benefício do design do disruptor é que facilita o acesso dos consumidores rapidamente se eles enfrentam um problema e ficam para trás. Se o unmarshaler tiver um problema ao processar no slot 15 e retornar quando o receptor estiver no slot 31, ele pode ler os dados dos slots 16-30 em um lote para recuperar o atraso. Este lote lido dos dados do disruptor facilita o atraso nos consumidores para recuperar o atraso, reduzindo assim a latência geral. Eu descrevi coisas aqui, com um cada um do jornalista, replicador e desmarcador - isso é, de fato, o que o LMAX faz. Mas o design permitiria que vários desses componentes fossem executados. Se você dirigisse dois jornalistas, então, um deles levaria os slots pares e o outro jornalista levaria os slots ímpares. Isso permite uma maior concorrência dessas operações de IO se isso for necessário. Os buffers do anel são grandes: 20 milhões de slots para buffer de entrada e 4 milhões de slots para cada um dos buffers de saída. Os contadores de seqüência são inteiros de 64 bits de comprimento que aumentam monotonicamente, mesmo que os slots de anel se encaixem.14 O buffer está configurado para um tamanho que é uma potência de dois para que o compilador possa fazer uma operação de módulo eficiente para mapear do número do contador de seqüência para o número do slot . Como o resto do sistema, os disruptores são rebocados durante a noite. Este salto é feito principalmente para limpar a memória de modo que haja menos chances de um cobrado processo de coleta de lixo durante a negociação. (Eu também acho que é um bom hábito reiniciar regularmente, para que você ensaia como fazê-lo para emergências.) O trabalho dos jornalistas é armazenar todos os eventos de forma durável, para que eles possam ser reproduzidos se qualquer coisa der errado. O LMAX não usa um banco de dados para isso, apenas o sistema de arquivos. Eles transmitem os eventos no disco. Em termos modernos, os discos mecânicos são horrivelmente lentos para o acesso aleatório, mas são muito rápidos para o streaming - daí o disco de linha de etiqueta é a nova fita.15 Anteriormente, mencionei que o LMAX executa várias cópias do seu sistema em um cluster para suportar o failover rápido . O replicador mantém esses nós sincronizados. Todas as comunicações no LMAX usam o multicast IP, portanto os clientes não precisam saber qual endereço IP é o nó mestre. Somente o nó mestre escuta diretamente os eventos de entrada e executa um replicador. O replicador transmite os eventos de entrada para os nós escravos. Se o nó mestre cair, a falta de batimentos cardíacos será notada, outro nó se tornará mestre, iniciará o processamento de eventos de entrada e iniciará o seu replicador. Cada nó tem seu próprio disruptor de entrada e, portanto, tem seu próprio diário e faz seu próprio desmarcamento. Mesmo com o multicast IP, a replicação ainda é necessária porque as mensagens IP podem chegar em uma ordem diferente em nós diferentes. O nó mestre fornece uma seqüência determinista para o resto do processamento. O unmarshaler transforma os dados do evento do fio em um objeto java que pode ser usado para invocar o comportamento no Business Logic Processor. Portanto, ao contrário dos outros consumidores, ele precisa modificar os dados no buffer do anel para que ele possa armazenar esse objeto não gerenciado. A regra aqui é que os consumidores podem escrever no buffer do anel, mas cada campo gravável só pode ter um consumidor paralelo que seja autorizado a gravá-lo. Isso preserva o princípio de ter apenas um único escritor. 16 Figura 4: A arquitetura LMAX com os disruptores expandidos O disruptor é um componente de propósito geral que pode ser usado fora do sistema LMAX. Normalmente, as empresas financeiras são muito seguras sobre seus sistemas, mantendo silêncio mesmo sobre itens que não são relevantes para seus negócios. Não só o LMAX foi aberto sobre sua arquitetura geral, eles têm código aberto do código do disruptor - um ato que me faz muito feliz. Não só isso permitirá que outras organizações façam uso do disruptor, mas também permitirá mais testes de suas propriedades de concorrência. Filas e sua falta de simpatia mecânica A arquitetura LMAX atraiu a atenção das pessoas porque é uma maneira muito diferente de se aproximar de um sistema de alto desempenho para o que a maioria das pessoas está pensando. Até agora, eu falei sobre o funcionamento, mas não esqueci muito sobre o porquê foi desenvolvido desta forma. Este conto é interessante em si mesmo, porque essa arquitetura não apareceu. Demorou um longo período de tentativa de alternativas mais convencionais, e percebendo onde estavam falhas, antes que a equipe se estabelecesse nessa. A maioria dos sistemas de negócios atualmente possui uma arquitetura central que depende de várias sessões ativas coordenadas através de um banco de dados transacional. A equipe LMAX estava familiarizada com essa abordagem e confiante de que não funcionaria para LMAX. Esta avaliação foi fundada nas experiências da Betfair - a empresa-mãe que criou o LMAX. Betfair é um site de apostas que permite que as pessoas apostem em eventos esportivos. Ele lida com volumes muito elevados de tráfego com muita disputa - as apostas esportivas tendem a irromper em eventos particulares. Para fazer isso funcionar, eles têm uma das instalações de banco de dados mais populares ao redor e tiveram que fazer muitos atos anormais para fazê-lo funcionar. Com base nessa experiência, eles sabiam o quão difícil era manter o desempenho de Betfairs e tinha certeza de que esse tipo de arquitetura não funcionaria pela baixa latência que um site de negociação exigiria. Como resultado, eles tiveram que encontrar uma abordagem diferente. Sua abordagem inicial era seguir o que tantos estão dizendo hoje em dia - que, para obter alto desempenho, você precisa usar uma concorrência explícita. Para esse cenário, isso significa que as ordens podem ser processadas por vários tópicos em paralelo. No entanto, como é frequentemente o caso com a concorrência, a dificuldade vem porque esses tópicos devem se comunicar entre si. O processamento de uma ordem altera as condições do mercado e essas condições precisam ser comunicadas. A abordagem que eles exploraram no início foi o modelo de ator e sua prima SEDA. O modelo de ator depende de objetos ativos e independentes com seu próprio fio que se comunicam entre si através de filas. Muitas pessoas acham esse tipo de modelo de concorrência mais fácil de tratar do que tentar fazer algo com base em primitivas de bloqueio. A equipe construiu uma troca de protótipo usando o modelo de ator e fez testes de desempenho nela. O que eles descobriram foi que os processadores passaram mais tempo gerenciando filas do que fazer a lógica real da aplicação. O acesso da fila foi um gargalo. Ao empurrar um desempenho como esse, ele começa a se tornar importante para ter em conta a forma como o hardware moderno é construído. A frase que Martin Thompson gosta de usar é a simpatia mecânica. O termo vem da condução de carro de corrida e reflete o motorista tendo uma sensação inata para o carro, então eles são capazes de sentir como tirar o melhor proveito disso. Muitos programadores, e eu confesso que eu caio neste campo, não tenho muita simpatia mecânica sobre como a programação interage com o hardware. O que é pior é que muitos programadores pensam ter simpatia mecânica, mas são construídos com base em noções de como o hardware usado para trabalhar, que agora estão fora de data de muitos anos. Um dos fatores dominantes com CPUs modernas que afetam a latência, é como a CPU interage com a memória. Hoje em dia, a memória principal é uma operação muito lenta em termos de CPU. As CPUs têm vários níveis de cache, cada um dos quais é significativamente mais rápido. Então, para aumentar a velocidade, você deseja obter seu código e dados nesses caches. Em um nível, o modelo do ator ajuda aqui. Você pode pensar em um ator como seu próprio objeto que agrupa código e dados, que é uma unidade natural para armazenamento em cache. Mas os atores precisam se comunicar, o que eles fazem através de filas - e a equipe LMAX observou que são as filas que interferem no armazenamento em cache. A explicação funciona assim: para colocar alguns dados em uma fila, você precisa escrever nessa fila. Da mesma forma, para tirar dados da fila, você precisa gravar na fila para executar a remoção. Esta é uma disputa de gravação - mais de um cliente pode precisar escrever na mesma estrutura de dados. Para lidar com a contenção de gravação, uma fila geralmente usa bloqueios. Mas se um bloqueio for usado, isso pode causar uma mudança de contexto para o kernel. Quando isso acontece, o processador envolvido provavelmente perderá os dados em seus caches. A conclusão a que eles chegaram foi que para obter o melhor comportamento de cache, você precisa de um design que tenha apenas um núcleo de escrita para qualquer local de memória17. Vários leitores estão bem, os processadores costumam usar links especiais de alta velocidade entre seus caches. Mas as filas falham no princípio do único escritor. Esta análise levou a equipe do LMAX a algumas conclusões. Em primeiro lugar, levou ao design do disruptor, que seguiu de forma determinante a restrição de um único escritor. Em segundo lugar, levou à ideia de explorar a abordagem lógica lógica de um único segmento, perguntando sobre a rapidez com que um único tópico pode ser executado se estiver liberado do gerenciamento de simultaneidade. A essência do trabalho em um único tópico é garantir que você tenha um segmento executado em um núcleo, o armazenamento em cache e o acesso da memória tanto quanto possível para os caches e não para a memória principal. Isso significa que tanto o código como o conjunto de dados de trabalho precisam ser acessados de forma consistente quanto possível. Também manter pequenos objetos com código e dados juntos permite que eles sejam trocados entre os caches como uma unidade, simplificando o gerenciamento de cache e melhorando novamente o desempenho. Uma parte essencial do caminho para a arquitetura LMAX foi o uso de testes de desempenho. A consideração e o abandono de uma abordagem baseada em ator veio da construção e teste de desempenho de um protótipo. Da mesma forma, muitas das etapas de melhoria do desempenho dos vários componentes foram habilitadas por testes de desempenho. A simpatia mecânica é muito valiosa - ajuda a formular hipóteses sobre as melhorias que você pode fazer e orienta você a encaminhar etapas, em vez de atrasadas -, mas no final é que o teste fornece as provas convincentes. O teste de desempenho neste estilo, no entanto, não é um tópico bem compreendido. Regularmente, a equipe LMAX enfatiza que, com testes de desempenho significativos, muitas vezes é mais difícil desenvolver o código de produção. Outra vez, a simpatia mecânica é importante para desenvolver os testes corretos. Testar um componente de concorrência de baixo nível não tem sentido a menos que você tenha em conta o comportamento de cache da CPU. Uma lição específica é a importância de escrever testes contra componentes nulos para garantir que o teste de desempenho seja rápido o suficiente para realmente medir o que os componentes reais estão fazendo. Escrever um código de teste rápido não é mais fácil do que escrever código de produção rápido e é muito fácil obter resultados falsos porque o teste não é tão rápido quanto o componente está tentando medir. Você deve usar essa arquitetura. À primeira vista, essa arquitetura parece ser um nicho muito pequeno. Depois de todo o driver que levou a isso foi poder executar muitas transações complexas com latência muito baixa - a maioria dos aplicativos não precisa executar em 6 milhões de TPS. Mas o que me fascina sobre esta aplicação, é que eles acabaram com um design que remove grande parte da complexidade de programação que aflige muitos projetos de software. O modelo tradicional de sessões concorrentes em torno de um banco de dados transacional não está livre de aborrecimentos. Há geralmente um esforço não-trivial que entra no relacionamento com o banco de dados. As ferramentas de mapeamento de objetos podem ajudar muitas das dificuldades em lidar com um banco de dados, mas não lida com tudo isso. A maior parte do ajuste de desempenho das aplicações empresariais envolve o futuro com o SQL. Hoje em dia, você pode obter mais memória principal em seus servidores do que nós, velhos, poderiam obter como espaço em disco. Mais e mais aplicações são bastante capazes de colocar todo o seu conjunto de trabalho na memória principal - eliminando assim uma fonte de complexidade e lentidão. O Sourcing de Eventos fornece uma maneira de resolver o problema de durabilidade de um sistema na memória, executando tudo em um único segmento resolve o problema de concorrência. A experiência LMAX sugere que, enquanto você precisar de menos de alguns milhões de TPS, você terá espaço suficiente para o desempenho. Há uma sobreposição considerável aqui com o crescente interesse no CQRS. Um processador de origem do evento, na memória, é uma escolha natural para o lado do comando de um sistema CQRS. (Embora a equipe LMAX atualmente não use o CQRS). Então, o que indica que você não deve seguir esse caminho. Isso é sempre uma questão complicada para técnicas pouco conhecidas como essa, já que a profissão precisa de mais tempo para explorar seus limites. Um ponto de partida, no entanto, é pensar nas características que incentivam a arquitetura. Uma característica é que este é um domínio conectado onde o processamento de uma transação sempre tem o potencial de alterar a forma como as seguintes são processadas. Com transações que são mais independentes umas das outras, há menos necessidade de coordenar, portanto, usar processadores separados que funcionam em paralelo torna-se mais atraente. O LMAX concentra-se em descobrir as conseqüências de como os eventos mudam o mundo. Muitos sites são mais sobre como levar uma loja existente de informações e renderizar várias combinações dessa informação para o maior número de globos oculares que possam encontrar - por exemplo, pensar em qualquer site de mídia. Aqui, o desafio arquitetônico geralmente se concentra em obter seus caches corretos. Outra característica do LMAX é que este é um sistema de backend, por isso é razoável considerar o quão aplicável seria para algo que atue em um modo interativo. Cada vez mais, a aplicação web está nos ajudando a nos acostumar com os sistemas de servidores que reagem aos pedidos, um aspecto que se encaixa bem com essa arquitetura. Onde essa arquitetura vai além da maioria desses sistemas é o uso absoluto de comunicações assíncronas, resultando em mudanças no modelo de programação que descrevi anteriormente. Essas mudanças levam algum tempo a se acostumar com a maioria das equipes. A maioria das pessoas tende a pensar em programação em termos síncronos e não está acostumada a lidar com a assincronia. No entanto, há muito foi verdade que a comunicação assíncrona é uma ferramenta essencial para a capacidade de resposta. Será interessante ver se o uso mais amplo da comunicação assíncrona no mundo javascript, com AJAX e node. js, incentivará mais pessoas a investigar esse estilo. A equipe LMAX descobriu que, embora demorasse um pouco a se adaptar ao estilo assíncrono, logo se tornou natural e, muitas vezes, mais fácil. Em particular, o tratamento de erros foi muito mais fácil de lidar com essa abordagem. A equipe LMAX certamente sente que os dias do banco de dados transacional de coordenação estão numerados. O fato de você poder escrever software com mais facilidade usando este tipo de arquitetura e que ele corre mais rapidamente remove grande parte da justificativa para o banco de dados central tradicional. Por minha parte, acho isso uma história muito emocionante. Grande parte do meu objetivo é concentrar-se em softwares que modelam domínios complexos. Uma arquitetura como essa proporciona uma boa separação de preocupações, permitindo que as pessoas se concentrem no Design Dominado pelo Domínio e mantenham a complexidade da plataforma muito bem separada. O acoplamento íntimo entre objetos de domínio e bancos de dados sempre foi uma irritação - abordagens como esta sugerem uma saída. Se você achou este artigo útil, compartilhe-o. Agradeço o feedback e o incentivo. Na verdade, existem apenas 3 blocos principais em um sistema de comércio Algo. 1. Manipulador de dados de mercado (por exemplo, manipulador FAST) 2. Módulo de estratégia (por exemplo, estratégia crossOver) 3. Ordem roteador (por exemplo, roteador FIX) você pode adicionar verificações de risco no módulo de estratégia ou no módulo de roteador de pedidos ou ambos. Por enquanto, seu fluxo de dados está correto, você deve estar pronto para ir. Lembre-se de que você está projetando um ATS para uma latência mínima, e adicionar mais camadas ou complexidade virão ao custo da latência. Arquitetura mínima de ATS E se você adicionar os sinos e os assobios, pareceria o seguinte: se você também está interessado no meio da implementação da arquitetura acima, você deve manter as seguintes coisas em mente. Evite locksmutexes. No caso de você ter que usá-lo, tente substituí-los por estruturas sem trava usando atomics. There are couple of libraries available for lockless data structures ( e. g. libcds, concurrency kit etc). C-11 supports std::atomic. and you should strive to use them as well. Avoid whats done in QuickFIX. Its written for safetyflexibilityreusability as object (lock) creation and destruction is done for each invocation of any message to router. Surely no way to write a latency sensitive code. No runtime memory allocation. runtime pathway should use customized and lock-free memory management with pre-allocated memory pool. All the initialization can be done in constructors. Tight coupling. Threading model, IO model and memory management should be designed to collaborate with each other to achieve best overall performance. This goes against the OOP concept of loose coupling, but its necessary to avoid runtime cost of dynamic polymorphism. Use Templates. In the same vein, I would also suggest you look at C templatization to achieve flexibility of code. OSHardware optimization: Finally, you should look to work with Linux RT Kernel and Solarflare network card with OpenOnLoad driver for achieving minimum latency. you can further look to isolate the cpu and run your program on that particular core. And finally the public API which you would need to expose to strategy developers. I would like this to be the minimal set which would encapsulate all the complexity of that particular exchangedestination. class OrderRouter public: virtual bool sendNewOrd(OrderInfo) 0 virtual bool sendRplOrd(OrderInfo) 0 virtual bool sendCxlOrd(OrderInfo) 0 virtualBut this means that the OrderInfo Class needs to have ALL the details required by the destinationexchange. In general, the exchanges requires the same kind of information, but as you go along and support more exchangesdestinations you would find yourself adding more variables in this class. The following are the important questionschallenges you would need to ask yourself : 1. Multi-process architecture or Multi-Threaded architecture . whether to build one monolithic process with multiple threads, or write several processes. The cost of multiple process is message passing latency, while the cost for multiple threaded single process is that any failure may bring down the whole system. 2. Message passing : while you can choose from plethora of options, you are restricted by latency consideration. Fastest IPC would be shared memory, but then how would you do the synchronization spend some time with these two questions because they would be the building block on which your architecture stands. Edit: FIX and FAST Regarding popularstandard protocol, FIX is for sending orders and FAST is for market data. Having said that, most exchanges have their own native protocol which is faster than FIX, because FIX is generally implemented on top of their native protocol. But they still support FIX adds to speed of deployment. On the other hand, while FIX is adopted by most of exchanges, FAST does not enjoy such wide acceptance. If anything, there would be only a handful of exchange adopting it. Most of them either send over FIX itself ( low latency ), or use their own native binary protocol. por exemplo. In India, NSE, BSE and MCXMCXSX, all the three exchanges gives you FIX protocol in addition to native protocol, but only BSE gives you FAST for market data. And that is also moving from FAST to native with introduction of EOBI. you can extrapolate the same thing to other exchanges. 3.7k Views middot View Upvotes middot Not for Reproduction As John mentioned, OMS is the crux of any trading platform and you should start from researching about it. You would have to spend time to determine your trade lifecycle, events and features you want to embed on the OMS and the ones you want your Algo Engine to handle. Metcetera offers an open source OMS, I haven039t used it personally but it039s one of the few in the market. The next thing you should look at is providing an interface to source data in and push it out. This is for a client order entry system to throw in the order details and Algo engine to source it. A lot of Sell Side OMS039s use a combination of proprietary programs written in JavaC using FIX. FIX protocol allows you to communicate realtime across systems in a simplified amp pre-defined message format laid down by the FIX protocol community. Go to The FIX Protocol Organization gt Home page to read more about it. Also looks at Open Source FIX Engine. an open source implementation of the FIX engine. Next comes a Market Data interface to source realtime time security market information, data ranging from HighLowOpenClose to Best BidBest Ask, Total traded volume, Last price, Last volume, Bid quotes, Ask quotes etc. The information you seek really depends upon the type of strategy you wish to implement. I believe Interactive Broker provides a realtime data feed via FIX. Exchange connectivity is next where your Algo interprets the signals, create an order and routes to an Exchange or ECN. Developing it in-house could be tough as you would need to work out Exchange membership, certify your platform and pay a regular membership fee. A cheaper way is to use a broker API (like IB) and route the order through them. Historical data is of essence too as you might want to compare the current market behavior with its historical values. Parameters like average spread, VWAP profiles, average daily volume etc may be required to influence decision making. You can have it on database (preferred) but if speed of the essence then download it on the server cache when you begin your program. Once your peripheral systems are setup, you can start developing your algo program the way you want it to work. This basic infrastructure would allow you to input a parent algo order, read market data, react to the signals but generating child orders and placing it on the exchange order book and historical data to influence decision making. The OMS holds the linkage between the parent amp child order, their realtime statuses and updates by the algo or exchange connectivity platform. What you want to implement inside the Algo is completely up to you. 2.1k Vistas middot View Upvotes middot Não para reprodução
No comments:
Post a Comment