Като администратор на база данни на PostgreSQL има ежедневните очаквания да проверявате резервните копия, да прилагате промени в DDL, да се уверите, че регистрационните файлове нямат ГРЕШКИ за нарушаване на играта и да отговаряте на панически обаждания от разработчици, чиито отчети се изпълняват два пъти по-дълго от нормалното и те има среща след десет минути.
Дори и при добро разбиране на здравето на управляваните бази данни, винаги ще има нови случаи и нови проблеми, свързани с производителността и начина, по който базата данни „се чувства“. Независимо дали става въпрос за паникьосан имейл или отворен билет за „базата данни се чувства бавно“, тази често срещана задача обикновено може да бъде последвана с няколко стъпки, за да се провери дали има или не проблем с PostgreSQL и какъв може да е този проблем.
Това в никакъв случай не е изчерпателно ръководство, нито стъпките трябва да се извършват в някакъв конкретен ред. Но това е по-скоро набор от първоначални стъпки, които могат да бъдат предприети, за да помогнат за бързото намиране на често срещаните нарушители, както и за придобиване на нова представа за това какъв може да е проблемът. Разработчикът може да знае как действа и реагира приложението, но администраторът на базата данни знае как действа базата данни и реагира на приложението и заедно може да се намери проблемът.
ЗАБЕЛЕЖКА: Заявките, които трябва да се изпълняват, трябва да се извършват като суперпотребител, като „postgres“ или всеки потребител на база данни, на когото са предоставени разрешения на суперпотребител. Ограничени потребители или ще бъдат отказани, или данните ще бъдат пропуснати.
Стъпка 0 – Събиране на информация
Получете възможно най-много информация от този, който казва, че базата данни изглежда бавна; конкретни заявки, свързани приложения, времеви рамки на забавяне на производителността и т.н. Колкото повече информация дават, толкова по-лесно ще бъде откриването на проблема.
Стъпка 1 – Проверете pg_stat_activity
Заявката може да дойде в много различни форми, но ако „бавността“ е общият проблем, проверката на pg_stat_activity е първата стъпка, за да разберете какво точно се случва. Изгледът pg_stat_activity (документация за всяка колона в този изглед може да бъде намерена тук) съдържа ред за всеки сървърен процес/връзка към базата данни от клиент. В този изглед има шепа полезна информация, която може да помогне.
ЗАБЕЛЕЖКА: Известно е, че pg_stat_activity променя структурата с течение на времето, прецизирайки данните, които представя. Разбирането на самите колони ще помогне за динамично изграждане на заявки, ако е необходимо в бъдеще.
Забележимите колони в pg_stat_activity са:
- заявка:текстова колона, показваща заявката, която се изпълнява в момента, чака да бъде изпълнена или е била изпълнена последно (в зависимост от състоянието). Това може да помогне да се определи кои заявки/заявки, за които разработчикът може да отчита, се изпълняват бавно.
- client_addr:IP адресът, от който произлиза тази връзка и заявка. Ако е празно (или Null), то произхожда от localhost.
- backend_start, xact_start, query_start:Тези три предоставят времеви отпечатък за това кога е стартирано всяко съответно. Backend_start представлява кога е установена връзката с базата данни, xact_start е кога е започнала текущата транзакция, а query_start е кога е започнала текущата (или последната) заявка.
- state:Състоянието на връзката с базата данни. Активно означава, че в момента изпълнява заявка, „неактивен“ означава, че чака допълнителни данни от клиента, „неактивен в транзакция“ означава, че чака по-нататъшно въвеждане от клиента, докато държи отворена транзакция. (Има и други, но вероятността за тях е рядка, вижте документацията за повече информация).
- datname:Името на базата данни, към която връзката е свързана в момента. В множество клъстери от бази данни това може да помогне за изолирането на проблемни връзки.
- wait_event_type и wait_event:Тези колони ще бъдат нулеви, когато заявката не изчаква, но ако чака, те ще съдържат информация защо заявката чака, а изследването на pg_locks може да идентифицира какво чака. (PostgreSQL 9.5 и преди има само булева колона, наречена „waiting“, true, ако чака, false ако не.
1.1. Заявката чака/блокирана ли е?
Ако има конкретна заявка или заявки, които са „бавни“ или „окачени“, проверете дали чакат да завърши друга заявка. Поради заключването на релациите, други заявки могат да заключват таблица и да не позволяват на други заявки да имат достъп или да променят данни, докато тази заявка или транзакция не бъдат извършени.
PostgreSQL 9.5 и по-стари версии:
SELECT * FROM pg_stat_activity WHERE waiting = TRUE;
PostgreSQL 9.6:
SELECT * FROM pg_stat_activity WHERE wait_event IS NOT NULL;
PostgreSQL 10 и по-нова версия (?):
SELECT * FROM pg_stat_activity WHERE wait_event IS NOT NULL AND backend_type = 'client backend';
Резултатите от тази заявка ще покажат всички връзки, които в момента чакат друга връзка, за да освободят заключванията на релация, която е необходима.
Ако заявката е блокирана от друга връзка, има някои начини да разберете какви са те. В PostgreSQL 9.6 и по-нови, функцията pg_blocking_pids() позволява въвеждането на идентификатор на процес, който е блокиран, и ще върне масив от идентификатори на процес, които са отговорни за блокирането му.
PostgreSQL 9.6 и по-нови версии:
SELECT * FROM pg_stat_activity
WHERE pid IN (SELECT pg_blocking_pids(<pid of blocked query>));
PostgreSQL 9.5 и по-стари версии:
SELECT blocked_locks.pid AS blocked_pid,
blocked_activity.usename AS blocked_user,
blocking_locks.pid AS blocking_pid,
blocking_activity.usename AS blocking_user,
blocked_activity.query AS blocked_statement,
blocking_activity.query AS current_statement_in_blocking_process
FROM pg_catalog.pg_locks blocked_locks
JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid
JOIN pg_catalog.pg_locks blocking_locks
ON blocking_locks.locktype = blocked_locks.locktype
AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE
AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
AND blocking_locks.pid != blocked_locks.pid
JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
WHERE NOT blocked_locks.GRANTED;
(Достъпно от PostgreSQL Wiki).
Тези заявки ще насочват към всичко, което блокира специфичен PID, който е предоставен. С това може да се вземе решение да се прекрати блокиращата заявка или връзка или да се остави да работи.
Стъпка 2 – Ако заявките се изпълняват, защо отнемат толкова време?
2.1. Планировщикът изпълнява ли заявки ефективно?
Ако въпросната заявка (или набор от заявки) има статус „активна“, тогава тя всъщност се изпълнява. Ако цялата заявка не е налична в pg_stat_activity, извлечете я от разработчиците или от регистрационния файл на postgresql и започнете да проучвате планирането на заявки.
EXPLAIN SELECT * FROM postgres_stats.table_stats t JOIN hosts h ON (t.host_id = h.host_id) WHERE logged_date >= '2018-02-01' AND logged_date < '2018-02-04' AND t.india_romeo = 569;
Nested Loop (cost=0.280..1328182.030 rows=2127135 width=335)
-> Index Scan using six on victor_oscar echo (cost=0.280..8.290 rows=1 width=71)
Index Cond: (india_romeo = 569)
-> Append (cost=0.000..1306902.390 rows=2127135 width=264)
-> Seq Scan on india_echo romeo (cost=0.000..0.000 rows=1 width=264)
Filter: ((logged_date >= '2018-02-01'::timestamp with time zone) AND (logged_date < '2018-02-04'::timestamp with time zone) AND (india_romeo = 569))
-> Seq Scan on juliet victor_echo (cost=0.000..437153.700 rows=711789 width=264)
Filter: ((logged_date >= '2018-02-01'::timestamp with time zone) AND (logged_date < '2018-02-04'::timestamp with time zone) AND (india_romeo = 569))
-> Seq Scan on india_papa quebec_bravo (cost=0.000..434936.960 rows=700197 width=264)
Filter: ((logged_date >= '2018-02-01'::timestamp with time zone) AND (logged_date < '2018-02-04'::timestamp with time zone) AND (india_romeo = 569))
-> Seq Scan on two oscar (cost=0.000..434811.720 rows=715148 width=264)
Filter: ((logged_date >= '2018-02-01'::timestamp with time zone) AND (logged_date < '2018-02-04'::timestamp with time zone) AND (india_romeo = 569))
Този пример показва план на заявка за присъединяване на две таблици, което също удря разделена таблица. Търсим всичко, което може да причини забавяне на заявката и в този случай плановникът прави няколко последователни сканирания на дялове, което предполага, че им липсват индекси. Добавянето на индекси към тези таблици за колона „india_romeo“ незабавно ще подобри тази заявка.
Нещата, които трябва да търсите, са последователно сканиране, вложени цикли, скъпо сортиране и т.н. Разбирането на планировчика на заявки е от решаващо значение, за да сте сигурни, че заявките се изпълняват по възможно най-добрия начин, официалната документация може да бъде прочетена за повече информация тук.
2.2. Раздути ли се масите?
Ако заявките все още се чувстват бавни, без инструментът за планиране на заявки да сочи нещо очевидно, време е да проверите изправността на включените таблици. Прекалено големи ли са? Подути ли са?
SELECT n_live_tup, n_dead_tup from pg_stat_user_tables where relname = ‘mytable’;
n_live_tup | n_dead_tup
------------+------------
15677 | 8275431
(1 row)
Тук виждаме, че има много пъти повече мъртви редове, отколкото живи редове, което означава, че за да намери правилните редове, машината трябва да отсее данни, които дори не са подходящи, за да намери реални данни. Вакуум/пълен вакуум на тази маса ще увеличи значително производителността.
Стъпка 3 – Проверете регистрационните файлове
Ако проблемът все още не може да бъде намерен, проверете регистрационните файлове за улики.
ФАТАЛНИ/ГРЕШКИ съобщения:
Потърсете съобщения, които може да причиняват проблеми, като блокиране или дълго време на изчакване за заключване.
Контрольни точки
Надяваме се log_checkpoints да е включен, което ще записва информация за контролните точки в регистрационните файлове. Има два вида контролно-пропускателни пунктове, насрочени и заявени (принудителни). Ако контролните точки се налагат, тогава мръсните буфери в паметта трябва да бъдат записани на диска, преди да се обработват повече заявки, което може да даде на системата на база данни цялостно усещане за „бавност“. Увеличаването на checkpoint_segments или max_wal_size (в зависимост от версията на базата данни) ще даде на контролния указател повече място за работа, както и ще помогне на фоновия записващ да поеме част от натоварването при писане.
Стъпка 4 – Какво е здравето на хост системата?
Ако няма улики в самата база данни, може би самият хост е претоварен или има проблеми. Всичко от претоварен IO канал към диск, препълване на паметта за размяна или дори неизправно устройство, нито един от тези проблеми не би бил очевиден с всичко, което разгледахме преди. Ако приемем, че базата данни работи на *nix базирана операционна система, ето няколко неща, които могат да помогнат.
4.1. Зареждане на системата
Използвайки „отгоре“, погледнете средното натоварване за хоста. Ако броят наближава или надвишава броя на ядрата в системата, може просто твърде много едновременни връзки да удрят базата данни, което я довежда до обхождане, за да навакса.
load average: 3.43, 5.25, 4.85
4.2. Системна памет и SWAP
Използвайки „безплатно“, проверете дали изобщо е използван SWAP. Преливането на паметта към SWAP в среда на база данни PostgreSQL е изключително лошо за производителността и много DBA дори ще елиминират SWAP от хостовете на базата данни, тъй като грешката „изчерпана памет“ е по-предпочитана от бавна система за много хора.
Ако се използва SWAP, рестартирането на системата ще я изчисти и може да се наложи увеличаване на общата системна памет или повторно конфигуриране на използването на паметта за PostgreSQL (като намаляване на shared_buffers или work_mem).
[[email protected] ~]$ free -m
total used free shared buff/cache available
Mem: 7986 225 1297 12 6462 7473
Swap: 7987 2048 5939
4.3. Достъп до диск
PostgreSQL се опитва да върши голяма част от работата си в паметта и да разпределя записа на диска, за да сведе до минимум тесните места, но при претоварена система с тежко писане е лесно да видите, че тежките четения и записвания причиняват забавяне на цялата система, докато наваксва на исканията. По-бързите дискове, повече дискове и IO канали са някои от начините да увеличите обема на работата, която може да бъде извършена.
Инструменти като „iostat“ или „iotop“ могат да помогнат да се определи дали има затруднение на диска и откъде може да идва.
4.4. Проверете регистрационните файлове
Ако всичко друго се провали или дори да не е, регистрационните файлове трябва винаги да се проверяват, за да се види дали системата отчита нещо, което не е правилно. Вече обсъдихме проверката на postgresql.logs, но системните регистрационни файлове могат да предоставят информация за проблеми като неизправни дискове, повредена памет, проблеми с мрежата и т.н. Всеки един от тези проблеми може да доведе до бавно и непредсказуемо действие на базата данни, така че добро разбиране на перфектно здраве може да помогне за намирането на тези проблеми.
Изтеглете Бялата книга днес Управление и автоматизация на PostgreSQL с ClusterControl Научете какво трябва да знаете, за да внедрите, наблюдавате, управлявате и мащабирате PostgreSQLD Изтеглете Бялата книгаСтъпка 5 – Нещо все още няма смисъл?
Дори и най-опитните администратори ще се сблъскат с нещо ново, което няма смисъл. Това е мястото, където глобалната PostgreSQL общност може да се намеси, за да помогне. Подобно на стъпка №0, колкото по-ясна информация се дава на общността, толкова по-лесно могат да помогнат.
5.1. PostgreSQL пощенски списъци
Тъй като PostgreSQL е разработен и управляван от общността с отворен код, има хиляди хора, които говорят чрез пощенските списъци, за да обсъждат безброй теми, включително функции, грешки и проблеми с производителността. Пощенските списъци могат да бъдат намерени тук, като pgsql-admin и pgsql-performance са най-важни за търсене на помощ при проблеми с производителността.
5.2. IRC
Freenode е домакин на няколко PostgreSQL канала с разработчици и администратори по целия свят и не е трудно да се намери полезен човек, който да проследи откъде може да идват проблемите. Повече информация можете да намерите на страницата на PostgreSQL IRC.