Redis праз VPN здаецца павольным: скарачаем кругавыя абмены на запыт
VPN не робіць аддалены выклік Redis лакальным. Плануйце кругавыя абмены на запыт, паўторна выкарыстоўвайце злучэнні і трымайце канвееры далей ад транзакцый.
Старонка, якая адказвае за 200 мс пры лакальным Redis, пасля размяшчэння кліента за VPN патрабуе чатыры секунды, а лічыльнікі сервера застаюцца пустымі. Павольны журнал не паказвае нічога вышэй за мілісекунду, графік CPU плоскі, і інстанцыя без скаргаў абслугоўвае іншых кліентаў. Змянілася адлегласць, а тое, што памнажае адлегласць, — колькасць разоў, калі ваш код спыняецца і чакае. Прайдзіце шлях запыту ад кліента вонкі, і рашэнне амаль заўсёды — менш паслядоўных чаканняў, а не хутчэйшы сервер.
Пачынайце з кліента, а не з метрык сервера
Назірайце за працэсам кліента паміж першай камандай і апошняй. Калі трасіроўка паказвае адказ, паўзу, а затым наступную каманду, вы плаціце поўны кругавы абмен за кожную каманду, і ніякая наладка сервера гэтага не зменіць. Павольны журнал тут — няправільны інструмент, бо ён фіксуе час выканання і наўмысна выключае камунікацыйны ўвод/вывад. Чысты павольны журнал побач з павольнай канчатковай кропкай — гэта подпіс праблемы кругавых абменаў.
Вымерайце сам шлях, перш чым кранаць код. redis-cli -h redis.example.internal --latency дасылае паўторныя PING-і і друкуе сярэдні час запыту і адказу, што і ёсць ваш кошт за адзін абмен. Памножце яго на колькасць паслядоўных каманд у адным дзеянні карыстальніка — і атрымаеце ніжнюю мяжу для канчатковай кропкі.
Падлічыце, колькі кругавых абменаў насамрэч патрабуе адно дзеянне карыстальніка
Вазьміце адну канчатковую кропку і выпішыце кожны выклік Redis па парадку, уключаючы тыя, што схаваныя ў ORM, прамежкавым ПЗ сесіі або пошуку сцяжка функцыі. Большасць павольных канчатковых кропак робіць дваццаць або трыццаць выклікаў там, дзе хапіла б трох, і схаваныя звычайна складаюць большасць.
Ланцуг залежнасцей нельга сціснуць: калі другой камандзе патрэбны ключ, вернуты першай, чаканне рэальнае, і адзіныя варыянты — іншая мадэль даных або серверная аперацыя, якая выражае ўвесь крок адразу. Незалежныя чытанні — іншая справа, бо нішто не прымушае чакаць першага адказу, перш чым адправіць другі. Пазначце кожны выклік як залежны або незалежны да любых праўк, і форма рашэння стане відавочнай.
Важная лічба — паслядоўныя чаканні, а не агульная колькасць каманд. Трыццаць каманд у адной порцыі ўсё роўна каштуюць аднаго чакання.
Аб'ядноўвайце ў порцыю толькі каманды, якія не залежаць адна ад адной
Канвеер ставіць у чаргу незалежныя каманды і збірае адказы па парадку, ператвараючы N чаканняў у адно. Большасць кліентаў прапануюць гэта як блок, зваротны выклік або кантэкстны менеджар, а не як асобны рэжым злучэння, таму праверце API, які пастаўляецца вашай усталяванай версіяй. Выгада маштабуецца з часам кругавога абмену — менавіта таму яна важная на VPN і амаль не прыкметная на 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())
Перадайце transaction=False, калі вам патрэбна толькі аб'яднанне ў порцыю. Пры стандартных наладах кліент заварочвае порцыю ў MULTI і EXEC, што робіць яе атамнай і змяняе тое, што іншыя кліенты могуць назіраць падчас выканання. Атамнасць — гэта рашэнне пра карэктнасць, а не рычаг прадукцыйнасці, і канвеер не з'яўляецца транзакцыяй толькі таму, што абодва скарачаюць кругавыя абмены.
Чытайце кожны адказ, а не толькі адпраўку порцыі. Каманда ў чарзе можа вярнуць памылку, пакуль порцыя ў цэлым завяршаецца, і кліент, які адкідвае спіс адказаў, ператварае няўдалы запіс у маўклівы. Параўнайце даўжыню спісу адказаў з колькасцю каманд, якія вы паставілі ў чаргу.
Трымайце злучэнне жывым паміж дзеяннямі
Кожнае новае злучэнне плаціць за развязанне імён, рукапоціск TCP, рукапоціск TLS і AUTH, а праз VPN кожнае з гэтага — кругавы абмен, які нельга аб'яднаць. Стварайце кліент адзін раз на працэс і выкарыстоўвайце паўторна або бярыце пул, які дае ваша бібліятэка, з абмежаваным памерам. Перападключэнне на кожны запыт — другая па распаўсюджанасці прычына гэтага сімптому пасля чаканняў на каманду.
Трымайце прыватнае імя хаста ў канфігурацыі, а не літаральны адрас. Праверка сертыфіката і ідэнтычнасць службы ўсё яшчэ дзейнічаюць у прыватнай сетцы, а замацаванне IP ламаецца ў той момант, калі правайдэр перанумароўвае падсетку. Калі павольная частка — развязанне імён, выпраўце шлях рэзалвера, а не радок злучэння.
Задайце яўны тайм-аўт сокета, каб застылы тунель хутка збойваў, а не падвешваў працоўніка. Затым пацвердзіце, што пул сапраўды выкарыстоўваецца паўторна, запісваючы стварэнне злучэнняў у кліенце.
Памер порцыі — да таго, як яна стане праблемай памяці
Redis трымае адказы ў чарзе на працягу ўсёй порцыі, а кліент потым трымае разабраны вынік. Канвеер з дзесяці тысяч буйных значэнняў абменьвае сеткавыя чаканні на ўсплёскі памяці і доўгія паўзы з абодвух бакоў.
Выбірайце памер порцыі па аб'ёме адказу, а не па колькасці каманд. Некалькі сотняў дробных каманд у адной порцыі звычайна камфортныя, а сотня шматкілабайтных нагрузак — не. Дзяліце па байтах і па колькасці, і трымайце кожную порцыю ў межах бюджэту затрымкі, які канчатковая кропка рэальна мае.
Вымерайце ад пачатку да канца пасля змены: redis-cli -h redis.example.internal --latency-history паказвае, ці стабільны сам шлях, а ваш уласны таймер запыту — ці палепшылася канчатковая кропка. Калі канчатковая кропка ўсё яшчэ павольная, а гісторыя затрымкі плоская, рэшткавы кошт — гэта праца на баку сервера або ваша ўласная серыялізацыя, і наступны крок — профіль апрацоўшчыка, а не чарговая змена аб'яднання.