Redis over VPN føles langsomt: færre rundture pr. anmodning
En VPN gør ikke et eksternt Redis-kald lokalt. Budgetlæg rundture pr. anmodning, genbrug forbindelser, og hold pipelines væk fra transaktioner.
En side, der svarer på 200 ms mod en lokal Redis, tager fire sekunder, når klienten sidder bag en VPN, mens serverens tællere står stille. Den langsomme log viser intet over en millisekund, CPU-grafen er flad, og instansen betjener andre klienter uden klager. Det, der er ændret, er afstanden, og det, der ganger afstanden, er antallet af gange, din kode stopper og venter. Gå anmodningens vej fra klienten og udefter, og løsningen er næsten altid færre sekventielle ventetider frem for en hurtigere server.
Start ved klienten, ikke ved serverens målinger
Hold øje med klientprocessen mellem den første og den sidste kommando. Hvis sporet viser et svar, en pause og derefter den næste kommando, betaler du en fuld rundtur pr. kommando, og ingen mængde servertuning ændrer det. Den langsomme log er det forkerte instrument her, fordi den registrerer udførelsestid og bevidst udelukker kommunikations-I/O. En ren langsom log ved siden af et langsomt endepunkt er signaturen på et rundturproblem.
Mål selve vejen, før du rører ved koden. redis-cli -h redis.example.internal --latency sender gentagne PING'er og udskriver den gennemsnitlige anmodnings- og svartid, som er din pris pr. udveksling. Gang det med antallet af sekventielle kommandoer i én brugerhandling, og du har en nedre grænse for endepunktet.
Tæl de rundture, som én brugerhandling faktisk kræver
Tag et enkelt endepunkt og skriv hvert Redis-kald ned i rækkefølge, inklusive dem, der er skjult i en ORM, en session-middleware eller et feature-flag-opslag. De fleste langsomme endepunkter viser sig at lave tyve eller tredive kald, hvor tre ville gøre det, og de skjulte er normalt flertallet.
En afhængighedskæde kan ikke slås sammen: hvis den anden kommando har brug for nøglen, som den første returnerer, er ventetiden reel, og de eneste muligheder er en anden datamodel eller en serveroperation, der udtrykker hele trinnet på én gang. Uafhængige læsninger er en anden sag, fordi intet tvinger dig til at afvente det første svar, før du sender det andet. Marker hvert kald som afhængigt eller uafhængigt, før du redigerer noget, og løsningens form bliver tydelig.
Det tal, der betyder noget, er sekventielle ventetider, ikke det samlede antal kommandoer. Tredive kommandoer i én batch koster stadig én ventetid.
Batch kun de kommandoer, der ikke afhænger af hinanden
En pipeline sætter uafhængige kommandoer i kø og samler svarene i rækkefølge, hvilket gør N ventetider til én. De fleste klienter eksponerer det som en blok, et callback eller en context manager frem for en separat forbindelsestilstand, så tjek den API, din installerede version leverer. Gevinsten skalerer med rundturstiden, og det er netop derfor, det betyder noget på en VPN og næsten ikke mærkes på localhost.
import redis
r = redis.Redis(host="redis.example.internal", port=6379, socket_timeout=2)
pipe = r.pipeline(transaction=False)
for key in ("user:1001", "user:1002", "user:1003"):
pipe.get(key)
print(pipe.execute())
Send transaction=False, når du kun vil batche. Som standard pakker klienten batchen ind i MULTI og EXEC, hvilket gør den atomisk og ændrer, hvad andre klienter kan observere undervejs. Atomicitet er en beslutning om korrekthed, ikke en ydelsesknap, og en pipeline er ikke en transaktion, bare fordi begge reducerer rundture.
Læs hvert svar i stedet for kun batchafsendelsen. En kommando i kø kan returnere en fejl, mens batchen som helhed gennemføres, og en klient, der smider svarlisten væk, gør en mislykket skrivning til en tavs. Sammenlign svarlistens længde med antallet af kommandoer, du satte i kø.
Hold forbindelsen i live mellem handlinger
Hver ny forbindelse betaler for navneopløsning, et TCP-håndtryk, et TLS-håndtryk og en AUTH, og over en VPN er hver af dem en rundtur, du ikke kan batche væk. Opret klienten én gang pr. proces og genbrug den, eller brug den pool, dit bibliotek tilbyder, med en begrænset størrelse. Genopkobling pr. anmodning er den næstmest almindelige årsag til dette symptom efter ventetider pr. kommando.
Hold det private værtsnavn i konfigurationen i stedet for en bogstavelig adresse. Certifikatvalidering og tjenesteidentitet gælder stadig på et privat netværk, og fastgørelse af en IP brækker i det øjeblik, udbyderen omnummererer et subnet. Hvis opløsning er den langsomme del, skal du rette resolverstien i stedet for forbindelsesstrengen.
Sæt en eksplicit socket-timeout, så en fastlåst tunnel fejler hurtigt i stedet for at hænge en worker. Bekræft derefter, at poolen virkelig genbruges, ved at logge forbindelsesoprettelse i klienten.
Dimensionér batchen, før den bliver et hukommelsesproblem
Redis holder køede svar i hele batchens varighed, og klienten holder derefter det parsede resultat. En pipeline med ti tusind store værdier bytter netværksventetider for hukommelsestoppe og lange pauser i begge ender.
Vælg en batchstørrelse efter svarmængde frem for kommandotal. Et par hundrede små kommandoer i én batch er normalt behageligt, mens hundrede payloads på flere kilobyte ikke er. Del efter bytes såvel som efter antal, og hold hver batch inden for det latenstidsbudget, endepunktet faktisk har.
Mål ende-til-ende efter ændringen: redis-cli -h redis.example.internal --latency-history viser, om vejen selv er stabil, og din egen anmodningstimer viser, om endepunktet blev bedre. Hvis endepunktet stadig er langsomt, mens latenstidshistorikken er flad, er den resterende omkostning serverarbejde eller din egen serialisering, og næste skridt er en profil af handleren frem for endnu en batchændring.