Како во
Еден ден се разбудив со незадоволен е-пошта поради долги одложувања со Алвин, кој планиравме да го лансираме во блиска иднина. Поточно, клиентот доживеа доцнење од 99-ти перцентил во регионот од 50 ms, многу над нашиот буџет за латентност. Ова беше изненадувачки бидејќи ја тестирав услугата опширно, особено на латентност, што е вообичаена поплака.
Пред да го ставам Алвин на тестирање, извршив многу експерименти со 40 илјади прашања во секунда (QPS), сите покажуваа латентност помала од 10 ms. Бев подготвен да се изјаснам дека не се согласувам со нивните резултати. Но, гледајќи го уште еднаш писмото, забележав нешто ново: не ги тестирав точно условите што тие ги спомнаа, нивниот QPS беше многу понизок од мојот. Јас тестирав на 40k QPS, но тие само на 1k. Направив уште еден експеримент, овој пат со понизок QPS, само за да ги смирам.
Бидејќи блогирам за ова, веројатно веќе сте сфатиле дека нивните бројки се точни. Го тестирав мојот виртуелен клиент одново и одново, со истиот резултат: малиот број на барања не само што ја зголемува латентноста, туку го зголемува бројот на барања со латентност од повеќе од 10 ms. Со други зборови, ако при 40k QPS околу 50 барања во секунда надминувале 50 ms, тогаш при 1k QPS имало 100 барања над 50 ms секоја секунда. Парадокс!
Стеснување на пребарувањето
Кога се соочуваме со проблем со латентност во дистрибуиран систем со многу компоненти, првиот чекор е да се создаде кратка листа на осомничени. Ајде да копаме малку подлабоко во архитектурата на Алвин:
Добра почетна точка е списокот на завршени I/O транзиции (мрежни повици/пребарување на диск, итн.). Ајде да се обидеме да откриеме каде е доцнењето. Покрај очигледниот влез/излез со клиентот, Алвин презема уште еден чекор: пристапува до продавницата за податоци. Сепак, ова складирање работи во истиот кластер како и Alvin, така што латентноста таму треба да биде помала отколку кај клиентот. Значи, списокот на осомничени:
- Мрежен повик од клиент до Алвин.
- Мрежен повик од Алвин до продавницата за податоци.
- Пребарувајте на дискот во продавницата за податоци.
- Мрежен повик од складиштето на податоци до Алвин.
- Мрежен повик од Алвин до клиент.
Ајде да се обидеме да прецртаме некои точки.
Складирањето податоци нема никаква врска со тоа
Првото нешто што го направив беше да го конвертирам Алвин во пинг-пинг сервер кој не обработува барања. Кога ќе прими барање, враќа празен одговор. Ако латентноста се намали, тогаш грешката во имплементацијата на Alvin или складиштето на податоци не е ништо нечуено. Во првиот експеримент го добиваме следниот график:
Како што можете да видите, нема подобрување при користење на серверот за пинг-пинг. Ова значи дека складиштето на податоци не ја зголемува латентноста, а листата на осомничени е преполовена:
- Мрежен повик од клиент до Алвин.
- Мрежен повик од Алвин до клиент.
Одлично! Списокот брзо се намалува. Мислев дека речиси ја сфатив причината.
gRPC
Сега е време да ве запознаам со нов играч: gRPC
добро оптимизиран и широко користен, ова беше мојот прв пат да го користам на систем од оваа големина и очекував мојата имплементација да биде неоптимална - во најмала рака.
достапност gRPC
во магацинот доведе до ново прашање: можеби тоа е мојата имплементација или јас gRPC
предизвикува проблем со латентност? Додавање нов осомничен на списокот:
- Клиентот ја повикува библиотеката
gRPC
- Библиотека
gRPC
прави мрежен повик до библиотеката на клиентотgRPC
на серверот - Библиотека
gRPC
контакти Алвин (без операција во случај на пинг-понг сервер)
За да ви дадам идеја за тоа како изгледа кодот, имплементацијата на мојот клиент/Алвин не се разликува многу од оние клиент-сервер
Забелешка: Горенаведената листа е малку поедноставена затоа што
gRPC
овозможува користење на ваш сопствен (шаблон?) модел на нишки, во кој е испреплетен оџакот за извршувањеgRPC
и корисничка имплементација. Заради едноставност, ќе се задржиме на овој модел.
Профилирањето ќе поправи се
Откако ги пречкртав продавниците за податоци, помислив дека речиси сум готов: „Сега е лесно! Ајде да го примениме профилот и да дознаеме каде се случува доцнењето“. Јас
Зедов четири профили: со висок QPS (ниска латентност) и со пинг-понг сервер со низок QPS (висока латентност), и на страната на клиентот и на страната на серверот. И за секој случај, земав и примерок од профилот на процесорот. Кога ги споредувам профилите, обично барам аномален куп на повици. На пример, на лошата страна со висока латентност има многу повеќе контекстуални прекинувачи (10 пати или повеќе). Но, во мојот случај, бројот на прекинувачи на контекст беше речиси ист. За мое ужас, таму немаше ништо значајно.
Дополнително дебагирање
Бев очајна. Не знаев кои други алатки можам да ги користам, а мојот следен план беше во суштина да ги повторам експериментите со различни варијации наместо јасно да го дијагностицирам проблемот.
Што ако
Од самиот почеток, бев загрижен за специфичната латентност од 50 ms. Ова е многу големо време. Решив дека ќе исечам делови од кодот додека не можам да сфатам точно кој дел ја предизвикува оваа грешка. Потоа дојде експеримент кој успеа.
Како и обично, во ретроспектива се чини дека сè беше очигледно. Го ставив клиентот на истата машина како и Алвин - и испратив барање до localhost
. И зголемувањето на латентноста го нема!
Нешто не беше во ред со мрежата.
Учење мрежни инженерски вештини
Морам да признаам: моето знаење за мрежните технологии е страшно, особено ако се земе предвид фактот дека со нив работам секој ден. Но, мрежата беше главниот осомничен и требаше да научам како да ја дебагирам.
За среќа, Интернетот ги сака оние кои сакаат да учат. Комбинацијата на пинг и трасерт се чинеше како доволно добар почеток за дебагирање на проблемите со транспортот на мрежата.
Прво, лансирав
Потоа се обидов
Значи, не беше мојот код, имплементацијата на gRPC или мрежата што го предизвикуваше доцнењето. Почнав да се грижам дека никогаш нема да го разберам ова.
Сега на кој оперативен систем сме
gRPC
широко користен на Linux, но егзотичен на Windows. Решив да пробам експеримент, кој успеа: создадов виртуелна машина Линукс, го составив Алвин за Линукс и го распоредив.
И еве што се случи: пинг-понг серверот Линукс ги немаше истите доцнења како сличен Windows хост, иако изворот на податоци не се разликуваше. Излегува дека проблемот е во имплементацијата на gRPC за Windows.
Нагловиот алгоритам
Цело ова време мислев дека ми фали знаме gRPC
. Сега разбирам што всушност е тоа gRPC
Знамето на Windows недостасува. Најдов внатрешна RPC библиотека за која бев убеден дека ќе работи добро за сите поставени знамиња
Речиси Готово: Почнав да ги отстранувам додадените знаменца едно по едно додека не се врати регресијата за да можам точно да ја одредам причината. Тоа беше неславно
gRPC
ова знаме беше поставено во имплементацијата на Linux за TCP приклучоците, но не и во Windows. Јас сум ова
Заклучок
Поголемата доцнење при низок QPS беше предизвикана од оптимизацијата на ОС. Во ретроспектива, профилирањето не откри латентност бидејќи беше направено во режим на јадро наместо во
Што се однесува до експериментот на локалниот хост, тој веројатно не го допрел вистинскиот мрежен код и алгоритмот на Нагл не работи, така што проблемите со латентноста исчезнаа кога клиентот стигна до Алвин преку локалниот хост.
Следниот пат кога ќе видите зголемување на латентноста бидејќи бројот на барања во секунда се намалува, алгоритмот на Nagle треба да биде на вашата листа на осомничени!
Извор: www.habr.com