PostgreSQL е една от най-популярните бази данни с отворен код в света и има успешни имплементации в няколко критични за мисия среди в различни домейни, използвайки висококачествени OLTP приложения в реално време, извършващи милиони и милиарди транзакции на ден. PostgreSQL I/O е доста надежден, стабилен и производителен на почти всеки хардуер, включително дори в облак.
За да се гарантира, че базите данни работят в очаквания мащаб с очаквано време за реакция, има нужда от известно инженерство на производителността. Е, постигането на добра производителност на базата данни зависи от различни фактори. Производителността на базата данни може да се влоши поради различни причини, като например оразмеряване на инфраструктурата, неефективна стратегия за поддръжка на база данни, лош SQL код или лошо конфигурирани процеси на база данни, които не успяват да използват всички налични ресурси - процесор, памет, мрежова честотна лента и дисков вход/изход.
Какво може да причини влошаване на производителността на базата данни?
- Зле написани заявки с лоши съединения, логика и т.н., които отнемат много процесор и памет
- Заявки, извършващи пълно сканиране на таблици на големи таблици поради неправилно индексиране
- Лоша поддръжка на базата данни без подходяща статистика
- Неефективно планиране на капацитета, което води до неадекватно оразмерена инфраструктура
- Неправилен логически и физически дизайн
- Няма обединение на връзки, което кара приложенията да правят огромен брой връзки по неконтролируем начин
Така че това са много потенциални области, които могат да причинят проблеми с производителността. Една от значимите области, върху които бих искал да се съсредоточа в този блог, е как да настроите PostgreSQL I/O (Input/Out) производителност. Настройката на входно/изходните операции на PostgreSQL е от съществено значение, особено в среда с високи транзакции като OLTP или в среда за съхранение на данни със сложен анализ на данни върху масиви от данни с огромен размер.
В повечето случаи проблемите с производителността на базата данни се дължат главно на високо ниво на I/O. Това означава, че процесите на база данни прекарват повече време в запис или четене от диска. Всяка операция с данни в реално време е свързана с I/O, наложително е да се гарантира, че базата данни е I/O настроена. В този блог ще се съсредоточа върху често срещаните I/O проблеми, които PostgreSQL бази данни могат да срещнат в производствени среди в реално време.
Настройка на PostgreSQL I/O
Настройката на PostgreSQL I/O е наложителна за изграждането на високопроизводителна и мащабируема архитектура на база данни. Нека разгледаме различни фактори, влияещи върху I/O производителността:
- Индексиране
- Разделяне на дялове
- Пропускателни пунктове
- ВАКУУМ, АНАЛИЗ (с FILLFACTOR)
- Други I/O проблеми
- PostgreSQL I/O в облак
- Инструменти
Индексиране
Индексирането е една от основните техники за настройка, която играе наложителна роля за подобряване на I/O производителността на базата данни. Това наистина се отнася за всяка база данни. PostgreSQL поддържа различни типове индекси, които могат да ускорят операциите за четене до голяма степен, осигурявайки подобрена мащабируемост на приложенията. Въпреки че създаването на индекси е доста просто и лесно, от съществено значение е администраторите на база данни и разработчиците да знаят какъв тип индекс да изберат и за какви колони. Последното се основава на различни фактори като сложност на заявката, тип данни, мощност на данните, обем на записвания, размер на данните, архитектура на диска, инфраструктура (публичен облак, частен облак или локален) и др.
Докато индексирането може драстично да подобри производителността на четене на заявка, то може също да забави записите, удрящи индексираните колони. Нека разгледаме един пример:
Влияние на индексите върху операциите READ
Таблица, наречена emp с около 1 милион реда.
ЧЕТЕТЕ изпълнение без индекс
postgres=# select * from emp where eid=10;
eid | ename | peid | did | doj
-----+---------------+--------+------+------------
10 | emp | | 1 | 2018-06-06
(1 row)
Time: 70.020 ms => took about 70+ milli-seconds to respond with on row
ЧЕТЕТЕ изпълнение с индекс
Нека поставим индекс на колоната eid и да видим разликата
postgres=# create index indx001 on emp ( eid );
CREATE INDEX
postgres=# select * from emp where eid=10;
eid | ename | peid | did | doj
------+-------------+-------+------+------------
10 | emp | | 1 | 2018-06-06
(1 row)
Time: 0.454 ms => 0.4+ milli-seconds!!! thats a huge difference - isn’t it?
И така, индексирането е важно.
Влияние на индексите върху операциите WRITE
Индексите забавят производителността на запис. Въпреки че индексите оказват влияние върху всички видове операции за запис, нека разгледаме някакъв анализ на въздействието на индексите върху INSERT
Вмъкване на 1 милион реда в таблица без индекси
postgres=# do $$
postgres$# declare
postgres$# i integer;
postgres$# begin
postgres$# for i in 1..1000000 loop
postgres$# insert into emp values (i,'emp',null,1,current_date);
postgres$# end loop;
postgres$# end $$;
DO
Time: 4818.470 ms (00:04.818) => Takes about 4.8 seconds
Вмъкване на същите 1 милион реда с индекс
Нека първо създадем индекс
postgres=# create index indx001 on emp ( eid );
CREATE INDEX
postgres=# do $$
postgres$# declare
postgres$# i integer;
postgres$# begin
postgres$# for i in 1..1000000 loop
postgres$# insert into emp values (i,'emp',null,1,current_date);
postgres$# end loop;
postgres$# end $$;
DO
Time: 7825.494 ms (00:07.825) => Takes about 7.8 seconds
Така че, както можем да наблюдаваме, времето INSERT се е увеличило с 80% само с един индекс и може да отнеме много повече време за завършване, когато има множество индекси. Може да стане още по-лошо, когато има индекси, базирани на функции. Това е, с което DBA трябва да живеят! Индексите ще увеличат производителността на запис. Въпреки това има начини за справяне с този проблем, който зависи от архитектурата на диска. Ако сървърът на база данни използва множество дискови файлови системи, тогава индексите и таблиците могат да бъдат поставени в множество пространства за таблици, разположени в множество дискови файлови системи. По този начин може да се постигне по-добра I/O производителност.
СЪВЕТИ за управление на индекси
- Разберете необходимостта от индекси. Интелигентното индексиране е от ключово значение.
- Избягвайте да създавате множество индекси и определено без ненужни индекси, това наистина може да влоши производителността на запис.
- Наблюдавайте използването на индекси и махнете всички неизползвани индекси.
- Когато индексираните колони са подложени на промени в данните, индексите също се раздуват. Така че редовно реорганизирайте индексите.
Разделяне на дялове
Една ефективна стратегия за разделяне може да намали до голяма степен проблемите с I/O производителността. Големите таблици могат да бъдат разделени въз основа на бизнес логиката. PostgreSQL поддържа разделяне на таблици. Въпреки че не поддържа напълно всички функции в момента, той може да помогне само с някои от случаите на използване в реално време. В PostgreSQL, разделените дъщерни таблици са напълно индивидуални спрямо главната таблица, което е пречка. Например, ограниченията, създадени в главната таблица, не могат да бъдат наследени автоматично към дъщерните таблици.
Въпреки това, от гледна точка на балансиране на I/O, разделянето може наистина да помогне. Всички дъщерни дялове могат да бъдат разделени на множество пространства за таблици и дискови файлови системи. Заявките с диапазон от дати в клаузата „където“, попадащи в таблицата, разделени въз основа на период от време, могат да се възползват от разделянето, като просто сканират един или два дяла вместо цялата таблица.
Контролен пункт
Контролните точки определят последователното състояние на базата данни. Те са критични и е важно контролните точки да се появяват достатъчно редовно, за да се гарантира, че промените в данните се запазват постоянно на диск и базата данни е в постоянно състояние. Като се има предвид това, неправилната конфигурация на контролните точки може да доведе до проблеми с I/O производителността. DBA трябва да бъдат внимателни при конфигурирането на контролни точки, за да гарантират, че няма скок на I/O, а също така това зависи от това колко добри са дисковете и колко добре е архитектирано оформлението на файловете с данни.
Какво прави контролната точка?
Казано по-просто, контролните точки ще гарантират:
- Всички въведени данни се записват във файловете с данни на диска.
- запушените файлове се актуализират със състояние на записване.
- Регистрационните файлове на транзакциите в директорията pg_xlog (сега pg_wal) се рециклират.
Това обяснява как са I/O интензивните контролни точки. В postgresql.conf има параметри, които могат да бъдат конфигурирани/настроени да контролират поведението на контролната точка и тези параметри са max_wal_size, min_wal_size, checkpoint_timeout и checkpoint_completion_target. Тези параметри ще решат колко често трябва да се появяват контролните точки и в рамките на колко време трябва да завършат контролните точки.
Как да разбера коя конфигурация е по-добра за контролни точки? Как да ги настроите?
Ето няколко съвета:
- Оценете TPS на базата данни. Оценете общия обем на транзакциите, извършвани в базата данни за един работен ден, и също така установете в кое време най-голям брой транзакции попадат в базата данни.
- Обсъждайте редовно с разработчиците на приложения и други технически екипи, за да разберете статистиката за скоростта на транзакциите в базата данни, както и бъдещия растеж на транзакциите.
- Това може да се направи и от края на базата данни:
-
Наблюдавайте базата данни и оценявайте броя на транзакциите, извършвани през деня. Това може да стане чрез запитване на pgcatalog таблици като pg_stat_user_tables.
-
Оценете броя на генерираните wal архивни файлове на ден
-
Наблюдавайте, за да разберете как се представят контролните точки, като активирате параметъра log_checkpoints
2018-06-06 15:03:16.446 IST [2111] LOG: checkpoint starting: xlog 2018-06-06 15:03:22.734 IST [2111] LOG: checkpoint complete: wrote 12112 buffers (73.9%); 0 WAL file(s) added, 0 removed, 25 recycled; write=6.058 s, sync=0.218 s, total=6.287 s; sync files=4, longest=0.178 s, average=0.054 s; distance=409706 kB, estimate=412479 kB
-
Разберете дали текущата конфигурация на контролната точка е достатъчно добра за базата данни. Конфигурирайте параметъра checkpoint_warning (по подразбиране конфигуриран на 30 секунди), за да видите предупрежденията по-долу в регистрационните файлове на postgres.
2018-06-06 15:02:42.295 IST [2111] LOG: checkpoints are occurring too frequently (11 seconds apart) 2018-06-06 15:02:42.295 IST [2111] HINT: Consider increasing the configuration parameter "max_wal_size".
-
Какво означава горното предупреждение?
Контролните точки обикновено се появяват всеки път, когато max_wal_size (1 GB по подразбиране, което означава 64 WAL файла) стойността на лог файловете се запълват или когато се достигне checkpoint_timeout (на всеки 5 минути по подразбиране). Горното предупреждение означава, че конфигурираният max_wal_size не е адекватен и контролните точки се появяват на всеки 11 секунди, което на свой ред означава, че 64 WAL файла в директорията PG_WAL се запълват само за 11 секунди, което е твърде често. С други думи, ако има по-малко чести транзакции, тогава контролните точки ще се появяват на всеки 5 минути. Така че, както подсказва съветът, увеличете параметъра max_wal_size до по-висока стойност, параметърът max_min_size може да бъде увеличен до същия или по-малък от предишния.
Друг критичен параметър, който трябва да се вземе предвид от гледна точка на I/O производителността, е checkpoint_completion_target, който по подразбиране е конфигуриран на 0.5.
checkpoint_completion_target =0,5 x checkpoint_timeout =2,5 минути
Това означава, че контролните точки имат 2,5 минути, за да синхронизират мръсните блокове с диска. Достатъчни ли са 2,5 минути? Това трябва да се оцени. Ако броят на мръсните блокове, които трябва да бъдат записани, е много голям, тогава 2,5 минути може да изглеждат много много агресивни и тогава може да се наблюдава скок на I/O. Конфигурирането на параметъра completion_target трябва да се извърши въз основа на стойностите max_wal_size и checkpoint_timeout. Ако тези параметри са повишени до по-висока стойност, помислете за съответно повишаване на checkpoint_completion_target.
ВАКУУМ, АНАЛИЗ (с FILLFACTOR)
VACUUM е една от най-мощните функции на PostgreSQL. Може да се използва за премахване на раздуване (фрагментирано пространство) в таблици и индекси и се генерира от транзакции. Базата данни трябва да се подлага редовно на VACUUMING, за да се осигури здравословна поддръжка и по-добра производителност. Отново, нередовното почистване на базата данни може да доведе до сериозни проблеми с производителността. ANALYZE трябва да се извърши заедно с VACUUM (VACUUM ANALYZE), за да се гарантират актуални статистически данни за планирането на заявки.
ВАКУУМНИЯ АНАЛИЗ може да се извърши по два начина:ръчен, автоматичен или и двата. В производствена среда в реално време обикновено е и двете. Автоматичният ВАКУУМ се активира от параметъра “autovacuum”, който по подразбиране е конфигуриран на “on”. С активирано автоматично вакуумиране, PostgreSQL автоматично започва периодично да VACUUMING таблиците. Масите кандидати, които се нуждаят от вакуумиране, се улавят от процеси на автоматично вакуумиране на базата на различни прагове, зададени от различни параметри на автоматично вакуумиране*, тези параметри могат да бъдат настроени/настроени, за да се гарантира, че раздуването на масите се изчиства периодично. Нека разгледаме някои параметри и тяхното използване -
Параметри за автоматично вакуумиране
autovacuum=on | Този параметър се използва за активиране/деактивиране на автоматично вакуумиране. По подразбиране е „включено“. |
log_autovacuum_min_duration =-1 | Регистрира продължителността на процеса на автоматично вакуумиране. Това е важно, за да разберете колко време е работил процесът на автоматично вакуумиране. |
autovacuum_max_workers =3 | Брой необходими процеси за автоматично вакуумиране. Това зависи от това колко агресивни са транзакциите в базата данни и колко процесора можете да предложите за процеси на автоматично вакуумиране. |
autovacuum_naptime =1 мин. | Време за почивка на автоматично вакуумиране между автоматичното вакуумиране. |
Параметри, определящи прага за стартиране на процеса на автоматично вакуумиране
Автовакуумната(ите) работа(и) започват при достигане на определен праг. По-долу са параметрите, които могат да се използват за задаване на определен праг, въз основа на който ще започне процесът на автоматично вакуумиране.
autovacuum_vacuum_threshold =50 | Таблицата ще бъде изчистена, когато минимум 50 реда бъдат актуализирани/изтрити в таблица. |
autovacuum_analyze_threshold =50 | Таблицата ще бъде анализирана, когато минимум 50 реда бъдат актуализирани/изтрити в таблица. |
autovacuum_vacuum_scale_factor =0,2 | Таблицата ще бъде изчистена, когато минимум 20% от редовете бъдат актуализирани/изтрити в таблица. |
autovacuum_analyze_scale_factor =0,1 | Таблицата ще бъде изчистена, когато минимум 10% от редовете бъдат актуализирани/изтрити в таблица. |
Параметрите над прага могат да бъдат модифицирани въз основа на поведението на базата данни. DBA ще трябва да анализират и идентифицират горещите таблици и да гарантират, че тези таблици се вакуумират възможно най-често, за да осигурят добра производителност. Постигането на определена стойност за тези параметри може да бъде предизвикателство в среда с много транзакции, при която промените в данните се случват всяка секунда. Много пъти забелязах, че процесите на автовакуум отнемат доста време за завършване, като в крайна сметка изразходват твърде много ресурси в производствените системи.
Бих предложил да не зависи изцяло от процеса на автоматично вакуумиране, най-добрият начин е да планирате ежедневна работа VACUUM ANALYZE, така че тежестта на автоматичното вакуумиране да бъде намалена. За да започнете, помислете за ръчно почистване на големи маси с висок процент на транзакции.
ВАКУУМ ПЪЛЕН
VACUUM FULL помага да се възстанови раздуто пространство в таблиците и индексите. Тази помощна програма не може да се използва, когато базата данни е онлайн, тъй като заключва таблицата. Таблиците трябва да бъдат подложени на ВАКУУМ ПЪЛЕН само когато приложенията са изключени. Индексите също ще бъдат реорганизирани заедно с таблиците по време на VACUUM FULL.
Нека да разгледаме въздействието на ВАКУУМЕН АНАЛИЗ
Подутие:Как да разпознаем подуване? Кога се генерират подуване?
Ето няколко теста:
Имам таблица с размер 1 GB с 10 милиона реда.
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
----------------
1
postgres=# select count(*) From pgbench_accounts ;
count
-----------------
10000000
Нека разгледаме влиянието на раздуването върху проста заявка:изберете * от pgbench_accounts;
По-долу е обясненият план за заявката:
postgres=# explain analyze select * from pgbench_accounts;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on pgbench_accounts (cost=0.00..263935.00 rows=10000000 width=97)
(actual time=0.033..1054.257 rows=10000000 loops=1)
Planning time: 0.255 ms
Execution time: 1494.448 ms
Сега нека актуализираме всички редове в таблицата и да видим въздействието на горната заявка SELECT.
postgres=# update pgbench_accounts set abalance=1;
UPDATE 10000000
postgres=# select count(*) From pgbench_accounts ;
count
-----------------
10000000
По-долу е ОБЯСНИТЕЛЕН ПЛАН на изпълнението на заявката след АКТУАЛИЗИРАНЕ.
postgres=# explain analyze select * from pgbench_accounts;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on pgbench_accounts (cost=0.00..527868.39 rows=19999939 width=97)
(actual time=404.474..1520.175 rows=10000000 loops=1)
Planning time: 0.051 ms
Execution time: 1958.532 ms
Размерът на таблицата се увеличи до 2 GB след АКТУАЛИЗИРАНЕТО
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
-----------------
2
Ако можете да наблюдавате и сравните числата на разходите от по-ранния ОБЯСНИТЕЛЕН ПЛАН, има огромна разлика. Разходите са се увеличили с голям марж. По-важното е, ако наблюдавате внимателно, броят на редовете (малко над 19 милиона), които се сканират след АКТУАЛИЗИРАНЕТО, е по-висок, което е почти два пъти повече от действително съществуващите редове (10 милиона). Това означава, че броят на раздутите редове е 9+ милиона и действителното време също се е увеличило, а времето за изпълнение се е увеличило от 1,4 секунди на 1,9 секунди.
И така, това е ефектът от това, че не се почиства ТАБЛИЦАТА след АКТУАЛИЗИРАНЕТО. Горните числа на EXPLAIN PLAN точно означават, че таблицата е раздута.
Как да разпознаем дали масата е подута? Използвайте pgstattuple contrib модул:
postgres=# select * from pgstattuple('pgbench_accounts');
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
------------+-------------+------------+---------------+------------------+----------------+--------------------+------------+--------------
2685902848 | 10000000 | 1210000000 | 45.05 | 9879891 | 1195466811 | 44.51 | 52096468 | 1.94
Горното число показва, че половината от таблицата е раздута.
Нека ВАКУУМНО АНАЛИЗИРАМ таблицата и да видим въздействието сега:
postgres=# VACUUM ANALYZE pgbench_accounts ;
VACUUM
postgres=# explain analyze select * from pgbench_accounts;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on pgbench_accounts (cost=0.00..428189.05 rows=10032005 width=97)
(actual time=400.023..1472.118 rows=10000000 loops=1)
Planning time: 4.374 ms
Execution time: 1913.541 ms
След ВАКУУМЕН АНАЛИЗ цифрите на разходите са намалели. Сега броят на сканираните редове се показва близо 10 милиона, като действителното време и времето за изпълнение не се промениха много. Това е така, защото въпреки че раздувите в таблицата са изчезнали, размерът на таблицата, която трябва да бъде сканирана, остава същият. По-долу е изходът pgstattuple след ВАКУУМЕН АНАЛИЗ.
postgres=# select * from pgstattuple('pgbench_accounts');
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
------------+-------------+------------+---------------+------------------+----------------+--------------------+------------+--------------
2685902848 | 10000000 | 1210000000 | 45.05 | 0 | 0 | 0 | 1316722516 | 49.02
Горното число показва, че всички раздувания (мъртви кортежи) са изчезнали.
Нека разгледаме въздействието на ВАКУУМЕН ПЪЛЕН АНАЛИЗ и да видим какво се случва:
postgres=# vacuum full analyze pgbench_accounts ;
VACUUM
postgres=# explain analyze select * from pgbench_accounts;
QUERY PLAN
---------------------------------------------------------------------------
Seq Scan on pgbench_accounts (cost=0.00..263935.35 rows=10000035 width=97)
(actual time=0.015..1089.726 rows=10000000 loops=1)
Planning time: 0.148 ms
Execution time: 1532.596 ms
Ако наблюдавате, числата на действителното време и времето за изпълнение са подобни на числата преди UPDATE. Освен това размерът на таблицата вече е намалял от 2 GB на 1 GB.
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
-----------------
1
Това е въздействието на VACUUM FULL.
FILLFACTOR
FILLFACTOR е много важен атрибут, който може да направи реална разлика в стратегията за поддръжка на базата данни на ниво таблица и индекс. Тази стойност показва количеството пространство, което трябва да се използва от INSERT в блок от данни. Стойността FILLFACTOR по подразбиране е 100%, което означава, че INSERT могат да използват цялото налично пространство в блок от данни. Това също така означава, че няма свободно място за АКТУАЛИЗАЦИИ. Тази стойност може да бъде намалена до определена стойност за силно актуализирани таблици.
Този параметър може да бъде конфигуриран за всяка таблица и индекс. Ако FILLFACTOR е конфигуриран на оптимална стойност, можете да видите реална разлика в производителността на VACUUM и производителността на заявката. Накратко, оптималните стойности FILLFACTOR гарантират, че не се разпределят ненужен брой блокове.
Нека разгледаме същия пример по-горе -
Таблицата има един милион реда
postgres=# select count(*) From pgbench_accounts ;
count
-----------------
10000000
Преди актуализиране размерът на таблицата е 1 GB
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
--------
1
postgres=# update pgbench_accounts set abalance=1;
UPDATE 10000000
След актуализацията размерът на таблицата се увеличи до 2 GB след АКТУАЛИЗИРАНЕТО
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;
?column?
---------
2
Това означава, че броят на блоковете, разпределени в таблицата, се е увеличил със 100%. Ако FILLFACTOR е конфигуриран, размерът на таблицата може да не се е увеличил с това поле.
Как да разбера каква стойност да конфигурирам на FILLFACTOR?
Всичко зависи от това кои колони се актуализират и размера на актуализираните колони. Като цяло би било добре да оцените стойността FILLFACTOR, като я тествате в UAT бази данни. Ако колоните, които се актуализират, са да речем 10% от цялата таблица, тогава помислете за конфигуриране на фактора на запълване на 90% или 80%.
Важна забележка:
Ако промените стойността FILLFACTOR за съществуващата таблица с данните, ще трябва да направите VACUUM FULL или реорганизация на таблицата, за да гарантирате, че стойността FILLFACTOR е в сила за съществуващите данни.
СЪВЕТИ за прахосмукачката
- Както беше казано по-горе, помислете за стартиране на задание VACUUM ANALYZE ръчно всяка вечер на силно използвани маси, дори когато автоматичното вакуумиране е активирано.
- Помислете за стартиране на VACUUM ANALYZE върху таблици след групово INSERT. Това е важно, тъй като мнозина смятат, че ВАКУУМирането може да не е необходимо след INSERT.
- Наблюдавайте, за да се уверите, че високоактивните таблици се ВАКУУМират редовно, като отправяте заявка към таблицата pg_stat_user_tables.
- Използвайте pg_stattuple contrib модул, за да идентифицирате размера на раздуто пространство в сегментите на таблицата.
- Помощната програма VACUUM FULL не може да се използва в производствени системи с бази данни. Помислете за използването на инструменти като pg_reorg или pg_repack, които ще помогнат за реорганизирането на таблици и индекси онлайн без ключалки.
- Уверете се, че процесът AUTOVACUUM работи за по-дълго време по време на работно време (с голям трафик).
- Активирайте параметъра log_autovacuum_min_duration, за да регистрирате времето и продължителността на процесите AUTOVACUUM.
- Важно е да се уверите, че FILLFACTOR е конфигуриран на оптимална стойност при високи транзакционни таблици и индекси.
Други I/O проблеми
Сортиране на дискове
Заявките, извършващи сортиране, са друго често срещано явление в производствените бази данни в реално време и повечето от тях не могат да бъдат избегнати. Заявките, използващи клаузи като GROUP BY, ORDER BY, DISTINCT, CREATE INDEX, VACUUM FULL и т.н. извършват сортиране и сортирането може да се извърши на диск. Сортирането се извършва в паметта, ако изборът и сортирането се извършва въз основа на индексирани колони. Тук съставните индекси играят ключова роля. Индексите се кешират агресивно в паметта. В противен случай, ако възникне необходимост от сортиране на данните на диска, производителността ще се забави драстично.
За да се гарантира, че сортирането се извършва в паметта, може да се използва параметърът work_mem. Този параметър може да бъде конфигуриран на стойност, така че цялото сортиране да може да се извърши в паметта. Основното предимство на този параметър е, че освен да го конфигурирате в postgresql.conf, той може да бъде конфигуриран и на ниво сесия, потребителско ниво или ниво на база данни. Колко трябва да бъде стойността work_mem? Как да разбера кои заявки извършват сортиране на диск? Как да наблюдавате заявки, извършващи сортиране на диск в производствена база данни в реално време?
Отговорът е - конфигурирайте параметъра log_temp_files на определена стойност. Стойността е в байтове, стойност от 0 регистрира всички временни файлове (заедно с техните размери), генерирани на диска поради сортиране на диска. След като параметърът е конфигуриран, ще можете да видите следните съобщения в регистрационните файлове
2018-06-07 22:48:02.358 IST [4219] LOG: temporary file: path "base/pgsql_tmp/pgsql_tmp4219.0", size 200425472
2018-06-07 22:48:02.358 IST [4219] STATEMENT: create index bid_idx on pgbench_accounts(bid);
2018-06-07 22:48:02.366 IST [4219] LOG: duration: 6421.705 ms statement: create index bid_idx on pgbench_accounts(bid);
Горното съобщение означава, че заявката CREATE INDEX е извършвала сортиране на диск и е генерирала файл с размер 200425472 байта, който е 191+ MB. Това точно означава, че параметърът work_mem трябва да бъде конфигуриран на 191+ MB или повече, за да може тази конкретна заявка да извърши сортиране на паметта.
Е, за заявките на приложението, параметърът work_mem може да се конфигурира само на ниво потребител. Преди да направите това, внимавайте за броя връзки, които потребителят прави към базата данни и броя на заявките за сортиране, изпълнявани от този потребител. Тъй като PostgreSQL се опитва да разпредели work_mem за всеки процес (извършвайки сортиране) във всяка връзка, което потенциално може да изтощи паметта на сървъра на базата данни.
Оформление на файловата система на базата данни
Проектирането на ефективно и благоприятно за производителност оформление на файловата система на базата данни е важно от гледна точка на производителността и мащабируемостта. Важно е, че това не зависи от размера на базата данни. Като цяло, схващането е, че базите данни с огромен размер ще се нуждаят от високопроизводителна дискова архитектура, което НЕ е вярно. Дори ако размерът на базата данни е 50 GB, може да имате нужда от добра дискова архитектура. И това може да не е възможно без допълнителни разходи.
Ето няколко СЪВЕТА за същото:
- Уверете се, че базата данни има множество пространства за таблици, с таблици и индекси, групирани въз основа на процентите на транзакциите.
- Пространството за таблици трябва да бъде поставено в множество дискови файлови системи за балансиран I/O. Това също така ще гарантира, че множество процесори влизат в игра за извършване на транзакции на множество дискове.
- Помислете за поставяне на pg_xlog или pg_wal директория на отделен диск в база данни с високи транзакции.
- Уверете се, че параметрите на *_cost са конфигурирани въз основа на инфраструктурата
- Използвайте iostat, mpstat и други инструменти за наблюдение на I/O, за да разберете I/O статистиката за всички дискове и съответно архитектирайте/управлявайте обектите на базата данни.
PostgreSQL в облак
Инфраструктурата е от решаващо значение за добрата производителност на базата данни. Стратегиите за инженеринг на производителност се различават в зависимост от инфраструктурата и околната среда. Трябва да се обърне специално внимание на PostgreSQL бази данни, хоствани в облака. Сравнителен анализ на производителността за бази данни, хоствани на физически barebone сървъри в локален център за данни, може да бъде напълно различен от базите данни, хоствани в публичния облак.
Като цяло облачните екземпляри могат да бъдат малко по-бавни и сравнителните показатели се различават със значителна разлика, особено по отношение на I/O. Винаги извършвайте проверки на I/O латентност, преди да изберете/изградите облачна инстанция. За моя изненада научих, че производителността на облачните екземпляри може да варира и в зависимост от регионите, въпреки че са от един и същ доставчик на облак. За да обясним това допълнително, облачен екземпляр със същите спецификации, изградени в два различни региона, може да ви даде различни резултати за производителност.
Групово зареждане на данни
Офлайн операциите за групово зареждане на данни са доста често срещани в света на базата данни. Те могат да генерират значително I/O натоварване, което от своя страна забавя производителността на зареждане на данни. Сблъсквал съм се с подобни предизвикателства в моя опит като DBA. Често натоварването на данни става ужасно бавно и трябва да се настройва. Ето няколко съвета. Имайте предвид, че те се отнасят само за офлайн операции за зареждане на данни и не могат да се считат за зареждане на данни в база данни за производство на живо.
- Тъй като повечето от операциите за зареждане на данни се извършват в извънработно време, уверете се, че следните параметри са конфигурирани по време на зареждането на данни -
- Конфигурирайте стойностите, свързани с контролните точки, достатъчно големи, така че контролните точки да не причиняват проблеми с производителността.
- Изключете full_page_write
- Изключете архивирането на wal
- Конфигурирайте параметъра synchronous_commit на „изключено“
- Отпускане на ограниченията и индексите за тези таблици, подложени на натоварване с данни (Ограниченията и индексите могат да бъдат създадени повторно след натоварването на данните с по-голяма стойност на work_mem)
- Ако извършвате зареждането на данни от CSV файл, по-големият support_work_mem може да ви даде добри резултати.
- Въпреки че ще има значителна полза от производителността, НЕ изключвайте параметъра fsync, тъй като това може да доведе до повреда на данните.
СЪВЕТИ за анализ на ефективността в облака
- Извършете задълбочени тестове за I/O латентност с помощта на pgbench. Според моя опит имах доста обикновени резултати за производителност, когато правех проверки на латентността на диска като част от оценката на TPS. Имаше проблеми с производителността на кеша в някои публични облачни екземпляри. Това ще ви помогне да изберете подходящите спецификации за облачния екземпляр, избран за базите данни.
- Облачните екземпляри могат да работят различно в различните региони. Облачен екземпляр с определени спецификации в даден регион може да даде различни резултати за производителност в сравнение с облачен екземпляр със същите спецификации в друг регион. Моите pgbench тестове, изпълнени на множество облачни инстанции (всички същите спецификации с един и същ доставчик на облак) в различни региони, ми дадоха различни резултати за някои от тях. This is important especially when you are migrating to cloud.
- Query performance on the cloud might need a different tuning approach. DBAs will need to be using *_cost parameters to ensure healthy query execution plans are generated.
Tools to Monitor PostgreSQL Performance
There are various tools to monitor PostgreSQL performance. Let me highlight some of those.
- pg_top is a GREAT tool to monitor PostgreSQL database dynamically. I would highly recommend this tool for DBAs for various reasons. This tool has numerous advantages, let me list them out:
- pg_top tool uses textual interface and is similar to Unix “top” utility.
- Will clearly list out the processes and the hardware resources utilized. What excites me with this tool is that it will clearly tell you if a particular process is currently on DISK or CPU - in my view that’s excellent. DBAs can clearly pick the process running for longer time on the disk.
- You can check the EXPLAIN PLAN of the top SQLs dynamically or instantly
- You can also find out what Tables or Indexes are being scanned instantly
- Nagios is a popular monitoring tool for PostgreSQL which has both open-source and commercial versions. Open source version should suffice for monitoring. Custom Perl scripts can be built and plugged into Nagios module.
- Pgbadger is a popular tool which can be used to analyze PostgreSQL log files and generate performance reports. This report can be used to analyze the performance of checkpoints, disk sorting.
- Zabbix is another popular tool used for PostgreSQL monitoring.
ClusterControl is an up-and-coming management platform for PostgreSQL. Apart from monitoring, it also has functionality to deploy replication setups with load balancers, automatic failover, backup management, among others.