Saltar para o conteúdo
Transferir
Todos os artigos
Guias

Como melhorámos o desempenho da Moove em 59%

Os utilizadores da Moove estão longe dos nossos servidores. Como reduzimos em 59% o tempo até à primeira resposta sem mudar um servidor e o que foi mais difícil.
6/11/20269 min de leitura

A distância era a nossa dependência mais lenta

A maioria das pessoas que abrem a Moove app está em redes móveis na Nigéria e na Indonésia, a milhares de quilómetros dos servidores que lhes respondem. Este mês mudámos a forma como os pedidos delas chegam até nós, e o nosso tempo até ao primeiro byte (TTFB), o tempo que decorre entre um telemóvel enviar um pedido e chegar a primeira parte da resposta, desceu 59%, de 0,74 segundos para 0,31 segundos. Para isso, não mudámos um único servidor de lugar.

Este artigo explica porque é que a distância nos custou mais do que esperávamos, o que mudámos, a parte que acabou por ser mais difícil do que a própria mudança e o que diríamos a outra equipa que esteja prestes a fazer o mesmo.

Porque é que uma viagem longa se transforma em três

Os engenheiros chamam latência ao atraso entre enviar algo e esse algo chegar, e tempo de ida e volta (RTT) ao tempo que uma mensagem demora a chegar a um servidor e a resposta a regressar. De Lagos aos nossos servidores, o RTT situa-se entre 200 e 300 milissegundos. Isolado, é tolerável. O problema é que um pedido raramente viaja sozinho.

Antes de um telemóvel poder pedir o que quer que seja através de uma ligação segura, tem de concluir dois handshakes (apertos de mão), as breves trocas de mensagens que estabelecem uma ligação. O handshake TCP abre a ligação e o handshake TLS acorda depois as chaves de encriptação que a mantêm privada. Cada um custa uma viagem de ida e volta completa. Só então o pedido propriamente dito é enviado, o que é uma terceira viagem. A 250 milissegundos por viagem, o utilizador espera cerca de três quartos de segundo antes de os nossos servidores terem feito qualquer trabalho.

Nas redes móveis, esse custo é pago muito mais vezes do que gostaríamos. Os telemóveis passam de uma antena para outra, os rádios adormecem para poupar bateria e as aplicações são enviadas para segundo plano. Qualquer um destes eventos pode derrubar a ligação, e o pedido seguinte tem de partir de uma ligação fria, uma ligação em que ainda não foi feito nenhum handshake, e pagar de novo o custo total de estabelecimento. Uma ligação quente, já aberta e protegida, salta diretamente para o pedido.

Não podíamos aproximar Lagos dos nossos servidores. Podíamos aproximar de Lagos o estabelecimento da ligação.

Mudar o handshake, não os servidores

Uma rede de distribuição de conteúdos (CDN) costuma ser descrita como uma cache: um conjunto de localizações pelo mundo que guardam cópias de ficheiros para os servir a partir de perto. Nós usámos uma por outra razão. Na nossa API, a interface com que a aplicação comunica para tudo o que faz, a cache está totalmente desligada. Cada pedido continua a viajar até à nossa origem, o nome que a CDN dá aos servidores que estão por trás dela.

O que muda é onde a ligação começa. Um telemóvel abre agora a ligação ao ponto de presença (PoP) mais próximo, também chamado localização de periferia: um dos locais da CDN espalhados pelo mundo, muitas vezes a dezenas de milissegundos de distância em vez de centenas. A periferia faz a terminação TLS, ou seja, a ligação segura com o telemóvel termina aí. Depois reutiliza um conjunto de ligações quentes à nossa origem, mantidas abertas com keep-alive, uma definição que deixa uma ligação aberta entre pedidos em vez de a fechar. As duas viagens caras de estabelecimento acontecem no salto curto, e apenas o pedido em si atravessa o oceano, numa ligação que já está quente.

Três viagens longas passam a ser uma longa e duas curtas. É toda a ideia.

O resto manteve-se propositadamente banal:

  • Os clientes não notaram nada. A aplicação e o website mantiveram os mesmos endereços, por isso não foi preciso lançar uma nova versão da aplicação nem ninguém teve de atualizar o que quer que fosse.
  • O comportamento em caso de falha manteve-se. Os tempos limite são iguais aos anteriores, pelo que tudo o que antes falhava continua a falhar da mesma forma. Não queríamos novos tipos de erro.
  • A periferia fecha primeiro as ligações inativas. Cada ligação tem um tempo limite de inatividade, o tempo que pode ficar sem uso antes de ser fechada. Se os nossos servidores fechassem uma ligação parada enquanto a periferia ainda a julgava aberta, o pedido seguinte falharia. Definir um tempo limite mais curto na periferia garante que é ela a desistir primeiro e a abrir uma ligação nova.
  • Protocolos mais recentes para telemóveis. Os telemóveis podem ligar-se por HTTP/3, a versão mais recente do protocolo de pedidos da web. Funciona sobre QUIC, que junta os dois handshakes numa única viagem de ida e volta e lida melhor com a perda de pacotes, comum nas redes móveis.
  • Nenhuma região de fora. Os escalões mais baratos de uma rede de periferia muitas vezes omitem localizações precisamente nas zonas do mundo onde vivem os nossos utilizadores, por isso escolhemos cobertura total.

O que medimos

Medimos a partir de Sydney, que fica aproximadamente tão longe dos nossos servidores como Lagos, comparando o percurso antigo com o novo. Em cada um, abrimos cinco ligações frias novas, o caso que mais importa nas redes móveis, e tirámos a mediana, também escrita p50: o resultado do meio, que metade dos pedidos supera e a outra metade não. O mesmo projeto ativou ainda a compressão dos scripts do nosso website, que eram enviados em tamanho completo. A compressão reduz um ficheiro antes de ser enviado e o navegador expande-o de novo à chegada; usámos Brotli, um formato de compressão concebido para a web.

O que medimosAntesDepoisMelhoria
Handshakes TCP e TLS concluídos (p50)490 ms59 ms88% mais rápido
Tempo até ao primeiro byte (p50)743 ms307 ms59% mais rápido
Tamanho dos scripts da página inicial1,76 MB560 KB68% mais pequeno

O tempo até ao primeiro byte é de onde vêm os 59%. Uma ligação que demorava meio segundo a estabelecer está agora pronta em menos de um décimo disso, e uma primeira visita ao nosso website descarrega agora dois terços a menos, em ligações onde muita gente paga por cada megabyte.

Estes números vêm de uma cidade, não de uma referência global. A aritmética, porém, aplica-se a Lagos e a Jacarta, e é aí que estão os nossos utilizadores.

O mais difícil era saber quem está a ligar

Pôr algo à frente dos seus servidores é fácil. Manter as suas proteções a funcionar por trás disso é onde foi a maior parte do esforço.

Como a maioria das plataformas de pagamentos, a Moove usa limitação de taxa, um limite ao número de pedidos que cada interlocutor pode fazer num dado período, e esses limites são associados ao endereço IP do interlocutor, o número que identifica um dispositivo na internet. Por trás de uma rede de periferia, todos os pedidos chegam do endereço de uma localização de periferia e não do endereço do utilizador. Se nada mais tivesse mudado, toda a gente em Lagos teria partilhado um único orçamento, e uma tarde movimentada teria começado a recusar pessoas que nada tinham feito de errado.

A solução assenta em duas ideias.

Confiar exatamente nas camadas que tem. Uma CDN é um tipo de proxy inverso, um servidor que fica à frente do seu e reencaminha os pedidos. Cada proxy acrescenta o endereço de onde recebeu o pedido a um cabeçalho padrão chamado X-Forwarded-For, pelo que o interlocutor real está um número fixo de passos, ou saltos, atrás nessa lista. Errar esse número é um erro nos dois sentidos. Se contar camadas a menos, todos os utilizadores parecem a sua localização de periferia. Se contar a mais, começa a confiar numa entrada que o próprio interlocutor escreveu. Por isso, fizemos desse número uma propriedade da infraestrutura e não do código. Muda no mesmo instante em que a rede muda, e o nosso serviço recusa-se a arrancar se o valor não fizer sentido, em vez de adivinhar.

Deixar a periferia atestar quem é o interlocutor e acreditar apenas nela. A periferia escreve agora o endereço do interlocutor real em cada pedido e substitui qualquer coisa que o interlocutor tenha enviado no seu lugar. As nossas proteções só acreditam nesse valor quando conseguem verificar que o pedido passou mesmo pela nossa periferia. Todos os limites que antes se baseavam no endereço de rede baseiam-se agora no interlocutor real para o tráfego da periferia. Acrescentámos estas regras junto das antigas em vez de as alterar, de modo que cada passo do lançamento foi uma adição pura que qualquer pessoa podia rever numa só leitura.

Um erro que apanhámos antes de seguir para produção

Os Moove Profiles podem viver no domínio próprio de um comerciante. Os pedidos para esses domínios passavam pelo nosso website com o domínio do comerciante anexado, para o site saber que perfil mostrar.

A nova periferia à frente do website remove esse tipo de informação dos pedidos recebidos, o que está exatamente certo, porque um visitante nunca deve poder defini-la. Significava também que, assim que o website passasse para trás da periferia, todos os domínios de comerciantes teriam mostrado discretamente a página inicial da Moove em vez do perfil do comerciante.

Apanhámos o problema na revisão, passámos primeiro o caminho dos domínios de comerciantes para uma rota própria e fizemos com que a nossa infraestrutura se recusasse a aplicar a alteração do website em qualquer sítio onde essa mudança não tivesse sido feita. Um erro que antes só vivia na cabeça de um revisor é agora algo que a compilação bloqueia.

A lição geral: quando acrescentar uma camada que limpa entradas, procure tudo o que dependia das entradas que está prestes a limpar.

Como fizemos o lançamento

Na infraestrutura de pagamentos não se faz "implementar e ver", por isso alterámos primeiro o ambiente de teste e depois a produção, e algumas escolhas mantiveram a transição sem sobressaltos. Reduzimos o TTL (tempo de vida) dos nossos registos DNS, o diretório da internet que converte um nome como moove.xyz num endereço de servidor. O TTL é o tempo durante o qual o resto da internet pode guardar essa resposta em cache, e reduzimo-lo de uma hora para cinco minutos, uma hora inteira antes de qualquer coisa mudar, para que a resposta antiga tivesse expirado em todo o lado e uma reversão fizesse efeito em minutos. Mantivemos os registos de endereço numa forma que podia ser alterada no próprio sítio, porque removê-los e voltar a criá-los teria deixado uma lacuna, e uma lacuna é uma interrupção. Cada passo arriscado foi uma pequena alteração própria, com os passos para a desfazer escritos por ordem.

O que diríamos a outra equipa

Se os seus utilizadores estão longe dos seus servidores, vale a pena ter uma rede de periferia mesmo que não guarde nada em cache. Antes de fazer a transição:

  • Liste tudo o que lê o endereço do interlocutor, incluindo limites de taxa, listas de permissões, sinais de fraude, registos de auditoria e regras de segurança. Cada um deles vê o endereço da periferia, a menos que o altere.
  • Faça do número de camadas de confiança parte da sua infraestrutura e recuse-se a arrancar quando estiver errado.
  • Deixe a periferia registar o interlocutor real e confie nesse registo apenas no tráfego que consegue verificar que veio da sua periferia.
  • Garanta que os seus servidores aceitam tráfego apenas através da periferia e observe antes de impor.
  • Se guarda páginas em cache, construa a chave de cache, o conjunto de detalhes do pedido que uma cache usa para decidir se dois pedidos podem partilhar uma única resposta guardada, a partir de tudo aquilo em que a resposta realmente varia. Os servidores listam esses detalhes num cabeçalho Vary, por isso leia-o em vez de confiar na memória.
  • Meça antes e depois, e veja o tempo de handshake e o tempo até ao primeiro byte em separado, para distinguir o estabelecimento da ligação do tempo que os seus servidores gastam a trabalhar.

O que se segue

A maioria das nossas páginas é personalizada, por isso a cache de periferia do website fica, para já, quase parada. A melhoria da ligação aplica-se a todas as páginas, independentemente disso, e as páginas individuais podem agora optar pela cache quando for seguro partilhá-las. Guardar respostas da API em cache exigiria o seu próprio desenho e revisão, e é a próxima coisa que queremos analisar.

O dinheiro deve mover-se à velocidade da rede, não à velocidade da luz através de um oceano.

Se desenvolve sobre a Moove, leia a nossa introdução às APIs e SDKs de pagamentos Web3 e o Moove Developer Program.

Escrito pela equipa de engenharia da moove.xyz.

Sobre a moove.xyz

A moove.xyz é uma plataforma global Web3 fintech construída para o movimento de valor sem permissão e sem esforço. Capacitamos empresas e consumidores em qualquer lugar a enviar, receber, fazer staking e trocar qualquer criptomoeda em qualquer blockchain — tudo numa única plataforma.

Somos uma das primeiras empresas Web3 fintech a nível global a inovar e construir uma infraestrutura completa de pagamentos cripto e finanças descentralizadas, permitindo uma cobertura integrada e abrangente de acesso a carteiras multi-cadeia, handles de carteira personalizados, swaps de tokens cross-chain, transações cross-chain incorporadas e uma rede financeira social descentralizada. Os nossos produtos principais incluem Moove Profile, Moove Send, Moove Receive, Moove Stake, Moove Swap, Moove Rewards, Moove Discover e mais.

A nossa missão é simples — criar e distribuir tecnologia financeira sem permissão e sem esforço para o próximo 1 mil milhão de utilizadores Web3. Acreditamos fundamentalmente que o futuro do movimento de dinheiro e valor será sem custo, sem fronteiras, sem permissão, sem esforço e construído para todos — e estamos a construir a plataforma Web3 fintech definitiva para tornar esse futuro real.

O seu dinheiro. O seu movimento.

Continue a ler.

Moove App: Pagamentos Cripto Para iOS e Android
Perspetivas

Moove App: Pagamentos Cripto Para iOS e Android

28/03/20267 min de leitura

O seu dinheiro. A decisão é sua.

Digitalize para descarregar a app Moove
Transferir na App StoreDisponível no Google Play