Redis cez VPN je pomalý: znížte počet kôl na požiadavku
VPN nezmení vzdialené volanie Redisu na lokálne. Rozpočítajte kolá na požiadavku, znovu používajte pripojenia a držte pipeline ďalej od transakcií.
Stránka, ktorá pri lokálnom Redis odpovie za 200 ms, potrebuje štyri sekundy, len čo klient sedí za VPN, pričom počítadlá servera zostávajú nečinné. Slow Log neukazuje nič nad milisekundu, graf CPU je plochý a inštancia obsluhuje ďalších klientov bez sťažností. Čo sa zmenilo, je vzdialenosť, a to, čo vzdialenosť násobí, je počet rázov, keď sa váš kód zastaví a čaká. Prejdite cestu požiadavky od klienta smerom von a oprava je takmer vždy v menšom počte sekvenčných čakaní, nie v rýchlejšom serveri.
Začnite na klientovi, nie na metrikách servera
Sledujte proces klienta medzi prvým a posledným príkazom. Ak stopa ukazuje odpoveď, pauzu a potom nasledujúci príkaz, platíte jedno celé kolo na príkaz a žiadne ladenie servera to nezmení. Slow Log je tu nesprávny nástroj, pretože zaznamenáva čas vykonania a komunikačné I/O zámerne vylučuje. Čistý Slow Log vedľa pomalého endpointu je podpisom problému s počtom kôl.
Zmerajte najprv samotnú cestu, až potom sa dotýkajte kódu. redis-cli -h redis.example.internal --latency posiela opakované PINGy a vypisuje priemerný čas požiadavky a odpovede, čo je vaša cena za jednu výmenu. Vynásobte ju počtom sekvenčných príkazov v jednej akcii používateľa a máte spodnú hranicu pre endpoint.
Spočítajte, koľko kôl jedna akcia používateľa skutočne potrebuje
Vezmite jeden endpoint a zapíšte si každé volanie Redisu v poradí, vrátane tých skrytých v ORM, v session middlewari alebo v hľadaní feature flagu. Väčšina pomalých endpointov robí dvadsať alebo tridsať volaní tam, kde by stačili tri, a tie skryté sú zvyčajne väčšina.
Reťaz závislostí sa nedá zložiť: ak druhý príkaz potrebuje kľúč vrátený prvým, čakanie je skutočné a jediné možnosti sú iný dátový model alebo serverová operácia, ktorá celý krok vyjadrí naraz. Nezávislé čítania sú iný prípad, pretože nič vás nenúti čakať na prvú odpoveď pred odoslaním druhej. Označte každé volanie ako závislé alebo nezávislé skôr, než čokoľvek upravíte, a tvar opravy bude zrejmý.
Rozhodujúci je počet sekvenčných čakaní, nie celkový počet príkazov. Tridsať príkazov v jednej dávke stojí stále len jedno čakanie.
Dávkujte len príkazy, ktoré nezávisia jeden od druhého
Pipeline zaraďuje nezávislé príkazy do frontu a odpovede zbiera v poradí, čím sa N čakaní mení na jedno. Väčšina klientov ju vystavuje ako blok, callback alebo kontextový manažér, nie ako samostatný režim pripojenia, preto si skontrolujte API, ktoré vaša nainštalovaná verzia ponúka. Zisk rastie s časom kola, a práve preto záleží na VPN a na localhoste sa takmer neprejaví.
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())
Odovzdajte transaction=False vtedy, keď chcete len dávkovanie. Pri predvolenom nastavení klient zabalí dávku do MULTI a EXEC, čím je atomická a mení, čo iní klienti vidia počas letu. Atomicita je rozhodnutie o korektnosti, nie výkonový gombík, a pipeline nie je transakcia len preto, že obe znižujú počet kôl.
Prečítajte si každú odpoveď, nie iba odoslanie dávky. Zaradený príkaz môže vrátiť chybu, kým dávka ako celok skončí úspešne, a klient, ktorý zoznam odpovedí zahodí, premení neúspešný zápis na tichý. Porovnajte dĺžku zoznamu odpovedí s počtom príkazov, ktoré ste zaradili.
Udržujte pripojenie živé medzi akciami
Každé nové pripojenie platí za preklad mena, TCP handshake, TLS handshake a AUTH, a za VPN je každé z toho kolo, ktoré nedávkujete. Vytvorte klienta raz na proces a znovu ho používajte, alebo použite pool, ktorý vaša knižnica poskytuje, s obmedzenou veľkosťou. Opätovné pripájanie na každú požiadavku je druhá najčastejšia príčina tohto príznaku hneď po čakaní na každý príkaz.
Uchovávajte súkromný hostname v konfigurácii, nie ako doslovnú adresu. Validácia certifikátu a identita služby platia aj v súkromnej sieti a pripnutie IP sa zlomí v momente, keď poskytovateľ prečísluje subnet. Ak je pomalý preklad mien, opravte cestu k resolveru, nie connection string.
Nastavte explicitný socket timeout, aby zaseknutý tunel zlyhal rýchlo a nezavesil workera. Potom overte, že sa pool naozaj znovu používa, logovaním vytvárania pripojení v klientovi.
Dimenzujte dávku skôr, než sa z nej stane problém s pamäťou
Redis drží zaradené odpovede po celý čas dávky a klient potom drží spracovaný výsledok. Pipeline s desiatimi tisícmi veľkých hodnôt vymieňa čakanie na sieť za špičky pamäte a dlhé pauzy na oboch koncoch.
Veľkosť dávky vyberajte podľa objemu odpovedí, nie podľa počtu príkazov. Niekoľko stoviek malých príkazov v jednej dávke je zvyčajne v pohode, kým sto viackilobajtových payloadov nie. Rozdeľujte podľa bajtov aj podľa počtu a každú dávku držte v rámci latencie, ktorú endpoint skutočne má.
Po zmene merajte end to end: redis-cli -h redis.example.internal --latency-history ukáže, či je samotná cesta stabilná, a váš vlastný časovač požiadaviek ukáže, či sa endpoint zlepšil. Ak je endpoint stále pomalý a história latencie je plochá, zostávajúca cena je práca na strane servera alebo vaša serializácia, a ďalším krokom je profil handlera, nie ďalšia zmena dávkovania.