View
9
Download
0
Category
Preview:
Citation preview
Gustavo BicalhoMaurício Verardo
Construindo a NuConta
Agenda
● NuConta● Microsserviços no Nubank● Transferindo dinheiro entre NuContas
○ Event-sourcing: Modularidade e Escalabilidade○ Consistência em sistemas distribuídos
● O feed de movimentações○ Backend for Frontends com GraphQL
NuConta
NuConta
NuConta
NuConta
NuConta
NuConta
NuConta
NuConta
https://nubank.design/
Microsserviços
Microsserviços
Fatura
Saldo
AntecipaçãoAntecipações
Saldos
Faturas
Saldos
Antecipações
Faturas
Microsserviços
Fatura
Saldo
Antecipação
Load
Balancer
Load
Balancer
Load
Balancer
Microsserviços
Serviço A Serviço BHTTP
Microsserviços
Serviço A
Tópico do Kafka
Serviço B
Transferindo dinheiro entre NuContas
SOUTHEAST BRAZIL REGION FROM SPACE
Transferindo dinheiro entre NuContas
Pedido de envio
Envio
Recebimentos
Recebimento
Envios
Liquidação
Saldos
Depósito
Transferindo dinheiro entre NuContas
Pedido de envio
RecebimentosEnvios
Saldos
Pedido
Envio Solicitado
Transferindo dinheiro entre NuContas
Pedido de envio
RecebimentosEnvios
Saldos
Pedido
Envio Solicitado
Liquidação
Liquidação efetuada
Transferindo dinheiro entre NuContas
Pedido de envio
RecebimentosEnvios
Saldos
Pedido
Envio Solicitado
Liquidação
Envio
Liquidação efetuada
Dinheiro enviado para NuConta
Transferindo dinheiro entre NuContas
Pedido de envio
RecebimentosEnvios
Saldos
Pedido
Envio Solicitado
Liquidação
Envio
Liquidação efetuada
Dinheiro enviado para NuConta
Recebimento
Dinheiro Recebido
Transferindo dinheiro entre NuContas
Pedido de envio
RecebimentosEnvios
Saldos
Pedido
Envio Solicitado
Liquidação
Envio
Liquidação efetuada
Dinheiro enviado para NuConta
Recebimento
Dinheiro Recebido
Depósito
Características interessantes desse fluxo
Pedido de envio
RecebimentosEnvios
Saldos
Pedido
Envio Solicitado
Liquidação
Envio
Liquidação efetuada
Dinheiro enviado para NuConta
Recebimento
Dinheiro Recebido
Depósito
Event Sourcing
Pedido de envio
RecebimentosEnvios
Saldos
Pedido
Envio Solicitado
Liquidação
Envio
Liquidação efetuada
Dinheiro enviado para NuConta
Recebimento
Dinheiro Recebido
Depósito
E se o cliente quiser enviar transferências para outra instituição financeira?
Pedido de envio
Envios
Saldos
Pedido
Envio Solicitado
Liquidação
Envio
Liquidação efetuada
Depósito
E se o cliente quiser enviar transferências para outra instituição financeira?
Dinheiro enviado para outra instituição
Integração com o banco central
Pedido de envio
RecebimentosEnvios
Saldos
Pedido
Envio Solicitado
Liquidação
Envio
Liquidação efetuada
Dinheiro enviado para NuConta
Recebimento
Dinheiro Recebido
Depósito
E se o cliente receber transferências de outra instituição financeira?
Recebimentos
Saldos
Liquidação
Recebimento
Dinheiro Recebido
Depósito
E se o cliente receber transferências de outra instituição financeira?
Dinheiro recebido do Banco Central
Integração com o Banco Central
Pedido de envio
RecebimentosEnvios
Saldos
Pedido
Envio Solicitado
Liquidação
Envio
Liquidação efetuada
Dinheiro enviado para NuConta
Recebimento
Dinheiro Recebido
Depósito
E se o cliente quiser pagar a fatura do cartão de crédito?
Pedido de Pagamento
Pagamento de Fatura
Saldos
Pedido
Pagamento Solicitado
Liquidação
Pagamento
Liquidação efetuada
Pagamento de fatura
Depósito
E se o cliente quiser pagar a fatura do cartão de crédito?
Cartão de crédito
Saldos
Liquidação
Depósito
Event Sourcing
Saldo hoje
Saldo no ano que vem
Saldo no mês passado
Pedido de envio
RecebimentosEnvios
Saldos
Pedido
Envio Solicitado
Liquidação
Envio
Liquidação efetuada
Dinheiro enviado para NuConta
Recebimento
Dinheiro Recebido
Depósito
Event Sourcing
Consistência em sistemas distribuídos
O que pode dar errado?
Pedido de envio
Envios
Liquidação
Saldos
Envio Solicitado
Envio
Liquidação para envio
Recebimentos
Recebimento
Dinheiro enviado para NuConta
Dinheiro Recebido
Depósito
Pedido
O que pode dar errado?
Pedido de envio
Envios
Saldos
Envio Solicitado
Envio
Liquidação para envio
Recebimentos
Recebimento
Dinheiro enviado para NuConta
Dinheiro Recebido
DepósitoLiquidação
Pedido
Primeiro requisito: Processamento at-least-once
Todo evento publicado é recebido e processadocompletamente pelos consumidores pelo menos uma vez
Primeiro requisito: Processamento at-least-once
MSG
OK!
:)
MSG
MSG
MSG
Primeiro requisito: Processamento at-least-once
● Mensagens são persistidas e replicadas no Kafka cluster, podendo ser consumidas a qualquer momento
● Próxima mensagem da fila será entregue de novo até que consumidor confirme que completou seu processamento
● Consumidor só deve confirmar o processamento depois que completar todos os efeitos colaterais
Segundo requisito: Idempotência
● Uma operação é idempotente se aplicá-la várias vezes é equivalente a aplicá-la uma vez
● Exemplos:○ Multiplicação por 0: 7*0 = 7*0*0 = 7*0*0*0 … = 0○ DELETE FROM users WHERE users.id = 186
Segundo requisito: Idempotência
● Cada evento em nossa arquitetura tem um UUID aleatório● Cada evento derivado usa o UUID do evento anterior (origem) como chave
única (chave de idempotência)● Serviços garantem consistência interna: banco de dados local valida a chave
única● Resultado: Criar um evento a partir de outro é uma operação idempotente
LiquidacaoID: 78Origem: PedidoDeEnvio:32
PedidoDeEnvioID: 32
Segundo requisito: Idempotência
LiquidacaoID: 78Origem: PedidoDeEnvio:32
PedidoDeEnvioID: 32
EnvioID: 44Origem: Liquidacao:78
RecebimentoID: 156Origem: Envio:44
DepositoID: 377Origem: Recebimento:156
E quando um serviço cair?
Envios
Saldos
Pedido de envio
Envio Solicitado
Liquidação
Pedido
E quando um serviço cair?
Envios
Saldos
Pedido de envio
Liquidação
Envio Solicitado
Pedido
E se rolar um bug ou mensagem inválida?
Envio
SaldosDeadletters
xkcd.com (CC BY-NC 2.5)
Deadletters:Tópico onde guardamos mensagens cujo processamento falhou (inclui metadados como stack-traces, timestamp, etc)
Pedido de envio
Liquidação
Envio Solicitado
Pedido
E se rolar um bug ou mensagem inválida?
Envio
SaldosDeadletters
xkcd.com (CC BY-NC 2.5)
Republicar
/dev/null
Descartar
Deadletters:Tópico onde guardamos mensagens cujo processamento falhou (inclui metadados como stack-traces, timestamp, etc)
Pedido de envio
Liquidação
Envio Solicitado
Pedido
Feed de movimentações
Dados distribuídos = muitos requests
EnviosPedido de envioEnvio
Recebimentos Recebimento
SaldosDepósitoLiquidação
Evento de envio no feed● Valor● Data● Status: pendente | falha | sucesso
Modelo do backend != visão do cliente
Liquidação Envio
404 | 404
404
EnviosPedido de envioEnvio
SaldosLiquidação
● Lançar uma nova versão de um aplicativo numa app store pode demorar dias
● Muitos usuários continuam com versões antigas por muito tempo
● Bugfixes e otimizações demoram para chegar
● Frontend acoplado impede evoluções no backend
Ciclos de atualização lentos
Backend For Frontend
BFF
EnviosPedido de envioEnvio
Recebimentos Recebimento
SaldosDepósitoLiquidação
"GraphQL is a query language designed to build client applications by providing an intuitive and flexible syntax and system for describing their data requirements and
interactions."
(GraphQL spec: http://facebook.github.io/graphql/)
Schema é o modelo disponível para o frontend
schema { query: Query}
type Query { saldo(accountId: ID!): Float feed(accountId: ID!): [Envio | Recebimento]}
type Recebimento { data: Date valor: Float}
enum StatusEnvio { PENDENTE, FALHA, SUCESSO}
type Envio { data: Date valor: Float status: StatusEnvio}
EnviosPedido de envioEnvio
Recebimentos Recebimento
SaldosDepósitoLiquidação
Query define os campos que o client precisa
schema { query: Query}
type Query { saldo(accountId: ID!): Float feed(accountId: ID!): [Envio | Recebimento]}
type Recebimento { data: Date valor: Float}
enum StatusEnvio { PENDENTE, FALHA, SUCESSO}
type Envio { data: Date valor: Float status: StatusEnvio}
query feedScreen($accountId: ID!) {
feed(accountId: $accountId) {
... on Envio { data valor status }
... on Recebimento { data valor }
}
}
POST /api/query
Query define os campos que o client precisa
schema { query: Query}
type Query { saldo(accountId: ID!): Float feed(accountId: ID!): [Envio | Recebimento] saldoDetalhado(accountId: ID!): SaldoDetalhado}
query($accountId: ID!) { feed(accountId: $accountId) { … } saldoDetalhado(accountId: $accountId) { … }}
Client v2
query($accountId: ID!) { feed(accountId: $accountId) { … } saldo(accountId: $accountId)}
Client v1
Recapitulando
● Event-sourcing
● Comunicação assíncrona via Kafka
● Backend for Frontend com GraphQL
Gustavo BicalhoMaurício Verardo
Obrigado!
https://sou.nu/vagasnu
Recommended