Principais conclusões

  • O Ledger da Binance armazena saldos de contas e transações, ao mesmo tempo que permite que serviços façam transações.

  • Ele cria as condições necessárias para alto rendimento, disponibilidade 24 horas por dia, 7 dias por semana e precisão de dados em nível de bit.

O papel da Binance Ledger nos bastidores a torna uma das tecnologias mais importantes da Binance. Aprenda exatamente como funciona e os problemas que está resolvendo na operação da maior exchange de criptomoedas do mundo aqui.

Já se perguntou exatamente o que faz o Binance funcionar? Com a necessidade de processar milhões de transações diariamente em uma enorme base de usuários, vale a pena dar uma olhada no que a Binance tem nos bastidores.

A base das operações técnicas da Binance é o seu Ledger. O Ledger armazena saldos e transações de contas enquanto permite que os serviços façam transações.

Binance tem altos requisitos para o razão

Como você pode imaginar, os requisitos do Ledger são altos para atender à enorme demanda dos usuários. Existem três pontos principais que precisam ser considerados:

  • Alto rendimento com capacidade para uma grande quantidade de TPS (transações por segundo) em horários de pico.

  • Disponibilidade 24 horas por dia, 7 dias por semana, sem tempo de inatividade.

  • Precisão dos dados em nível de bit, sem perda de fundos ou erros de transação.

Vejamos um exemplo de entrada básica no Ledger. Aqui está uma transação comum em que a conta 1 transfere 1 BTC para a conta 2.

Saldo antes da transação:

CONTA_ID

ATIVO

EQUILÍBRIO

1

Bitcoin

10

2

Bitcoin

0,1

tabela 1

Saldo após a transação:

CONTA_ID

ATIVO

EQUILÍBRIO

1

Bitcoin

9

2

Bitcoin

1.1

mesa 2

Nesta transação, existem dois comandos:

  1. Conta 1    -1 BTC

  2. Conta 2 +1 BTC

Quando a transação for realizada, dois registros de saldo serão armazenados para auditoria e reconciliação.

CONTA_ID

ATIVO

DELTA

TX_ID

TEMPO

100001

Bitcoin

-1

tx-001

01/01/2022  01:02:03

100002

Bitcoin

+1

tx-001

01/01/2022  01:02:03

Tabela 3

A solução padrão da indústria

Uma solução Ledger padrão do setor é baseada em um banco de dados relacional. Voltando ao exemplo anterior, os dois comandos da transação podem ser traduzidos em duas instruções SQL e executados em uma transação de banco de dados (tabela 4).

iniciar a transação;

ATUALIZAR saldo_1 definir saldo = saldo - 1

WHERE account_id=1 e ativo = ‘BTC’ e saldo - 1 >= 0;

Se 0 linha for afetada, então reverta;

ATUALIZAR saldo_2 definir saldo = saldo + 1

WHERE account_id=2 e ativo = ‘BTC’ e saldo + 1 >= 0;

Se 0 linha for afetada, então reverta;

comprometer-se;

tabela-4

As vantagens da solução

  1. É bastante simples de implementar.

  2. É fácil aplicar técnicas comuns de ajuste de banco de dados, como divisão e fragmentação de leitura/gravação, para melhorar o desempenho.

  3. Não é difícil para os devops se recuperarem do failover, bem como monitorar e manter um banco de dados comercial.

As desvantagens da solução

  1. O TPS cairá drasticamente quando houver condições de corrida devido a bloqueios de linha.

  2. É difícil dimensionar horizontalmente para melhorar o desempenho.

O problema da conta quente

Infelizmente para a Binance, a solução industrial demonstrada acima não atende aos seus elevados requisitos. Quando ocorre uma transação, ela deve conter os bloqueios de linha de cada linha envolvida. Embora algumas contas tenham relativamente poucas transações para lidar, há, é claro, contas ocupadas com muitas transações simultâneas. Neste caso, apenas uma transação é capaz de manter o bloqueio de linha da conta.

As outras transações não poderão fazer nada além de esperar que o bloqueio seja liberado. Chamamos essa situação de problema de conta quente e testes internos mostram que o TPS cairá pelo menos 10 vezes nessa situação. Você pode ver esse problema na tabela 5 abaixo.

Exemplo de conta quente:

Tx 1 (transferir 1 BTC da conta 1 para a conta 2)

Tx 2 (transferir 2 BTC da conta 1 para a conta 3)

iniciar a transação;

iniciar a transação;

ATUALIZAR saldo definido saldo = saldo - 1

WHERE account_id=1 e ativo = ‘BTC’ e saldo - 1 >= 0;

(linha bloqueada: account_id=1 e ativo = ‘BTC’)

Se 0 linha for afetada, então reverta;

ATUALIZAR saldo definido saldo = saldo - 2

ONDE account_id=1 e ativo = ‘BTC’

e equilíbrio - 2 >= 0;

Se 0 linha for afetada, então reverta;

ATUALIZAR saldo definido saldo = saldo + 1

WHERE account_id=2 e ativo = ‘BTC’ e saldo + 1 >= 0;

Se 0 linha for afetada, então reverta;

esperar bloqueio

comprometer-se;

esperar bloqueio

obter bloqueio, executar

ATUALIZAR saldo definido saldo = saldo + 2

WHERE account_id=3 e ativo = ‘BTC’ e saldo + 1 >= 0;

Se 0 linha for afetada, então reverta;

comprometer-se;

tabela-5

Solução de contabilidade da Binance

Como resolvemos o problema da conta quente?

Uma solução possível para o nosso problema é converter de forma inovadora o modelo multithread para um modo single-thread. Isso evita o problema de condição de corrida e, como resultado, não haverá um problema de conta quente.

Novo modelo de thread

Comunicação baseada em mensagens

Após implementar nosso novo modelo de thread, um problema de comunicação precisa ser resolvido. A camada da máquina de estado é de thread único, mas a camada de rede é multithread, então como podemos nos comunicar de forma eficiente entre os dois?

Um Disruptor [1] é o próximo passo do quebra-cabeça. Ele cria uma fila de alto desempenho e sem bloqueios com base em um design de buffer em anel.

Alta disponibilidade

Até agora, alcançamos alto desempenho usando um modelo em memória e armazenamento local RocksDB [2]. Mas, mais uma vez, surge um novo desafio. Agora precisamos cuidar da alta disponibilidade de dados.

Para garantir a consistência dos dados entre os nós, usamos um Algoritmo de Consenso Raft [3]. Isto significa que o número de backups de dados é igual ao número de nós não líderes presentes. O algoritmo também garante que o sistema ainda funcionará com pelo menos metade dos nós saudáveis, para ajudar a fornecer alta disponibilidade de serviço.

Funções do domínio Raft:

  • Líder. O Líder processa todas as solicitações do cliente e replica a operação para todos os seguidores.

  • Seguidor. Os seguidores seguem o líder em todas as operações. Se o líder falhar, um dos seguidores será eleito o novo líder.

  • Aprendiz. Os alunos são seguidores sem direito a voto que enviam cada registro de alteração idempotente/transação para outros serviços.

Funções de domínio Raft

CQRS (segregação de responsabilidade de consulta de comando)

Outro critério importante que queremos garantir é o maior desempenho de gravação do Ledger e a capacidade para condições de consulta mais diversas. Para isso, precisamos criar domínios diferentes. O domínio raft fornece escrita mais eficiente baseada em rocksdb+raft, e o domínio view escuta as mensagens do domínio raft e as salva no banco de dados relacional para consultas externas. Também podemos implementar a segregação de responsabilidade de consulta de comando no nível arquitetônico.

Arquitetura de razão

Arquitetura geral

Termos entre Raft e Ledger:

Jangada

Razão

máquinas de estado replicadas

nós contábeis

estado

equilíbrio

comando

transação

tabela-6

Ver funções de domínio

  • Centro de registro de jangada

Consumir a mensagem produzida pelo aluno e armazenar os dados de transação e saldo no MySQL para fins de consulta.

Processamento de solicitação

Uma solicitação de transação passará primeiro pela camada de rede, pela camada de razão (manipulador de solicitação) e pela camada de raft (sincronização de log de raft). Em seguida, ele retornará à camada contábil (máquina de estado), à camada de rede (manipulador de resposta) e, finalmente, retornará uma resposta ao cliente.

Os dados são passados ​​​​pela fila entre as duas camadas.

  1. Camada de Rede – Desserialize a solicitação RPC e coloque-a na fila de solicitações.

  2. Camada Ledger – Obtenha a solicitação da fila e prepare o contexto. Em seguida, ele colocará os metadados da solicitação na fila raft.

  3. Camada Raft – Obtenha os metadados da solicitação da fila raft e sincronize-os entre todos os seguidores. Em seguida, ele colocará o resultado na fila de aplicação.

  4. Camada Ledger – Obtenha os dados da fila de aplicação e atualize a máquina de estado. Em seguida, ele colocará o resultado na fila de resposta.

  5. Camada de rede – Obtenha o resultado da fila de resposta e construa e serialize os dados de resposta antes de devolvê-los ao cliente.

Processamento de solicitação

Recuperação de dados

Cada nó do Ledger acionará um instantâneo genérico com base em um período de tempo. Além disso, também implementamos um instantâneo consistente. Cada nó é acionado no mesmo índice de log de raft para garantir que a máquina de estado seja exatamente a mesma quando cada nó aciona um instantâneo. O instantâneo será então carregado no S3 para verificação pelo Checker e como backup frio.

Quando o Ledger é reiniciado, ele lê o instantâneo local e reconstrói a máquina de estado. Em seguida, ele reproduz o log da balsa local e sincroniza o log mais recente do líder até alcançar o índice mais recente. Se o instantâneo local ou o log da balsa não existir, ele será obtido do líder.

Instantâneo e recuperação

Tolerância a desastres

Para melhorar a disponibilidade e a tolerância a falhas, os nós do Ledger são implantados em zonas diferentes. Contanto que mais da metade dos nós estejam íntegros, os dados não serão perdidos e o failover será concluído em um segundo.

Mesmo que todo o cluster falhe, o que tem uma probabilidade muito baixa, ainda podemos restaurar o cluster por meio do snapshot consistente armazenado no Amazon S3 e recuperar os dados perdidos mais recentes por meio do sistema downstream.

Tolerância ao erro

Desempenho

A tabela a seguir mostra as especificações de hardware para o teste de desempenho

Componente

Tipo de instância

Largura de banda da rede (Gbps)

Largura de banda EBS (Gbps)

Tipo de armazenamento EBS

Líder/Seguidor

M6i.4xgrande

16c64g

Até 12,5

Até 10

2T GP3 * 3 IOPS6000 625 MB/s

Aluno

M6i.4xgrande

16c64g

Até 12,5

Até 10

2T GP3 * 3 IOPS6000 625 MB/s

Banco

C5.4xgrande

16c32g

Até 10

4.750

Apenas volume raiz

Testes internos comprovam que um cluster de 4 nós (um líder, dois seguidores e um aluno) pode processar mais de 10.000 TPS. Por design, o cluster processa todas as transações, uma por uma. Não há nenhuma condição de bloqueio e corrida. Portanto, no cenário de conta quente, o TPS é tão alto quanto nos cenários normais.

Conta quente TPS

A figura a seguir mostra a latência de cada transação. A maioria das transações pode ser concluída em 10 ms. As transações mais lentas podem ser concluídas em 25 ms.

Latência ms

Potenciando nossos serviços com Binance Ledger

Como você viu, a resposta da indústria tradicional ao problema das contas quentes não satisfaz as necessidades da Binance e de seus clientes. Ao usar uma abordagem projetada especificamente para a infraestrutura da Binance, obtivemos uma das trocas e experiências de produto mais tranquilas disponíveis. Estamos felizes em compartilhar com você nossa experiência e esperamos que você entenda melhor o que é necessário para fazer um serviço como o Binance funcionar.

Leia o seguinte artigo para mais informações sobre nossa infraestrutura tecnológica:

  • (Blog da Binance) Usando MLOps para construir um pipeline de aprendizado de máquina ponta a ponta em tempo real

  • (Binance Blog) Conheça o CTO: Rohit reflete sobre criptografia, blockchain, Web3 e seu primeiro mês na Binance

Referências

[1] Disruptor LMAX

[2] RocksDB

[3] O Algoritmo de Consenso da Jangada