En sida som svarar på 200 ms mot ett lokalt Redis tar fyra sekunder när klienten sitter bakom ett VPN, medan serverns räknare står stilla. Slow Log visar inget över en millisekund, CPU-grafen är platt och instansen betjänar andra klienter utan klagomål. Det som ändrades är avståndet, och det som mångfaldigar avståndet är antalet gånger din kod stannar och väntar. Gå igenom requestens väg från klienten och utåt, och fixen är nästan alltid färre sekventiella väntetider snarare än en snabbare server.

Börja hos klienten, inte i serverns mätvärden

Titta på klientprocessen mellan första och sista kommandot. Om spåret visar ett svar, en paus och sedan nästa kommando betalar du en hel rundtur per kommando, och ingen serverjustering ändrar det. Slow Log är fel instrument här, eftersom den registrerar exekveringstid och medvetet utesluter kommunikations-I/O. En ren Slow Log intill en långsam endpoint är signaturen för ett rundtursproblem.

Mät själva vägen innan du rör koden. redis-cli -h redis.example.internal --latency skickar upprepade PING och skriver ut den genomsnittliga tiden för request och svar, vilket är din kostnad per utbyte. Multiplicera den med antalet sekventiella kommandon i en användaråtgärd och du har ett golv för endpointen.

Räkna rundturerna som en användaråtgärd faktiskt behöver

Ta en enda endpoint och skriv upp varje Redis-anrop i ordning, inklusive de som gömmer sig i en ORM, en session middleware eller en feature flag-uppslagning. De flesta långsamma endpoints gör tjugo eller trettio anrop där tre hade räckt, och de dolda är oftast majoriteten.

En beroendekedja går inte att kollapsa: om det andra kommandot behöver nyckeln som det första returnerade är väntan verklig, och de enda alternativen är en annan datamodell eller en serveroperation som uttrycker hela steget på en gång. Oberoende läsningar är ett annat fall, eftersom inget tvingar dig att invänta det första svaret innan du skickar det andra. Markera varje anrop som beroende eller oberoende innan du ändrar något, så blir fixens form uppenbar.

Det tal som spelar roll är sekventiella väntetider, inte totala kommandon. Trettio kommandon i en batch kostar fortfarande en väntan.

Batcha bara de kommandon som inte beror på varandra

En pipeline köar oberoende kommandon och samlar svaren i ordning, vilket gör N väntetider till en. De flesta klienter exponerar den som ett block, en callback eller en context manager snarare än ett separat anslutningsläge, så kontrollera API:t som din installerade version levererar. Vinsten skalar med rundturstiden, vilket är precis varför den spelar roll på ett VPN och knappt märks 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())

Skicka transaction=False när du bara vill batcha. Med standardvärdet lindar klienten batchen i MULTI och EXEC, vilket gör den atomär och ändrar vad andra klienter kan observera under flykten. Atomicitet är ett korrekthetsbeslut, inte en prestandaknapp, och en pipeline är inte en transaktion bara för att båda minskar antalet rundturer.

Läs varje svar i stället för bara batchinlämningen. Ett köat kommando kan returnera ett fel medan batchen som helhet slutförs, och en klient som kastar bort svarslistan förvandlar en misslyckad skrivning till en tyst. Jämför längden på svarslistan med antalet kommandon du köade.

Håll anslutningen vid liv mellan åtgärderna

Varje ny anslutning betalar för namnmatchning, en TCP-handskakning, en TLS-handskakning och en AUTH, och över ett VPN är var och en av dem en rundtur du inte kan batcha bort. Skapa klienten en gång per process och återanvänd den, eller använd poolen som ditt bibliotek erbjuder med en begränsad storlek. Att återansluta per request är den näst vanligaste orsaken till det här symptomet efter väntan per kommando.

Behåll det privata hostnamnet i konfigurationen i stället för en litteral adress. Certifikatvalidering och tjänstidentitet gäller fortfarande i ett privat nät, och att låsa en IP går sönder i samma stund som leverantören numrerar om ett subnet. Om uppslagningen är den långsamma delen, fixa resolvervägen i stället för anslutningssträngen.

Sätt en explicit socket-timeout så att en stockad tunnel faller snabbt i stället för att hänga en worker. Bekräfta sedan att poolen verkligen återanvänds genom att logga anslutningsskapande i klienten.

Dimensionera batchen innan den blir ett minnesproblem

Redis håller köade svar under batchens varaktighet, och klienten håller det tolkade resultatet efteråt. En pipeline med tiotusen stora värden byter nätverksväntan mot minnestoppingar och långa pauser i båda ändar.

Välj batchstorlek efter svarsvolym i stället för kommandonummer. Några hundra små kommandon i en batch är oftast bekvämt, medan hundra flerkilobytes payloads inte är det. Dela efter byte såväl som efter antal, och håll varje batch inom den latensbudget som endpointen faktiskt har.

Mät end to end efter ändringen: redis-cli -h redis.example.internal --latency-history visar om själva vägen är stabil, och din egen request-timer visar om endpointen blev bättre. Om endpointen fortfarande är långsam medan latenshistoriken är platt är den återstående kostnaden serverarbete eller din egen serialisering, och nästa steg är en profil av handlern snarare än ännu en batchändring.

Relaterade artiklar