Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Во извештајот се претставени некои пристапи кои дозволуваат следете ја работата на SQL-пребарувањата кога има милиони од нив дневно, и има стотици набљудувани PostgreSQL сервери.

Кои технички решенија ни дозволуваат ефикасно да обработиме толкав обем на информации и како тоа го олеснува животот на обичниот програмер?


Кој е заинтересиран? анализа на конкретни проблеми и различни техники за оптимизација SQL прашања и решавање на типични DBA проблеми во PostgreSQL - исто така можете прочитајте серија написи на оваа тема.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)
Јас се викам Кирил Боровиков, застапувам Тензор компанија. Поточно, јас сум специјализиран за работа со бази на податоци во нашата компанија.

Денес ќе ви кажам како ги оптимизираме барањата, кога не треба да ги „разделите“ перформансите на едно барање, туку масовно да го решавате проблемот. Кога има милиони барања, а треба да најдете некои пристапи кон решението овој голем проблем.

Во принцип, Tensor за милион наши клиенти е VLSI е нашата апликација: корпоративна социјална мрежа, решенија за видео комуникација, за внатрешен и надворешен проток на документи, сметководствени системи за сметководство и магацини,... Односно, таков „мега-комбинат“ за интегрирано управување со бизнисот, во кој има повеќе од 100 различни внатрешни проекти.

За да се осигураме дека сите тие работат и се развиваат нормално, имаме 10 развојни центри низ целата земја, со повеќе во нив 1000 програмери.

Ние работиме со PostgreSQL од 2008 година и имаме акумулирано голема количина од она што го обработуваме - податоци за клиентите, статистички, аналитички, податоци од надворешни информациски системи - повеќе од 400 ТБ. Само во производство има околу 250 сервери, а вкупно има околу 1000 сервери за бази на податоци кои ги следиме.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

SQL е декларативен јазик. Не опишувате „како“ нешто треба да функционира, туку „што“ сакате да постигнете. DBMS знае подобро како да направи JOIN - како да ги поврзе вашите табели, какви услови да наметне, што ќе помине низ индексот, што нема...

Некои DBMS прифаќаат совети: „Не, поврзете ги овие две табели во таква и таква редица“, но PostgreSQL не може да го стори тоа. Ова е свесната позиција на водечките програмери: „Попрво ќе го завршиме оптимизатор на барања отколку да им дозволиме на програмерите да користат некакви совети“.

Но, и покрај фактот што PostgreSQL не дозволува „надворот“ да се контролира себеси, тоа совршено дозволува види што се случува во негокога го извршувате вашето барање и каде има проблеми.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Општо земено, со какви класични проблеми обично доаѓа развивачот [на DBA]? „Тука го исполнивме барањето и кај нас се е бавно, сè виси, нешто се случува... Некаква неволја!“

Причините се скоро секогаш исти:

  • неефикасен алгоритам за пребарување
    Програмер: „Сега му давам 10 табели во SQL преку JOIN...“ - и очекува дека неговите услови за чудо ќе бидат ефективно „одврзани“ и тој ќе добие сè брзо. Но чуда не се случуваат и секој систем со таква варијабилност (10 табели во една FROM) секогаш дава некаква грешка. [Член]
  • неважна статистика
    Оваа точка е многу релевантна конкретно за PostgreSQL, кога ќе „истурите“ голема база на податоци на серверот, ќе поднесете барање и ќе го „сексализирате“ вашиот таблет. Бидејќи вчера имаше 10 записи во него, а денес има 10 милиони, но PostgreSQL сè уште не е свесен за ова, и треба да го кажеме тоа. [Член]
  • „приклучете“ на ресурсите
    Инсталиравте голема и силно оптоварена база на податоци на слаб сервер кој нема доволно перформанси на диск, меморија или процесор. И тоа е сè... Некаде има плафон за изведба над кој повеќе не можете да скокате.
  • блокирање
    Ова е тешка точка, но тие се најрелевантни за различни прашања за модификација (ВНЕСЕТЕ, АЖУРИРАЈ, БРИШИ) - ова е посебна голема тема.

Добивање план

...А за се друго ние треба план! Треба да видиме што се случува внатре во серверот.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Планот за извршување на барањето за PostgreSQL е дрво на алгоритмот за извршување на барањето во претставувањето на текстот. Токму алгоритмот, како резултат на анализата на планерот, се покажа дека е најефикасен.

Секој јазол на дрво е операција: преземање податоци од табела или индекс, градење битмапа, спојување на две табели, спојување, вкрстување или исклучување на селекции. Извршувањето на барањето вклучува одење низ јазлите на ова дрво.

За да го добиете планот за барање, најлесниот начин е да ја извршите изјавата EXPLAIN. За да ги добиете сите реални атрибути, односно да извршите барање на базата - EXPLAIN (ANALYZE, BUFFERS) SELECT ....

Лошиот дел: кога го стартувате, тоа се случува „овде и сега“, така што е погоден само за локално дебагирање. Ако земете силно вчитан сервер кој е под силен проток на податоци, се менува и ќе видите: „О! Тука имаме бавно извршувањеся барање“. Пред половина час, пред еден час - додека го извршувавте и го добивавте ова барање од дневниците, враќајќи го на серверот, целата ваша база на податоци и статистика се променија. Го стартувате за дебагирање - и работи брзо! И не можете да разберете зошто, зошто беше полека.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

За да се разбере што се случило точно во моментот кога барањето било извршено на серверот, напишале паметни луѓе auto_explain модул. Присутен е во скоро сите најчести PostgreSQL дистрибуции и едноставно може да се активира во конфигурациската датотека.

Ако сфати дека некое барање работи подолго од лимитот што му го кажавте, тоа го прави „слика“ од планот на ова барање и ги запишува заедно во дневникот.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Се чини дека сè е во ред сега, одиме до дневникот и гледаме таму... [текст шапка]. Но, не можеме да кажеме ништо за тоа, освен фактот дека тоа е одличен план бидејќи беа потребни 11 ms за да се изврши.

Се чини дека сè е во ред - но ништо не е јасно што всушност се случило. Освен општото време, навистина не гледаме ништо. Затоа што гледањето во такво „јагне“ од обичен текст генерално не е визуелно.

Но, дури и ако не е очигледно, дури и ако е незгодно, постојат посуштински проблеми:

  • Јазолот покажува збир на ресурси на целото подстебло под него. Односно, не можете само да дознаете колку време е потрошено на ова конкретно скенирање на индекс ако има некоја вгнездена состојба под него. Мора динамички да гледаме дали има „деца“ и условни променливи, CTE внатре - и сето тоа да го одземеме „во нашите умови“.
  • Втора точка: времето што е означено на јазолот е време на извршување на еден јазол. Ако овој јазол бил извршен како резултат на, на пример, циклус низ записите на табелата неколку пати, тогаш бројот на циклуси - циклуси на овој јазол - се зголемува во планот. Но, самото време на атомско извршување останува исто во однос на планот. Тоа е, за да разберете колку долго се изведувал овој јазол вкупно, треба да помножите една работа со друга - повторно, „во вашата глава“.

Во такви ситуации, разберете „Која е најслабата алка? речиси невозможно. Затоа, дури и самите програмери пишуваат во „прирачникот“ дека „Разбирањето на планот е уметност што мора да се научи, да се доживее...“.

Но, имаме 1000 програмери и не можете да го пренесете ова искуство на секој од нив. Јас, ти, тој знае, но некој таму веќе не знае. Можеби ќе научи, или можеби не, но треба да работи сега - и каде би го добил ова искуство?

План визуелизација

Затоа, сфативме дека за да се справиме со овие проблеми, ни треба добра визуелизација на планот. [напис]

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Прво отидовме „низ пазарот“ - ајде да погледнеме на Интернет за да видиме што воопшто постои.

Но, се покажа дека има многу малку релативно „живи“ решенија што повеќе или помалку се развиваат - буквално, само едно: објасни.depesz.com од Хуберт Лубацевски. Кога ќе го внесете полето „feed“ текстуален приказ на планот, тој ви прикажува табела со анализирани податоци:

  • сопственото време на обработка на јазолот
  • вкупно време за целото поддрво
  • број на извадени записи кои беа статистички очекувани
  • самото тело на јазолот

Оваа услуга исто така има можност да споделува архива на врски. Ти го фрли твојот план таму и рече: „Еј, Васија, еве линк, нешто не е во ред таму“.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Но, има и мали проблеми.

Прво, огромна количина „copy-paste“. Земаш парче од трупецот, го ставаш таму, и повторно и повторно.

Второ, нема анализа на количината на прочитани податоци - истите бафери што излегуваат EXPLAIN (ANALYZE, BUFFERS), не го гледаме овде. Тој едноставно не знае како да ги расклопи, да ги разбере и да работи со нив. Кога читате многу податоци и сфаќате дека можеби погрешно ги распределувате кешот на дискот и меморијата, оваа информација е многу важна.

Третата негативна точка е многу слабиот развој на овој проект. Обврските се многу мали, добро е еднаш на секои шест месеци, а кодот е во Perl.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Но, сето ова е „стихови“, некако би можеле да живееме со ова, но има една работа што во голема мера нè оддалечи од оваа услуга. Ова се грешки во анализата на Common Table Expression (CTE) и разни динамички јазли како InitPlan/SubPlan.

Ако верувате во оваа слика, тогаш вкупното време на извршување на секој поединечен јазол е поголемо од вкупното време на извршување на целото барање. Едноставно е - времето на генерирање на овој CTE не беше одземено од јазолот CTE Scan. Затоа, повеќе не го знаеме точниот одговор на тоа колку време траело самото CTE скенирање.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Тогаш сфативме дека е време да го напишеме своето - ура! Секој развивач вели: „Сега ќе напишеме свое, ќе биде супер лесно!“

Зедовме стек типичен за веб-услуги: јадро базирано на Node.js + Express, користевме Bootstrap и D3.js за прекрасни дијаграми. И нашите очекувања беа целосно оправдани - првиот прототип го добивме за 2 недели:

  • парсер на сопствен план
    Тоа е, сега можеме да анализираме кој било план од оние генерирани од PostgreSQL.
  • правилна анализа на динамичките јазли - CTE Scan, InitPlan, SubPlan
  • анализа на дистрибуција на бафери - каде се читаат страниците со податоци од меморијата, каде од локалниот кеш, каде од дискот
  • доби јасност
    За да не го „копате“ сето ова во дневникот, туку веднаш да ја видите „најслабата алка“ на сликата.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Добивме вакво нешто, со вклучено истакнување на синтаксата. Но, обично нашите програмери повеќе не работат со целосна претстава на планот, туку со пократка. На крајот на краиштата, веќе ги анализиравме сите броеви и ги фрливме лево-десно, а во средината ја оставивме само првата линија, каков јазол е тоа: CTE Scan, CTE генерација или Seq Scan според некој знак.

Ова е скратеното претставување што го нарекуваме шаблон за план.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Што друго би било погодно? Би било погодно да се види колкав дел од нашето вкупно време е доделен на кој јазол - и само „залепете го“ на страна пита шема.

Посочуваме на јазолот и гледаме - излегува дека Seq Scan трае помалку од една четвртина од вкупното време, а преостанатите 3/4 ги презема CTE Scan. Ужас! Ова е мала забелешка за „стапката на пожар“ на CTE Scan доколку активно ги користите во вашите прашања. Тие не се многу брзи - тие се инфериорни дури и во однос на редовното скенирање на табелата. [напис] [напис]

Но, обично таквите дијаграми се поинтересни, покомплексни, кога веднаш покажуваме на некој сегмент и гледаме, на пример, дека повеќе од половина од времето некое Seq Scan „јадело“. Покрај тоа, внатре имаше некаков филтер, според него беа отфрлени многу записи... Можете директно да ја фрлите оваа слика на развивачот и да кажете: „Васија, сè е лошо овде за тебе! Дознајте, погледнете - нешто не е во ред!“

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Секако, имаше некои „гребло“ вклучени.

Првото нешто што наидовме беше проблемот со заокружувањето. Времето на секој поединечен јазол во планот е означено со точност од 1 μs. И кога бројот на циклуси на јазли надминува, на пример, 1000 - по извршувањето PostgreSQL поделен „во точноста“, тогаш кога се пресметуваме назад, го добиваме вкупното време „некаде помеѓу 0.95ms и 1.05ms“. Кога броењето оди до микросекунди, тоа е во ред, но кога е веќе [мили]секунди, треба да ги земете предвид овие информации кога ги „одврзувате“ ресурсите за јазлите на планот „кој колку потрошил“.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Втората точка, покомплексна, е распределбата на ресурсите (тие бафери) меѓу динамичните јазли. Ова не чинеше првите 2 недели од прототипот плус уште 4 недели.

Сосема е лесно да се добие ваков проблем - правиме CTE и наводно читаме нешто во него. Всушност, PostgreSQL е „паметен“ и нема да чита ништо директно таму. Потоа ја земаме првата плоча од неа, а нему сто и првата од истиот CTE.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Го гледаме планот и разбираме - чудно е, имаме 3 бафери (страници со податоци) „потрошени“ во Seq Scan, уште 1 во CTE Scan и уште 2 во второто CTE Scan. Односно, ако едноставно сумираме сè, ќе добиеме 6, но од таблетот читаме само 3! CTE Scan не чита ништо од никаде, туку работи директно со процесната меморија. Односно, овде нешто очигледно не е во ред!

Впрочем, испаѓа дека еве ги сите тие 3 страници со податоци кои се побарани од Seq Scan, прво 1 побарал 1-ви CTE Scan, а потоа 2-та и му биле прочитани уште 2. Односно, вкупно 3 страници се прочитани податоци, а не 6.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

И оваа слика нè доведе до разбирање дека извршувањето на планот повеќе не е дрво, туку едноставно некој вид ацикличен график. И добивме дијаграм како овој, за да разбереме „што на прво место од каде дојде“. Односно, овде направивме CTE од pg_class, и го побаравме двапати, и скоро цело време поминавме на филијалата кога го побаравме по 2-ри пат. Јасно е дека читањето на 101-виот запис е многу поскапо од самото читање на првиот запис од таблетот.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Издишувавме некое време. Тие рекоа: „Сега, Нео, знаеш кунг фу! Сега нашето искуство е директно на вашиот екран. Сега можете да го користите“. [напис]

Консолидација на дневникот

Нашите 1000 програмери здивнаа. Но, разбравме дека имаме само стотици „борбени“ сервери и сето ова „copy-paste“ од страна на програмерите воопшто не е погодно. Сфативме дека треба сами да го собереме.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Општо земено, постои стандарден модул што може да собира статистика, но исто така треба да се активира во конфигурацијата - ова pg_stat_statements модул. Но, тој не ни одговараше.

Прво, се доделува на истите прашања користејќи различни шеми во истата база на податоци различни QueryIds. Тоа е, ако прво го направите SET search_path = '01'; SELECT * FROM user LIMIT 1;и тогаш SET search_path = '02'; и истото барање, тогаш статистиката на овој модул ќе има различни записи и нема да можам да собирам општи статистики конкретно во контекст на овој профил на барање, без да ги земам предвид шемите.

Втората точка што не спречи да ја користиме е недостаток на планови. Односно, нема план, постои само самото барање. Гледаме што забавува, но не разбираме зошто. И тука се враќаме на проблемот на брзо менување на податоци.

И последниот момент - недостаток на „факти“. Односно, не можете да адресирате конкретен пример за извршување на барањето - нема, има само збирна статистика. Иако е можно да се работи со ова, тоа е само многу тешко.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Затоа, решивме да се бориме со copy-paste и почнавме да пишуваме колектор.

Колекторот се поврзува преку SSH, воспоставува безбедна врска со серверот со базата на податоци користејќи сертификат и tail -F „се прилепува“ на него во датотеката за евиденција. Така во оваа сесија добиваме целосно „огледало“ на целата датотека за евиденција, што го генерира серверот. Оптоварувањето на самиот сервер е минимално, бидејќи ние не анализираме ништо таму, само го пресликуваме сообраќајот.

Бидејќи веќе почнавме да го пишуваме интерфејсот во Node.js, продолживме да го пишуваме колекторот во него. И оваа технологија се оправда, бидејќи е многу погодно да се користи JavaScript за работа со слабо форматирани текстуални податоци, што е дневникот. И самата инфраструктура Node.js како платформа за заднина ви овозможува лесно и практично да работите со мрежни конекции, и навистина со какви било потоци на податоци.

Соодветно на тоа, ние „протегаме“ две врски: првата да го „слушаме“ самиот дневник и да го однесеме кај себе, а втората периодично да ја прашуваме основата. „Но, дневникот покажува дека знакот со oid 123 е блокиран“, но ова не значи ништо за развивачот и би било убаво да се праша базата на податоци: „Што е OID = 123 во секој случај? И затоа, периодично ја прашуваме основата она што сè уште не го знаеме за себе.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

„Постои само една работа што не ја зедовте во предвид, има еден вид пчели слични на слон!...“ Почнавме да го развиваме овој систем кога сакавме да надгледуваме 10 сервери. Најкритично во нашето разбирање, каде што се појавија некои проблеми со кои беше тешко да се справиме. Но, во текот на првиот квартал, добивме стотина за следење - затоа што системот функционираше, сите го сакаа тоа, на сите им беше удобно.

Сето ова треба да се собере, протокот на податоци е голем и активен. Всушност, она што го следиме, со што можеме да се справиме е она што го користиме. Ние исто така користиме PostgreSQL како складирање на податоци. И ништо не е побрзо да ги „истури“ податоците во него од операторот COPY Не сеуште.

Но, едноставното „истурање“ податоци не е навистина наша технологија. Затоа што ако имате приближно 50 илјади барања во секунда на сто сервери, тогаш ова ќе генерира 100-150 GB дневници дневно. Затоа, моравме внимателно да ја „пресечеме“ основата.

Прво, направивме поделба по ден, затоа што, во голема мера, никој не го интересира корелацијата помеѓу деновите. Каква разлика е она што го имавте вчера, ако вечерва објавивте нова верзија на апликацијата - и веќе некоја нова статистика.

Второ, научивме (бивме принудени) многу, многу брзо за пишување со користење COPY. Тоа е, не само COPYбидејќи тој е побрз од INSERT, па дури и побрзо.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Третата точка - морав напуштете ги предизвикувачите, соодветно, и странските клучеви. Односно, ние воопшто немаме референтен интегритет. Затоа што ако имате табела што има пар FK и велите во структурата на базата на податоци дека „тука е запис од дневник кој е референциран од FK, на пример, на група записи“, тогаш кога ќе го вметнете, PostgreSQL нема ништо друго освен како да го земе и да го направи тоа искрено SELECT 1 FROM master_fk1_table WHERE ... со идентификаторот што се обидувате да го вметнете - само за да проверите дали овој запис е присутен таму, да не го „откинете“ овој странски клуч со вашето вметнување.

Наместо еден запис во целната табела и нејзините индекси, ја добиваме дополнителната придобивка од читање од сите табели на кои се однесува. Но, ова воопшто не ни треба - нашата задача е да снимаме што е можно повеќе и што е можно побрзо со најмало оптоварување. Значи ФК - долу!

Следната точка е собирање и хаширање. Првично, ги имплементиравме во базата на податоци - на крајот на краиштата, погодно е веднаш, кога ќе пристигне записот, да се направи тоа во некој вид таблет „плус еден“ веднаш во чкрапалото. Па, погодно е, но истото лошо - вметнувате еден запис, но сте принудени да читате и пишувате нешто друго од друга табела. Згора на тоа, не само што читате и пишувате, туку тоа го правите и секој пат.

Сега замислете дека имате табела во која едноставно го броите бројот на барања што поминале низ одреден домаќин: +1, +1, +1, ..., +1. И, во принцип, не ви треба ова - се е можно сума во меморија на колекторот и испратете до базата на податоци со едно движење +10.

Да, во случај на некои проблеми, вашиот логички интегритет може да се „распадне“, но ова е речиси нереален случај - затоа што имате нормален сервер, има батерија во контролорот, имате дневник за трансакции, дневник на датотечен систем... Во принцип, не вреди. Загубата на продуктивноста што ја добивате од активирањето на тригерите/FK не вреди за трошоците што ги правите.

Исто е и со хаширањето. Ти лета одредено барање, од него пресметуваш одреден идентификатор во базата, го пишуваш во базата и потоа го кажуваш на сите. Сè е во ред додека во моментот на снимање не дојде кај вас второ лице кое сака да го сними истото - и вие бидете блокирани, а ова е веќе лошо. Затоа, ако можете да го пренесете генерирањето на некои ИД на клиентот (во однос на базата на податоци), подобро е да го направите ова.

Едноставно ни беше совршено да користиме MD5 од текстот - барање, план, шаблон,... Го пресметуваме на колекторската страна, и го „истураме“ готовиот ID во базата. Должината на MD5 и дневното преградување ни овозможуваат да не се грижиме за можни судири.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Но, за сето ова брзо да го снимиме, требаше да ја измениме самата процедура за снимање.

Како обично пишувате податоци? Имаме некој вид база на податоци, го делиме на неколку табели, а потоа КОПИРАЈТЕ го - прво во првата, потоа во втората, во третата... Незгодно е, бидејќи се чини дека пишуваме еден поток на податоци во три чекори последователно. Непријатни. Дали може да се направи побрзо? Може!

За да го направите ова, доволно е само да ги разложите овие текови паралелно едни со други. Излегува дека имаме грешки, барања, шаблони, блокирања, ... летаат во посебни нишки - и сето тоа го пишуваме паралелно. Доволно за ова чувајте го каналот COPY постојано отворен за секоја поединечна целна табела.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Односно кај колекторот секогаш има поток, во кој можам да ги запишам податоците што ми се потребни. Но, за базата да ги види овие податоци и некој да не се заглави чекајќи да се напишат овие податоци, COPY мора да се прекинува во одредени интервали. За нас, најефективниот период беше околу 100 ms - го затвораме и веднаш го отвораме повторно на истата маса. И ако немаме доволно еден проток за време на некои врвови, тогаш правиме здружување до одредена граница.

Дополнително, дознавме дека за таков профил на оптоварување, секоја агрегација, кога записите се собираат во серии, е зло. Класично зло е INSERT ... VALUES и уште 1000 записи. Затоа што во тој момент имате пик за пишување на медиумите, а сите други што се обидуваат да напишат нешто на дискот ќе чекаат.

За да се ослободите од таквите аномалии, едноставно не собирајте ништо, воопшто не тампонирајте. И ако се случи баферирање на дискот (за среќа, Stream API во Node.js ви овозможува да дознаете) - одложете ја оваа врска. Кога повторно ќе примите некој настан дека е бесплатен, пишете му од акумулираната редица. И додека е зафатено, земете го следниот бесплатен од базенот и пишете му.

Пред да го воведеме овој пристап за снимање податоци, имавме приближно 4K описи за запишување и на овој начин го намаливме оптоварувањето за 4 пати. Сега тие пораснаа уште 6 пати поради новите мониторирани бази на податоци - до 100MB/s. И сега ги складираме дневниците за последните 3 месеци во волумен од околу 10-15 TB, надевајќи се дека за само три месеци секој развивач ќе може да реши каков било проблем.

Ги разбираме проблемите

Но, едноставно собирањето на сите овие податоци е добро, корисно, релевантно, но не е доволно - треба да се разбере. Затоа што тоа се милиони различни планови дневно.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Но, милиони се неуправливи, прво мора да направиме „помали“. И, пред сè, треба да одлучите како ќе ја организирате оваа „помала“ работа.

Идентификувавме три клучни точки:

  • кој го испрати ова барање
    Односно, од која апликација „пристигна“: веб-интерфејс, заднина, систем за плаќање или нешто друго.
  • каде што тоа се случи
    На кој конкретен сервер? Затоа што ако имате неколку сервери под една апликација, и одеднаш еден „оглупува“ (бидејќи „дискот е скапан“, „протече меморија“, некој друг проблем), тогаш треба конкретно да му се обратите на серверот.
  • како проблемот се манифестираше на еден или друг начин

За да разбереме „кој“ ни испрати барање, користиме стандардна алатка - поставување променлива за сесија: SET application_name = '{bl-host}:{bl-method}'; — го испраќаме името на домаќинот за деловна логика од кој доаѓа барањето и името на методот или апликацијата што го иницирала.

Откако ќе го поминеме „сопственикот“ на барањето, тоа мора да биде излезено во дневникот - за ова ја конфигурираме променливата log_line_prefix = ' %m [%p:%v] [%d] %r %a'. Кој се грижи, можеби погледнете во прирачникотшто значи сето тоа. Излегува дека гледаме во дневникот:

  • време
  • идентификатори на процеси и трансакции
  • име на базата на податоци
  • IP на лицето кое го испратило ова барање
  • и името на методот

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Тогаш сфативме дека не е многу интересно да се погледне корелацијата за едно барање помеѓу различни сервери. Не се случува често да имате ситуација кога една апликација се завртува подеднакво овде и таму. Но, дури и ако е исто, погледнете кој било од овие сервери.

Значи, тука е намалувањето "еден сервер - еден ден" ни се покажа доволно за каква било анализа.

Првиот аналитички дел е ист "пример" - скратена форма на презентација на планот, исчистена од сите нумерички показатели. Вториот пресек е апликацијата или методот, а третиот пресек е конкретниот плански јазол што ни предизвика проблеми.

Кога се преселивме од конкретни примери на шаблони, добивме две предности одеднаш:

  • повеќекратно намалување на бројот на предмети за анализа
    Мораме да го анализираме проблемот не повеќе со илјадници прашања или планови, туку со десетици шаблони.
  • времеплов
    Односно, со сумирање на „фактите“ во одреден дел, можете да го прикажете нивниот изглед во текот на денот. И тука можете да разберете дека ако имате некаков образец што се случува, на пример, еднаш на час, но треба да се случува еднаш дневно, треба да размислите што тргнало наопаку - кој го предизвикал и зошто, можеби треба да биде тука не треба. Ова е уште еден ненумерички, чисто визуелен, метод на анализа.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Останатите методи се засноваат на индикаторите што ги извлекуваме од планот: колку пати се случила таква шема, вкупното и просечното време, колку податоци се прочитани од дискот и колку од меморијата...

Бидејќи, на пример, доаѓате на страницата за аналитика за домаќинот, погледнете - нешто почнува да чита премногу на дискот. Дискот на серверот не може да се справи - кој чита од него?

И можете да сортирате по која било колона и да одлучите со што ќе се занимавате во моментов - оптоварувањето на процесорот или дискот или вкупниот број на барања... Го подредивме, ги разгледавме „горните“, го поправивме и претстави нова верзија на апликацијата.
[видео предавање]

И веднаш можете да видите различни апликации кои доаѓаат со ист шаблон од барање како SELECT * FROM users WHERE login = 'Vasya'. Frontend, backend, processing... И се прашувате зошто обработката би го читала корисникот ако тој не комуницира со него.

Обратен начин е веднаш да се види од апликацијата што прави. На пример, предниот дел е ова, ова, ова и ова еднаш на час (временската линија помага). И веднаш се поставува прашањето: се чини дека не е работа на фронтендот да прави нешто еднаш на час...

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

По некое време сфативме дека ни недостига агрегирана статистика по јазли на планот. Од плановите ги изолиравме само оние јазли кои прават нешто со податоците од самите табели (ги читаат/пишуваат по индекс или не). Всушност, само еден аспект е додаден во однос на претходната слика - колку записи ни донесе овој јазол?, и колку беа отфрлени (Редови отстранети со филтер).

Немате соодветен индекс на плочата, барате до него, лета покрај индексот, паѓа во Seq Scan... ги филтриравте сите записи освен еден. Зошто ви се потребни 100 милиони филтрирани записи дневно? Зарем не е подобро да го навивате индексот?

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Откако ги анализиравме сите планови јазол по јазол, сфативме дека има некои типични структури во плановите кои многу веројатно ќе изгледаат сомнително. И би било убаво да му кажете на развивачот: „Пријателе, овде прво читате по индекс, потоа сортирате, а потоа отсечете“ - по правило, има еден запис.

Секој што пишувал прашања веројатно наишол на оваа шема: „Дајте ми ја последната нарачка за Vasya, нејзиниот датум.“ И ако немате индекс по датум или нема датум во индексот што го користевте, тогаш ќе стапнете на истото „гребло“ .

Но, знаеме дека ова е „гребло“ - па зошто веднаш да не му кажете на развивачот што треба да направи. Според тоа, кога отвораме план сега, нашиот програмер веднаш гледа убава слика со совети, каде што веднаш му велат: „Имаш проблеми овде и таму, но тие се решаваат вака и онака“.

Како резултат на тоа, количината на искуство што беше потребно за да се решат проблемите на почетокот и сега значително се намали. Ова е вид на алатка што ја имаме.

Масовна оптимизација на прашањата PostgreSQL. Кирил Боровиков (Тензор)

Извор: www.habr.com

Додадете коментар