Stránka, která odpovídá za 200 ms proti lokálnímu Redis, trvá čtyři sekundy, jakmile klient sedí za VPN, zatímco počítadla serveru zůstávají nečinná. Pomalý log neukazuje nic nad milisekundu, graf CPU je plochý a instance obsluhuje jiné klienty bez stížností. Změnila se vzdálenost a to, co vzdálenost násobí, je počet zastavení a čekání ve vašem kódu. Projděte cestu požadavku od klienta ven a řešením je téměř vždy méně po sobě jdoucích čekání, ne rychlejší server.

Začněte u klienta, ne u metrik serveru

Sledujte proces klienta mezi prvním a posledním příkazem. Pokud stopa ukazuje odpověď, pauzu a pak další příkaz, platíte plnou zpáteční cestu za každý příkaz a žádné ladění serveru to nezmění. Pomalý log je zde špatný nástroj, protože zaznamenává dobu provádění a komunikační I/O záměrně vylučuje. Čistý pomalý log vedle pomalého endpointu je podpis problému se zpátečními cestami.

Změřte samotnou cestu, než se dotknete kódu. redis-cli -h redis.example.internal --latency posílá opakované PINGy a tiskne průměrnou dobu požadavku a odpovědi, což jsou vaše náklady na jednu výměnu. Vynásobte to počtem po sobě jdoucích příkazů v jedné akci uživatele a máte spodní hranici pro endpoint.

Spočítejte zpáteční cesty, které jedna akce uživatele skutečně potřebuje

Vezměte jeden endpoint a zapište každé volání Redis v pořadí, včetně těch skrytých v ORM, session middleware nebo hledání feature flagu. Většina pomalých endpointů nakonec dělá dvacet nebo třicet volání tam, kde by stačila tři, a skrytá jsou obvykle většinou.

Řetěz závislostí nelze složit: pokud druhý příkaz potřebuje klíč vrácený prvním, čekání je skutečné a jediné možnosti jsou jiný datový model nebo serverová operace, která vyjádří celý krok najednou. Nezávislá čtení jsou jiný případ, protože nic vás nenutí čekat na první odpověď, než odešlete druhou. Označte každé volání jako závislé nebo nezávislé, než cokoli upravíte, a tvar řešení bude zřejmý.

Rozhodující číslo jsou po sobě jdoucí čekání, ne celkové příkazy. Třicet příkazů v jedné dávce stojí stále jedno čekání.

Do dávky dávejte jen příkazy, které na sobě nezávisí

Pipeline zařadí nezávislé příkazy do fronty a posbírá odpovědi v pořadí, čímž promění N čekání v jedno. Většina klientů to nabízí jako blok, callback nebo context manager, ne jako samostatný režim připojení, proto zkontrolujte API, které dodává nainstalovaná verze. Zisk roste s dobou zpáteční cesty, a právě proto je důležitý na VPN a na localhostu sotva znatelný.

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())

Předejte transaction=False, když chcete jen dávkování. Ve výchozím nastavení klient zabalí dávku do MULTI a EXEC, což ji udělá atomickou a změní, co ostatní klienti mohou vidět během provádění. Atomicita je rozhodnutí o správnosti, ne páka výkonu, a pipeline není transakce jen proto, že obě snižují zpáteční cesty.

Čtěte každou odpověď, ne jen odeslání dávky. Zařazený příkaz může vrátit chybu, zatímco dávka jako celek dokončí, a klient, který seznam odpovědí zahodí, promění neúspěšný zápis v tichý. Porovnejte délku seznamu odpovědí s počtem příkazů, které jste zařadili.

Udržujte spojení živé mezi akcemi

Každé nové připojení platí za překlad jmen, TCP handshake, TLS handshake a AUTH, a přes VPN je každé z nich zpáteční cesta, kterou nezadávkujete. Vytvářejte klienta jednou na proces a znovu ho používejte, nebo použijte pool, který nabízí vaše knihovna, s omezenou velikostí. Připojování znovu pro každý požadavek je druhá nejčastější příčina tohoto symptomu po čekáních na příkaz.

Držte privátní název hostitele v konfiguraci, ne doslovnou adresu. Ověřování certifikátu a identita služby platí i v privátní síti a připnutí IP se rozbije v okamžiku, kdy poskytovatel přečísluje podsíť. Pokud je pomalá část překlad jmen, opravte cestu resolveru, ne připojovací řetězec.

Nastavte explicitní socket timeout, aby zaseknutý tunel rychle selhal, místo aby zavěsil pracovníka. Potom potvrďte, že se pool skutečně znovu používá, logováním vytváření připojení v klientovi.

Nadimenzujte dávku, než se stane problémem s pamětí

Redis drží odpovědi ve frontě po celou dobu dávky a klient potom drží parsovaný výsledek. Pipeline deseti tisíc velkých hodnot mění síťová čekání za skoky paměti a dlouhé pauzy na obou koncích.

Vyberte velikost dávky podle objemu odpovědí, ne počtu příkazů. Několik stovek malých příkazů v jedné dávce je obvykle pohodlné, sto vícekilobajtových zátěží už ne. Dělte podle bajtů i podle počtu a držte každou dávku v rozpočtu latence, který endpoint skutečně má.

Změřte po změně cestu od začátku do konce: redis-cli -h redis.example.internal --latency-history ukáže, zda je cesta sama stabilní, a váš vlastní časovač požadavků ukáže, zda se endpoint zlepšil. Pokud je endpoint stále pomalý a historie latence je plochá, zbývající náklad je práce na serveru nebo vaše vlastní serializace, a dalším krokem je profil handleru, ne další změna dávkování.

Související články