Hoe we de prestaties van Moove met 59% verbeterden
Moove-gebruikers zitten ver van onze servers. Zo verkortten we de tijd tot de eerste reactie met 59% zonder een server te verplaatsen, en wat het lastig maakte.Afstand was onze traagste afhankelijkheid
De meeste mensen die de Moove app openen, zitten op mobiele netwerken in Nigeria en Indonesië, duizenden kilometers verwijderd van de servers die hun antwoord geven. Deze maand hebben we veranderd hoe hun verzoeken ons bereiken, en onze tijd tot de eerste byte (TTFB), de tijd tussen het moment dat een telefoon een verzoek verstuurt en het moment dat het eerste stuk van het antwoord binnenkomt, daalde met 59%: van 0,74 seconde naar 0,31 seconde. Daarvoor hebben we geen enkele server verplaatst.
In dit bericht leggen we uit waarom afstand ons meer kostte dan we verwachtten, wat we hebben veranderd, welk deel moeilijker bleek dan de verandering zelf, en wat we een ander team zouden vertellen dat hetzelfde wil doen.
Waarom één lange reis er drie wordt
Ontwikkelaars noemen de vertraging tussen het versturen van iets en de aankomst ervan latentie, en de tijd die een bericht nodig heeft om een server te bereiken en het antwoord terug te laten komen de heen-en-terugtijd (RTT). Van Lagos naar onze servers ligt de RTT tussen 200 en 300 milliseconden. Op zichzelf is dat te verdragen. Het probleem is dat een verzoek zelden alleen reist.
Voordat een telefoon via een beveiligde verbinding iets kan opvragen, moet hij twee handshakes voltooien: de korte uitwisselingen waarmee een verbinding tot stand komt. De TCP-handshake opent de verbinding, en de TLS-handshake spreekt vervolgens de encryptiesleutels af die de verbinding privé houden. Elk daarvan kost een volledige heen-en-terugreis. Pas daarna gaat het verzoek zelf op pad, en dat is de derde reis. Bij 250 milliseconden per reis wacht een gebruiker ruwweg driekwart seconde voordat onze servers ook maar iets hebben gedaan.
Op mobiele netwerken betaal je die prijs veel vaker dan je zou hopen. Telefoons wisselen van zendmast, radio's gaan slapen om batterij te sparen en apps worden naar de achtergrond gestuurd. Elk van die gebeurtenissen kan de verbinding verbreken, waarna het volgende verzoek vanaf een koude verbinding moet beginnen, een verbinding waarvan nog geen enkele handshake is uitgevoerd, en de volledige opbouwkosten opnieuw moet betalen. Een warme verbinding, die al open en beveiligd is, gaat direct door naar het verzoek.
We konden Lagos niet dichter bij onze servers brengen. We konden wel de opbouw dichter bij Lagos brengen.
De handshake verplaatsen, niet de servers
Een contentleveringsnetwerk (CDN) wordt meestal beschreven als een cache: een reeks locaties over de hele wereld die kopieën van bestanden bewaren, zodat ze van dichtbij kunnen worden geleverd. Wij gebruikten er een om een andere reden. Voor onze API, de interface waarmee de app praat voor alles wat ze doet, staat caching volledig uit. Elk verzoek reist nog steeds naar onze origin, de naam die het CDN geeft aan de servers erachter.
Wat verandert, is waar de verbinding begint. Een telefoon opent zijn verbinding nu met de dichtstbijzijnde edgelocatie, ook wel point of presence (PoP) genoemd: een van de vestigingen van het CDN over de hele wereld, vaak tientallen milliseconden verwijderd in plaats van honderden. De edge voert TLS-beëindiging uit, wat betekent dat de beveiligde verbinding vanaf de telefoon daar eindigt. Vervolgens hergebruikt de edge een pool van warme verbindingen met onze origin, open gehouden met keep-alive, een instelling die een verbinding tussen verzoeken open laat in plaats van hem te sluiten. De twee dure opbouwreizen vinden plaats over de korte afstand, en alleen het verzoek zelf steekt de oceaan over, over een verbinding die al warm is.
Drie lange reizen worden één lange en twee korte reizen. Dat is het hele idee.
De rest hebben we bewust saai gehouden:
- Clients merkten niets. De app en de website behielden dezelfde adressen, dus er was geen app-release nodig en niemand hoefde iets aan te passen.
- Het foutgedrag bleef gelijk. De time-outs komen overeen met wat er eerder was, dus alles wat eerder mislukte, mislukt nog steeds op dezelfde manier. We wilden geen nieuwe soorten fouten.
- De edge sluit inactieve verbindingen als eerste. Elke verbinding heeft een inactiviteitstime-out: hoe lang ze ongebruikt kan blijven voordat ze wordt gesloten. Als onze servers een stille verbinding sloten terwijl de edge dacht dat ze nog open was, zou het volgende verzoek mislukken. Door de time-out van de edge korter in te stellen, geeft de edge altijd als eerste op en opent hij een nieuwe verbinding.
- Nieuwere protocollen voor telefoons. Telefoons kunnen verbinden via HTTP/3, de nieuwste versie van het verzoekprotocol van het web. Dat draait op QUIC, dat beide handshakes samenvoegt tot één heen-en-terugreis en beter omgaat met het pakketverlies dat op mobiele netwerken veel voorkomt.
- Geen enkele regio overgeslagen. Goedkopere lagen van een edgenetwerk slaan vaak locaties over in precies de delen van de wereld waar onze gebruikers wonen, dus kozen we voor volledige dekking.
Wat we hebben gemeten
We maten vanuit Sydney, dat ongeveer even ver van onze servers ligt als Lagos, en vergeleken het oude pad met het nieuwe. Voor elk pad openden we vijf nieuwe koude verbindingen, het geval dat op mobiele netwerken het meest telt, en namen we de mediaan, ook geschreven als p50: het middelste resultaat, dat de helft van de verzoeken verslaat en de andere helft niet. Hetzelfde project schakelde ook compressie in voor de scripts van onze website, die tot dan toe op volledige grootte werden verstuurd. Compressie verkleint een bestand voordat het wordt verstuurd en de browser pakt het bij aankomst weer uit; wij gebruikten Brotli, een compressieformaat dat voor het web is gebouwd.
| Wat we hebben gemeten | Voor | Na | Verbetering |
|---|---|---|---|
| TCP- en TLS-handshakes voltooid (p50) | 490 ms | 59 ms | 88% sneller |
| Tijd tot de eerste byte (p50) | 743 ms | 307 ms | 59% sneller |
| Scriptgrootte van de startpagina | 1.76 MB | 560 KB | 68% kleiner |
De tijd tot de eerste byte is waar de 59% vandaan komt. Een verbinding die vroeger een halve seconde nodig had om op te bouwen, is nu in minder dan een tiende daarvan klaar, en een eerste bezoek aan onze website downloadt nu twee derde minder, op verbindingen waar veel mensen voor elke megabyte betalen.
Deze cijfers komen uit één stad en zijn geen wereldwijde benchmark. De rekensom geldt echter ook voor Lagos en Jakarta, en daar zitten onze gebruikers.
Het moeilijke deel was weten wie er aanklopt
Iets voor je servers zetten is makkelijk. Je beveiligingen laten blijven werken erachter is waar het meeste werk in zat.
Zoals de meeste betaalplatforms gebruikt Moove rate limiting, een plafond voor het aantal verzoeken dat één aanroeper in een bepaalde tijd kan doen, en die limieten zijn gekoppeld aan het IP-adres van de aanroeper, het nummer dat een apparaat op internet identificeert. Achter een edgenetwerk komt elk verzoek binnen vanaf het adres van een edgelocatie in plaats van dat van de gebruiker. Als er verder niets was veranderd, zou iedereen in Lagos één budget hebben gedeeld, en één drukke middag zou mensen zijn gaan weigeren die niets verkeerd hadden gedaan.
De oplossing rust op twee ideeën.
Vertrouw precies de lagen die je hebt. Een CDN is een soort reverse proxy, een server die voor de jouwe staat en verzoeken doorgeeft. Elke proxy voegt het adres waarvan hij een verzoek ontving toe aan een standaardheader genaamd X-Forwarded-For, zodat de echte aanroeper een vast aantal stappen, of hops, terug in die lijst staat. Dat getal verkeerd hebben is een bug in beide richtingen. Tel je te weinig lagen, dan lijkt elke gebruiker op zijn edgelocatie. Tel je er te veel, dan ga je een vermelding vertrouwen die de aanroeper zelf heeft geschreven. Daarom maakten we van dat getal een eigenschap van de infrastructuur in plaats van van de code. Het verandert op hetzelfde moment als het netwerk, en onze service weigert te starten als de waarde nergens op slaat, in plaats van te gokken.
Laat de edge instaan voor de aanroeper, en geloof alleen de edge. De edge schrijft nu het echte adres van de aanroeper op elk verzoek en overschrijft alles wat de aanroeper daarvoor in de plaats had meegestuurd. Onze beveiligingen geloven die waarde alleen als ze kunnen verifiëren dat het verzoek echt via onze edge is binnengekomen. Elke limiet die vroeger op het netwerkadres was gebaseerd, gebruikt nu voor edgeverkeer de echte aanroeper. We hebben deze regels naast de oude toegevoegd in plaats van die te wijzigen, zodat elke stap in de uitrol een pure toevoeging was die iedereen in één keer kon beoordelen.
Een bug die we hebben gevangen voordat hij live ging
Moove Profiles kunnen op het eigen domein van een handelaar staan. Verzoeken voor die domeinen werden via onze website doorgegeven met het domein van de handelaar erbij, zodat de site wist welk profiel hij moest tonen.
De nieuwe edge voor de website haalt dat soort informatie uit binnenkomende verzoeken weg, en dat is precies goed, omdat een bezoeker dat nooit zelf zou moeten kunnen instellen. Het betekende echter ook dat zodra de website achter de edge stond, elk handelaarsdomein stilletjes de Moove-startpagina zou hebben getoond in plaats van het profiel van de handelaar.
We ving het op in de review, verplaatsten het pad voor handelaarsdomeinen eerst naar een eigen route, en zorgden ervoor dat onze infrastructuur weigert de wijziging aan de website toe te passen waar die verplaatsing nog niet had plaatsgevonden. Een fout die vroeger alleen in het hoofd van een reviewer bestond, is nu iets wat de build tegenhoudt.
De algemene les: als je een laag toevoegt die invoer opschoont, zoek dan naar alles wat afhing van de invoer die je gaat opschonen.
Hoe we het hebben uitgerold
Bij betalingsinfrastructuur doe je niet "uitrollen en kijken", dus pasten we eerst staging aan en daarna productie, en een paar keuzes hielden de overgang rustig. We verlaagden de TTL (time to live) van onze DNS-records, de telefoongids van het internet die een naam als moove.xyz omzet in een serveradres. De TTL is hoe lang de rest van het internet dat antwoord mag cachen, en we verlaagden hem van een uur naar vijf minuten, een vol uur voordat er iets verhuisde, zodat het oude antwoord overal was verlopen en een rollback binnen enkele minuten van kracht zou zijn. We hielden adresrecords in een vorm die ter plekke kon worden omgeschakeld, omdat verwijderen en opnieuw aanmaken een gat zou hebben achtergelaten, en een gat is een storing. Elke riskante stap was een eigen kleine wijziging, met de stappen om hem ongedaan te maken in volgorde opgeschreven.
Wat we een ander team zouden vertellen
Als je gebruikers ver van je servers zitten, is een edgenetwerk de moeite waard, ook als het niets cachet. Voordat je overschakelt:
- Maak een lijst van alles wat het adres van de aanroeper leest, waaronder rate limits, allowlists, fraudesignalen, auditlogs en beveiligingsregels. Elk daarvan ziet het adres van de edge, tenzij je dat verandert.
- Maak het aantal vertrouwde lagen onderdeel van je infrastructuur en weiger te starten als het niet klopt.
- Laat de edge de echte aanroeper vastleggen en vertrouw die vastlegging alleen bij verkeer waarvan je kunt verifiëren dat het van je edge kwam.
- Zorg dat je servers verkeer alleen via de edge accepteren, en kijk eerst voordat je afdwingt.
- Als je pagina's cachet, bouw dan de cachesleutel, de verzameling verzoekdetails die een cache gebruikt om te bepalen of twee verzoeken één opgeslagen antwoord kunnen delen, uit alles waarvan het antwoord echt afhangt. Servers noemen die details in een Vary-header, dus lees die in plaats van op je geheugen te vertrouwen.
- Meet voor en na, en kijk afzonderlijk naar de handshaketijd en de tijd tot de eerste byte, zodat je het opbouwen van de verbinding kunt onderscheiden van de tijd die je servers aan werk besteden.
Vooruitblik
De meeste van onze pagina's zijn gepersonaliseerd, dus de edgecache van de website staat voorlopig grotendeels stil. De verbetering van de verbinding geldt voor elke pagina, en afzonderlijke pagina's kunnen nu kiezen voor caching wanneer het veilig is om ze te delen. Het cachen van API-antwoorden zou een eigen ontwerp en review vergen, en dat is het volgende wat we willen bekijken.
Geld moet bewegen met de snelheid van het netwerk, niet met de snelheid van het licht over een oceaan.
Als je bouwt op Moove, lees dan onze introductie tot Web3-betaal-API's en -SDK's en het Moove Developer Program.
Geschreven door het engineeringteam van moove.xyz.
Over moove.xyz
moove.xyz is een wereldwijd Web3 fintech-platform gebouwd voor de permissievrije en moeiteloze beweging van waarde. Wij stellen bedrijven en consumenten overal in staat om elke cryptocurrency over elke blockchain te versturen, ontvangen, staken en wisselen — alles in één enkel platform.
Wij zijn een van de eerste Web3 fintech-bedrijven wereldwijd die een full-stack crypto-betalings- en gedecentraliseerde financiële infrastructuur innoveren en bouwen, die een geïntegreerde en uitgebreide dekking mogelijk maakt over multi-chain wallettoeggang, gepersonaliseerde wallet-handles, cross-chain tokenswaps, ingebedde cross-chain transacties en een gedecentraliseerd sociaal financieel netwerk. Onze belangrijkste producten zijn Moove Profile, Moove Send, Moove Receive, Moove Stake, Moove Swap, Moove Rewards, Moove Discover en meer.
Onze missie is eenvoudig — het creëren en distribueren van permissievrije en moeiteloze financiële technologie voor de volgende 1 miljard Web3-gebruikers. Wij geloven fundamenteel dat de toekomst van de beweging van geld en waarde kostenloos, grenzeloos, permissievrij, moeiteloos en gebouwd voor iedereen zal zijn — en we bouwen het ultieme Web3 fintech-platform om die toekomst werkelijkheid te maken.
Jouw geld. Jouw zet.






