Ang pahinang sumasagot sa 200 ms laban sa lokal na Redis ay tumatagal ng apat na segundo kapag ang kliyente ay nasa likod ng VPN, habang walang ginagawa ang mga counter ng server. Walang ipinapakita ang Slow Log na mataas sa isang millisecond, flat ang graph ng CPU, at naglilingkod ang instance sa ibang mga kliyente nang walang reklamo. Ang nagbago ay ang distansya, at ang nagpapalaki sa distansya ay ang dami ng beses na humihinto at naghihintay ang iyong code. Lakarin ang landas ng kahilingan mula sa kliyente pakanlabas at halos palaging mas kaunting sunod-sunod na paghihintay ang solusyon, hindi mas mabilis na server.

Magsimula sa kliyente, hindi sa mga metric ng server

Panoorin ang proseso ng kliyente sa pagitan ng unang utos at ng huli. Kung ang trace ay nagpapakita ng sagot, isang paghinto, at pagkatapos ang susunod na utos, nagbabayad ka ng buong round trip kada utos at walang pagsasaayos ng server ang makakabago nito. Maling instrumento ang Slow Log dito, dahil nagtatala ito ng oras ng pagpapatupad at sadyang hindi kasama ang I/O ng komunikasyon. Ang malinis na Slow Log sa tabi ng mabagal na endpoint ay tanda ng problemang round trip.

Sukatin muna ang landas mismo bago hawakan ang code. redis-cli -h redis.example.internal --latency ay nagpapadala ng paulit-ulit na PING at naglilimbag ng average na oras ng kahilingan at sagot, na siyang gastos mo kada palitan. I-multiply iyon sa bilang ng sunod-sunod na utos sa isang aksyon ng user at mayroon kang pinakamababang antas para sa endpoint.

Bilangin ang mga round trip na talagang kailangan ng isang aksyon ng user

Kumuha ng isang endpoint at isulat ang bawat tawag sa Redis sa pagkakasunod-sunod, kasama ang mga nakatago sa loob ng ORM, session middleware o paghahanap ng feature flag. Karamihan sa mabagal na endpoint ay gumagawa ng dalawampu o tatlumpung tawag kung saan sapat na ang tatlo, at ang mga nakatago ang kadalasang mayorya.

Hindi maaaring ipagsama ang isang kadena ng dependency: kung kailangan ng ikalawang utos ang key na ibinalik ng una, totoo ang paghihintay at ang tanging pagpipilian ay ibang data model o operasyon sa server na nagpapahayag ng buong hakbang nang sabay. Ibang kaso ang mga independiyenteng pagbasa, dahil walang pumipilit sa iyong hintayin ang unang sagot bago ipadala ang pangalawa. Markahan ang bawat tawag bilang dependent o independent bago ka magbago ng kahit ano, at magiging halata ang hugis ng solusyon.

Ang mahalagang bilang ay ang sunod-sunod na paghihintay, hindi ang kabuuang utos. Ang tatlumpung utos sa isang batch ay isang paghihintay pa rin ang bayad.

I-batch lamang ang mga utos na hindi umaasa sa isa't isa

Ang pipeline ay nagpupuno ng mga independiyenteng utos sa pila at kinokolekta ang mga sagot sa pagkakasunod-sunod, na ginagawang isa ang N paghihintay. Ipinapakita ito ng karamihan sa mga kliyente bilang block, callback o context manager sa halip na hiwalay na mode ng koneksyon, kaya suriin ang API na ibinibigay ng naka-install na bersyon. Lumalaki ang pakinabang kasabay ng oras ng round trip, at iyon mismo ang dahilan kung bakit mahalaga ito sa VPN at bahagya lamang sa 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())

Ipasa ang transaction=False kapag batching lang ang gusto mo. Sa default ay binabalot ng kliyente ang batch sa MULTI at EXEC, na ginagawa itong atomic at binabago kung ano ang nakikita ng ibang kliyente habang tumatakbo. Ang atomicity ay desisyon sa kawastuhan, hindi sa performance, at ang pipeline ay hindi transaksyon dahil lang pareho silang nagpapababa ng round trip.

Basahin ang bawat sagot sa halip na ang pagsusumite ng batch lang. Maaaring magbalik ng error ang isang utos sa pila habang ang buong batch ay natatapos, at ang kliyenteng nagtatapon ng listahan ng sagot ay ginagawang tahimik ang isang bigong write. Ihambing ang haba ng listahan ng sagot sa bilang ng mga utos na inilagay mo sa pila.

Panatilihing buhay ang koneksyon sa pagitan ng mga aksyon

Ang bawat bagong koneksyon ay nagbabayad ng name resolution, isang TCP handshake, isang TLS handshake at isang AUTH, at sa ibabaw ng VPN ang bawat isa sa mga iyon ay round trip na hindi mo maaaring i-batch. Gumawa ng kliyente isang beses kada proseso at muling gamitin ito, o gamitin ang pool na ibinibigay ng iyong library na may limitadong laki. Ang muling pagkonekta kada kahilingan ay ang pangalawang pinakakaraniwang sanhi ng sintomas na ito pagkatapos ng paghihintay kada utos.

Panatilihin ang pribadong hostname sa configuration sa halip na literal na address. Naaangkop pa rin ang certificate validation at service identity sa pribadong network, at nasisira ang pag-pin ng IP sa sandaling magpalit ng numero ang provider sa isang subnet. Kung ang resolution ang mabagal na bahagi, ayusin ang landas ng resolver sa halip na ang connection string.

Magtakda ng tahasang socket timeout upang mabilis na mabigo ang natigil na tunnel sa halip na mabitin ang isang worker. Pagkatapos ay kumpirmahin na talagang muling ginagamit ang pool sa pamamagitan ng pag-log ng paggawa ng koneksyon sa kliyente.

Sukatin ang laki ng batch bago ito maging problemang memorya

Hinahawakan ng Redis ang mga nakapilang sagot sa buong tagal ng batch, at pagkatapos ay hinahawakan ng kliyente ang na-parse na resulta. Ang pipeline ng sampung libong malalaking halaga ay ipinagpapalit ang paghihintay sa network para sa pagsipa ng memorya at mahabang paghinto sa magkabilang dulo.

Piliin ang laki ng batch ayon sa dami ng sagot sa halip na bilang ng utos. Ang ilang daang maliliit na utos sa isang batch ay karaniwang komportable, samantalang ang isandaang payload na maraming kilobyte ay hindi. Hatiin ayon sa bytes at ayon sa bilang, at panatilihin ang bawat batch sa loob ng latency budget na talagang mayroon ang endpoint.

Sukatin mula simula hanggang dulo pagkatapos ng pagbabago: redis-cli -h redis.example.internal --latency-history ay nagpapakita kung matatag ang landas mismo, at ang sarili mong timer ng kahilingan ay nagpapakita kung bumuti ang endpoint. Kung mabagal pa rin ang endpoint habang flat ang history ng latency, ang natitirang gastos ay trabaho sa server o ang sarili mong serialization, at ang susunod na hakbang ay profile ng handler sa halip na isa pang pagbabago sa batch.

Kaugnay na mga artikulo