Mundarija (31)
- Bu darsda
- 1. Nega bu kerak?
- 2. Kim nima qilyapti: pg_stat_activity
- 2.1 O'z sessiyamiz
- 2.2 Muhim ustunlar
- 3. Qulf zanjirini topish
- 3.1 Kanon tajribasi: A unutdi, B kutyapti
- 3.2 pg_locks: qulflarning o'zi
- 4. Choralar: cancel va terminate
- 4.1 pg_cancel_backend — faqat so'rov
- 4.2 pg_terminate_backend — ulanishni uzish
- 4.3 Zanjir uzun bo'lsa
- 5. Oldini olish: timeout'lar
- 5.1 To'rt sozlama
- 5.2 Ularni ko'rib chiqamiz
- 5.3 Qayerga qo'yish
- 6. Disk to'lishi
- 6.1 Ma'lumot diski
- 6.2 WAL diski — boshqacha
- 6.3 WAL arxivini kuzatish
- 7. Nimani doim kuzatish kerak
- 8. Favqulodda vaziyat tartibi
- 9. Ko'p uchraydigan xatolar
- 10. Mashqlar
- 1-mashq (oson): qaysi chora
- 2-mashq (o'rta): timeout'dan keyingi tranzaksiya
- 3-mashq (qiyin): bosh tosuvchilar
- 11. Loyiha qadami: kanon tajribasi
- 12. Real ishda
- Xulosa
- Manbalar
Monitoring va favqulodda vaziyatlar: pg_stat_activity, qulflar va timeout'lar
Qisqacha: Baza "qotib qolsa", avval kim nima qilayotganini ko'ring:
pg_stat_activity(holat, kutish sababi, so'rov) vapg_blocking_pids(pid)(kim kimni to'syapti). Keyin eng yumshoq choradan boshlang:pg_cancel_backendfaqat joriy so'rovni bekor qiladi,pg_terminate_backendesa ulanishni uzadi va uning tranzaksiyasini qaytaradi. Takrorlanmasligi uchun timeout'lar:statement_timeout,lock_timeout,idle_in_transaction_session_timeout.
Bu darsda
pg_stat_activitydan "kim, qaysi holatda, nimani kutyapti" ni o'qiysiz.pg_blocking_pidsvapg_locksbilan qulf zanjirini topasiz.pg_cancel_backendvapg_terminate_backendfarqini bilib, to'g'risini tanlaysiz.- To'rt timeout sozlamasini qaysi rolga qanday qo'yishni bilasiz.
- Disk to'lganda Postgres o'zini qanday tutishini va nimani kuzatish kerakligini tushuntirasiz.
Oldin bilishingiz kerak: Qulflar: row, table va advisory, VACUUM, autovacuum va bloat, Rollar va huquqlar, Sekin so'rovlarni topish.
1. Nega bu kerak?
Seshanba, soat 11:15. Telegram guruhga xabar keladi: "Sayt ochilmayapti". Server ishlayapti, protsessor bo'sh, xotira yetarli. Lekin API'ga kelgan har so'rov 5 soniyadan keyin statement timeout bilan qaytyapti.
Sababi ko'pincha shunday: bitta jarayon tranzaksiya ochdi, vazifa qatorini o'zgartirdi va... "unutdi". Masalan dasturchi psql'da BEGIN; UPDATE … yozib, tushlikka chiqib ketdi. Yoki kodda ROLLBACK chaqirilmaydigan xato yo'li bor. U qator qulflangan qoladi (Qulflar), shu qatorni o'zgartirmoqchi bo'lgan har kim navbatda turadi, navbat esa hovuzdagi hamma ulanishni yeydi.
Bunday paytda vahima — eng yomon maslahatchi. Serverni qayta ishga tushirish hammani uzadi va baribir sababini ko'rsatmaydi. Bu darsda tartibli yo'lni o'rganamiz: ko'r → tushun → eng yumshoq chora → oldini ol.
O'xshatish: chorrahada tirbandlik. Hamma mashinani evakuator bilan olib ketish shart emas. Avval qaysi mashina buzilib, yo'lni to'sib turganini topasiz — qolganlari o'zi yuradi.
Diqqat: Ikki sessiyali (A to'sadi, B kutadi) tajriba va disk to'lishi — kanondan: PostgreSQL 18.6 Docker'da,
monbazasi, 2026-10-24. Bitta sessiyada takrorlash mumkin bo'lgan misollarni biz o'z PostgreSQL 17.6 klasterimizda holat 11 bazasida ishga tushirdik. Prometheus, Grafana va boshqa monitoring tizimlari — sinalmagan, hujjat bo'yicha.
2. Kim nima qilyapti: pg_stat_activity
2.1 O'z sessiyamiz
pg_stat_activity — har ulanish (backend jarayoni) uchun bitta qator: kim ulangan, qaysi bazaga, hozir nima qilyapti. Avval o'zimizni ko'raylik:
SET application_name = 'dars16';
SELECT application_name, state, backend_type,
pg_blocking_pids(pid) AS tosuvchi
FROM pg_stat_activity
WHERE pid = pg_backend_pid();Natija:
SET
application_name | state | backend_type | tosuvchi
------------------+--------+----------------+----------
dars16 | active | client backend | {}
(1 row)application_name — ulanish o'zini tanishtirgan nom. Kanon API hovuzi (pool) uni vazifalar-api qilib qo'yadi — shunda 40 ta ulanish ichidan "bular API'niki" deb darhol ajratasiz. pg_backend_pid() — joriy sessiya jarayonining raqami (PID). {} — bizni hech kim to'smayapti.
2.2 Muhim ustunlar
| Ustun | Nimani ko'rsatadi |
|---|---|
state |
active (bajaryapti), idle (bo'sh), idle in transaction (tranzaksiya ochiq, lekin hech narsa qilmayapti) |
wait_event_type, wait_event |
nimani kutyapti: Lock / transactionid, Client / ClientRead, IO … |
xact_start, query_start |
tranzaksiya va joriy so'rov qachon boshlangan |
query |
oxirgi (yoki joriy) so'rov matni |
Eng xavfli holat — idle in transaction: tranzaksiya ochiq, qulflar ushlab turilibdi, lekin sessiya mijozdan buyruq kutyapti (ClientRead). U o'zi hech qachon tugamaydi.
3. Qulf zanjirini topish
3.1 Kanon tajribasi: A unutdi, B kutyapti
Kanon ikki sessiya ochdi. A — BEGIN; UPDATE vazifalar … WHERE id = 1; va shu bilan to'xtadi. B — xuddi shu qatorni yangilamoqchi. Vaqt bo'yicha:
| Qadam | A sessiya | B sessiya | Natija |
|---|---|---|---|
| 1 | BEGIN; UPDATE … id = 1 |
— | A qatorni qulfladi |
| 2 | jim (COMMIT yo'q) | UPDATE … id = 1 |
B navbatda kutyapti |
| 3 | jim | kutyapti | admin zanjirni ko'radi |
| 4 | jim | cancel → ERROR |
B navbatdan chiqdi, ulanish qoldi |
| 5 | terminate → ROLLBACK | — | qator qulfi bo'shadi |
Uchinchi, admin sessiyasidan (uzun chiqishda state, wait_event_type va tosuvchi ustunlariga qarang):
SELECT pid, application_name AS ilova, state,
wait_event_type, wait_event,
pg_blocking_pids(pid) AS tosuvchi,
now() - xact_start > interval '1 second' AS uzoq_tx
FROM pg_stat_activity
WHERE datname = 'mon' AND pid <> pg_backend_pid()
ORDER BY backend_start;Kanon natijasi (sorov ustuni olib tashlandi):
pid | ilova | state | wait_event_type | wait_event | tosuvchi | uzoq_tx
------+--------------+---------------------+-----------------+---------------+----------+---------
3057 | A_unutgan | idle in transaction | Client | ClientRead | {} | t
3064 | B_kutayotgan | active | Lock | transactionid | {3057} | tO'qiymiz: A — idle in transaction, mijozdan buyruq kutyapti, uni hech kim to'smayapti. B — active, lekin aslida ishlamayapti: Lock / transactionid — boshqa tranzaksiya tugashini kutyapti. tosuvchi = {3057} — aynan A. PID'lar har safar boshqacha bo'ladi.
sequenceDiagram
participant A as A (3057)
participant B as B (3064)
participant M as Admin
A->>A: BEGIN, UPDATE id=1
Note over A: idle in transaction
B->>B: UPDATE id=1 (kutyapti)
M->>M: pg_blocking_pids(B) = {A}
M->>B: pg_cancel_backend
M->>A: pg_terminate_backendDiagrammada tartib: A qatorni qulflab "uxlab qoldi", B navbatga turdi, admin avval zanjirni ko'rdi, keyin chora ko'rdi. Choralarni quyida birma-bir ko'ramiz.
3.2 pg_locks: qulflarning o'zi
pg_blocking_pids "kim" ni aytadi, pg_locks esa "qanday qulf" ni. Kanon natijasi:
pid | locktype | mode | granted | application_name
------+---------------+------------------+---------+------------------
3057 | relation | RowExclusiveLock | t | A_unutgan
3057 | transactionid | ExclusiveLock | t | A_unutgan
3064 | relation | RowExclusiveLock | t | B_kutayotgan
3064 | transactionid | ShareLock | f | B_kutayotgan
3064 | tuple | ExclusiveLock | t | B_kutayotgangranted = f — berilmagan, kutilayotgan qulf. B A ning tranzaksiya raqamiga ShareLock so'rayapti: "A tugaganda meni uyg'ot". Qator darajasidagi qulf Postgres'da xotirada emas, qatorning o'zida yoziladi (MVCC) — shuning uchun kutish tranzaksiya orqali bo'ladi. tuple ExclusiveLock — B navbatda birinchi turganini belgilaydi.
Jadval darajasidagi og'ir qulfni o'zimiz ham ko'ra olamiz — bitta sessiyada:
BEGIN;
LOCK TABLE teglar IN ACCESS EXCLUSIVE MODE;
SELECT mode, granted
FROM pg_locks
WHERE relation = 'teglar'::regclass;
ROLLBACK;Natija:
BEGIN
LOCK TABLE
mode | granted
---------------------+---------
AccessExclusiveLock | t
(1 row)
ROLLBACKAccessExclusiveLock — eng kuchli qulf: hatto oddiy SELECT ham kutadi. Uni ALTER TABLE, DROP, TRUNCATE va VACUUM FULL oladi. Kanon VACUUM darsidagi tajribada buni o'lchadi: 300 000 qatorli jadvalda VACUUM FULL 2 497 ms ishladi, shu paytda oddiy SELECT 1 459 ms kutdi.
Tekshirib ko'ring: B
active, lekin protsessor yuklanmagan.statega qarab "B ishlayapti" deyish to'g'rimi?
Javob
Yo'q. active — "so'rov bajarilish jarayonida", ichida kutish ham bor. Haqiqatda nima bo'layotganini wait_event_type aytadi: Lock — qulfni kutyapti. Shuning uchun monitoring so'rovida state bilan birga doim wait_event_type ni ham chiqaring.
4. Choralar: cancel va terminate
4.1 pg_cancel_backend — faqat so'rov
Eng yumshoq chora — kutib turgan so'rovni bekor qilish:
SELECT pg_cancel_backend(3064);Kanonda B sessiyasi shu xatoni oldi:
ERROR: canceling statement due to user request
CONTEXT: while locking tuple (0,1) in relation "vazifalar""So'rov foydalanuvchi talabi bilan bekor qilindi; vazifalar dagi (0,1) qatorni qulflash paytida". Ulanish qoldi — B keyingi buyruqni yubora oladi. Xuddi shu xabarni bitta sessiyada o'zimiz ham olamiz — o'z PID'imizga cancel yuborib:
SELECT pg_cancel_backend(pg_backend_pid());Natija:
ERROR: canceling statement due to user requestLekin B'ni bekor qilish muammoni hal qilmaydi: A hali ham qatorni ushlab turibdi, keyingi so'rov yana navbatga turadi. Cancel — kutayotganlarni ozod qilish uchun, sababni yo'qotish uchun emas.
4.2 pg_terminate_backend — ulanishni uzish
Sabab — A. U idle in transaction holatida: bekor qiladigan so'rovi yo'q, shuning uchun cancel unga ta'sir qilmaydi. Yagona yo'l — ulanishni uzish:
SELECT pg_terminate_backend(3057);A sessiyasida:
FATAL: terminating connection due to administrator command
server closed the connection unexpectedly"Administrator buyrug'i bilan ulanish uzilmoqda". A ning tranzaksiyasi ROLLBACK bo'ldi: kanon tekshirdi — bajarildi o'zgarmagan (f). Qator qulfi bo'shadi: endi shu qatorga kelgan har yangi UPDATE kutmasdan bajariladi. (Kanonda B oldinroq cancel qilingan edi; agar cancel qilinmaganida, terminate'dan keyin B ning UPDATE'i o'zi davom etardi.)
pg_cancel_backend |
pg_terminate_backend |
|
|---|---|---|
| Nimani to'xtatadi | joriy so'rovni | butun ulanishni |
| Tranzaksiya | xato holatiga o'tadi (keyin ROLLBACK) | darhol ROLLBACK |
idle in transaction ga |
ta'sir qilmaydi | ishlaydi |
| Kim chaqira oladi | superuser yoki pg_signal_backend a'zosi (o'z rolining sessiyalari — har kim) |
xuddi shunday |
Diqqat: Terminate qilingan ulanish API hovuziga tegishli bo'lsa, hovuz
errorhodisasini oladi. Kanon API'si buni log'ga yozadi (pg pool: bo'sh ulanish uzildi) va keyingi so'rov uchun yangi ulanish ochadi — jarayon yiqilmaydi. Bu himoya 27-qism loyiha qadamida qo'shilgan (ORM, query builder va raw SQL).
4.3 Zanjir uzun bo'lsa
Real hayotda zanjir ko'pincha shunday: A → B'ni to'sadi, B → C, D, E'ni to'sadi (ular B ushlagan qatorlarni kutyapti). Hammasini o'ldirish shart emas — bosh tosuvchini (o'zi hech kimni kutmaydigan, lekin boshqalarni to'sadigan) topish kerak:
SELECT pid, state, now() - xact_start AS davomiylik,
left(query, 60) AS sorov
FROM pg_stat_activity
WHERE pid IN (SELECT unnest(pg_blocking_pids(pid))
FROM pg_stat_activity)
AND cardinality(pg_blocking_pids(pid)) = 0;"Kimdir uni tosuvchi deb ko'rsatgan, lekin uning o'zini hech kim to'smayapti" — shu bosh. 3-mashqda xuddi shu mantiqni JS'da yozasiz.
5. Oldini olish: timeout'lar
5.1 To'rt sozlama
Sukut bo'yicha Postgres hech narsani o'zi uzmaydi:
SELECT name, setting, unit
FROM pg_settings
WHERE name IN ('statement_timeout', 'lock_timeout',
'idle_in_transaction_session_timeout',
'transaction_timeout', 'deadlock_timeout')
ORDER BY name;Natija:
name | setting | unit
-------------------------------------+---------+------
deadlock_timeout | 1000 | ms
idle_in_transaction_session_timeout | 0 | ms
lock_timeout | 0 | ms
statement_timeout | 0 | ms
transaction_timeout | 0 | ms
(5 rows)0 — "cheksiz". Har biri nima qiladi:
| Sozlama | Qachon ishlaydi | Natija |
|---|---|---|
statement_timeout |
bitta so'rov shundan uzoq yursa | so'rov bekor (ERROR) |
lock_timeout |
qulfni shundan uzoq kutsa | so'rov bekor (ERROR) |
idle_in_transaction_session_timeout |
tranzaksiya ichida shuncha bo'sh tursa | ulanish uziladi (FATAL) |
transaction_timeout (PG 17+) |
butun tranzaksiya shundan uzoq bo'lsa | ulanish uziladi (FATAL) |
deadlock_timeout — boshqacha: u hech narsani bekor qilmaydi, faqat "qancha kutgandan keyin deadlock tekshiruvini boshlash" (Deadlock darsi).
5.2 Ularni ko'rib chiqamiz
statement_timeout — o'zimiz:
SET statement_timeout = '100ms';
SELECT pg_sleep(1);
RESET statement_timeout;Natija:
SET
ERROR: canceling statement due to statement timeout
RESETidle_in_transaction_session_timeout = 2s — kanonda sessiya BEGIN; SELECT 1; dan keyin jim turdi:
FATAL: terminating connection due to idle-in-transaction timeoutlock_timeout = 500ms — kanonda ALTER TABLE band jadvalni kutmasdan xato berdi:
ERROR: canceling statement due to lock timeoutOxirgisi migratsiyalar uchun juda muhim. Agar ALTER TABLE qulf navbatida tursa, uning ortidagi hamma kutadi — oddiy SELECT lar ham. lock_timeout bilan migratsiya tez yiqiladi va qayta urinadi, sayt esa to'xtamaydi — bu Xavfli migratsiyalar va qulflar darsida chuqur.
5.3 Qayerga qo'yish
Bitta global qiymat hamma uchun yaramaydi: API so'rovi 5 soniyadan oshmasin, hisobot esa 30 soniya ishlashi mumkin. Shuning uchun rol darajasida (Rollar va huquqlar):
ALTER ROLE vazifalar_api SET statement_timeout = '5s';
ALTER ROLE vazifalar_api
SET idle_in_transaction_session_timeout = '30s';
ALTER ROLE vazifalar_hisobot SET statement_timeout = '30s';Rol sozlamasi faqat yangi ulanishlarga ta'sir qiladi. Kanondagi tuzoqni eslang: SET ROLE bilan rolga o'tilganda rol sozlamalari qo'llanmaydi — faqat shu rol bilan haqiqiy LOGIN qilinganda.
Tekshirib ko'ring: API'da
statement_timeout = 5sbor. Nega baribiridle_in_transaction_session_timeoutkerak?
Javob
statement_timeout faqat bajarilayotgan so'rovni o'lchaydi. idle in transaction sessiyada hech qanday so'rov bajarilmayapti — taymer ishlamaydi. Kod BEGIN dan keyin xatoga uchrab, ROLLBACK chaqirmay qolsa, qulflarni faqat idle_in_transaction_session_timeout (yoki transaction_timeout) bo'shatadi.
6. Disk to'lishi
6.1 Ma'lumot diski
Kanon buni xavfsiz sinash uchun 16 MB lik alohida disk (tablespace) yaratdi va unga 100 000 qator yozishga urindi:
ERROR: could not extend file "pg_tblspc/16398/PG_18_202506291/5/16399": No space left on device
HINT: Check free disk space."Faylni kengaytirib bo'lmadi: qurilmada joy qolmadi. Diskdagi bo'sh joyni tekshiring". Muhim kuzatuvlar:
- INSERT to'liq bekor bo'ldi — jadvalda 0 qator, yarim yozilgan ma'lumot yo'q (tranzaksiya kafolati).
- Server ishlashda davom etdi — boshqa jadvallarga so'rovlar o'tdi.
DROP TABLEjoyni darhol bo'shatdi (16 MB → 0).
6.2 WAL diski — boshqacha
WAL yoziladigan diskning to'lishi ancha jiddiyroq: Postgres hech narsani yoza olmaydi, hujjatga ko'ra server PANIC bilan to'xtaydi va joy bo'shatilmaguncha ishga tushmaydi. Bu kanonda sinalmagan. WAL'ni to'ldiradigan odatiy sabablar: ishlamay qolgan archive_command (Backup va restore — arxivlanmagan WAL o'chirilmaydi) va unutilgan replikatsiya sloti.
Qoida: disk 100 % ga yetishini kutmang — 80 % da ogohlantirish oling.
6.3 WAL arxivini kuzatish
Oldingi darsda PITR WAL zanjiriga tayanishini ko'rdik. Arxivlash holatini pg_stat_archiver ko'rsatadi:
SELECT archived_count, failed_count, last_failed_wal
FROM pg_stat_archiver;Natija (arxivlash o'chiq):
archived_count | failed_count | last_failed_wal
----------------+--------------+-----------------
0 | 0 |
(1 row)failed_count o'sib borsa va last_failed_wal to'lsa — arxiv to'xtagan: PITR imkoniyati yo'qolyapti va WAL diskda to'planyapti. Bu ikkala muammoning eng erta belgisi.
7. Nimani doim kuzatish kerak
Har kuni qo'lda so'rov yozish o'rniga, monitoring tizimi shu ko'rsatkichlarni yig'ib, chegaradan oshsa xabar beradi:
| Ko'rsatkich | Qayerdan | Ogohlantirish |
|---|---|---|
| Ulanishlar soni | pg_stat_activity |
max_connections ning 80 % i |
| Uzoq tranzaksiyalar | now() - xact_start |
masalan > 5 daqiqa |
idle in transaction |
state |
> 1 daqiqa |
| Disk band joyi | operatsion tizim | > 80 % |
| WAL arxivi xatolari | pg_stat_archiver |
failed_count o'sdi |
| Deadlock, vaqtinchalik fayllar | pg_stat_database |
o'sish tezligi |
| Sekin so'rovlar | pg_stat_statements |
Sekin so'rovlarni topish |
Kanondagi pg_stat_database qatori: deadlocks 0, temp_files 1 (4 102 kB) — work_mem ga sig'magan saralash diskka tushgan. Vositalar (hammasi sinalmagan, 2026-10-25 dagi hujjat bo'yicha): Prometheus + postgres_exporter + Grafana — eng keng tarqalgan juftlik; pgwatch — Postgres uchun tayyor panellar; managed xizmatlar (RDS, Neon) o'z panelini beradi.
8. Favqulodda vaziyat tartibi
Qisqa yo'riqnoma — uni loyiha hujjatiga yozib qo'yish foydali:
- Ko'r.
pg_stat_activity—state,wait_event_type,pg_blocking_pids,now() - xact_start. - Bosh tosuvchini top. Kim boshqalarni to'syapti, lekin o'zini hech kim to'smayapti.
- Kim ekanini aniqla.
application_name,client_addr,query— bu API'mi, migratsiyami, kimningdir psql'imi? - Eng yumshoq chora. Faol so'rov —
pg_cancel_backend;idle in transaction—pg_terminate_backend. - Natijani tekshir. Navbat bo'shadimi, API javob beryaptimi?
- Sababini yoz va oldini ol. Kodda
ROLLBACKsiz yo'l, timeout yo'q rol, kunduzi ishga tushirilgan migratsiya.
Serverni qayta ishga tushirish — oxirgi chora: u hammani uzadi, va sabab (masalan kodda qaytib keladigan xato) besh daqiqadan keyin yana paydo bo'ladi.
9. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
| Hamma so'rov sekin, CPU bo'sh | qulf navbati | pg_blocking_pids, bosh tosuvchi |
pg_cancel_backend "ishlamadi" |
sessiya idle in transaction |
pg_terminate_backend |
| Migratsiya saytni to'xtatdi | ALTER TABLE qulf navbatida |
lock_timeout + qayta urinish |
| Rol timeout'i ishlamayapti | SET ROLE yoki eski ulanish |
haqiqiy LOGIN, hovuzni yangilash |
| Server o'zi to'xtadi | WAL diski to'ldi | arxiv va disk monitoringi |
current transaction is aborted |
timeout'dan keyin tranzaksiya davom ettirildi | ROLLBACK |
10. Mashqlar
Mashqlar kurs/mashqlar/27/16-monitoring/ da. 2-mashq holat 11 bazasida (biz ishga tushirdik, PostgreSQL 17.6), 3-mashq Node 24 da tekshirilgan.
1-mashq (oson): qaysi chora
active,Lock / transactionidkutayotgan so'rovni bekor qilish —pg__backendidle in transactionsessiyani to'xtatish —pg__backend- Tranzaksiya ichida jim turgan sessiyani avtomatik uzish —
- Qulfni 500 ms dan ortiq kutmaslik —
- Kim kimni to'syapti —
pg_
Yechim
- cancel — faqat joriy so'rov; ulanish qoladi.
- terminate — ulanish uziladi, tranzaksiya ROLLBACK.
- idle_in_transaction_session_timeout —
statement_timeoutbo'sh sessiyada ishlamaydi. - lock_timeout — migratsiyalar uchun ayniqsa muhim.
- blocking_pids — natija massiv: bir nechta tosuvchi bo'lishi mumkin.
2-mashq (o'rta): timeout'dan keyingi tranzaksiya
Bitta tranzaksiyada: SET LOCAL statement_timeout = '200ms', vazifalarni sanang, keyin pg_sleep(1), keyin yana sanashga urining va ROLLBACK qiling. Har qadamda nima chiqishini oldindan yozing, keyin tekshiring.
Yechim
BEGIN;
SET LOCAL statement_timeout = '200ms';
SELECT count(*) FROM vazifalar;
SELECT pg_sleep(1);
SELECT count(*) FROM vazifalar;
ROLLBACK;Natija:
BEGIN
SET
count
-------
48
(1 row)
ERROR: canceling statement due to statement timeout
ERROR: current transaction is aborted, commands ignored until end of transaction block
ROLLBACKTimeout so'rovni bekor qildi, lekin tranzaksiya xato holatida qoldi: keyingi oddiy SELECT ham bajarilmadi ("joriy tranzaksiya bekor qilingan, buyruqlar tranzaksiya oxirigacha e'tiborsiz"). Ilovada timeout xatosidan keyin albatta ROLLBACK — aks holda ulanish hovuzga shu holatda qaytadi. SET LOCAL — faqat shu tranzaksiya uchun, ROLLBACK dan keyin o'chadi.
3-mashq (qiyin): bosh tosuvchilar
pg_stat_activity dan olingan qatorlar massivi berilgan: har birida pid va tosuvchi (PID'lar massivi). boshTosuvchilar(qatorlar) funksiyasi kimnidir to'sadigan, lekin o'zini hech kim to'smaydigan PID'larni o'sish tartibida qaytarsin.
Ishora: avval hamma tosuvchilarni bitta Set ga yig'ing (Set); keyin ular ichidan tosuvchi massivi bo'sh bo'lganlarini qoldiring.
Yechim
function boshTosuvchilar(qatorlar) {
const tosuvchilar = new Set(qatorlar.flatMap((q) => q.tosuvchi));
return qatorlar
.filter((q) => tosuvchilar.has(q.pid) && q.tosuvchi.length === 0)
.map((q) => q.pid)
.sort((a, b) => a - b);
}
const qatorlar = [
{ pid: 3057, tosuvchi: [] },
{ pid: 3064, tosuvchi: [3057] },
{ pid: 3070, tosuvchi: [3064] },
{ pid: 3071, tosuvchi: [3064] },
{ pid: 3080, tosuvchi: [] },
{ pid: 3090, tosuvchi: [3095] },
{ pid: 3095, tosuvchi: [] },
];
console.log(boshTosuvchilar(qatorlar));Konsolda:
[ 3057, 3095 ]3064 ham tosuvchi, lekin o'zini 3057 to'syapti — uni o'ldirish yordam bermaydi. 3080 — hech kimni to'smaydi (oddiy bo'sh ulanish). Ikki mustaqil zanjirning boshlari — 3057 va 3095.
11. Loyiha qadami: kanon tajribasi
Bu darsda vazifalar-api kodi o'zgarmaydi va commit yo'q. Monitoring — server sozlamasi va operatsiya ishi; serverga chiqarish 33-qismda. Lekin API'da nima borligini bilib qo'yamiz:
- Hovuzda
application_name: "vazifalar-api"—pg_stat_activityda darhol ajraladi. statement_timeout—PG_STATEMENT_TIMEOUT(sukut 5 000 ms). Bo'sh qiymat bilan uni jim o'chirib yuborish teshigi 27-qismda yopilgan (ORM, query builder va raw SQL darsining loyiha qadami).- Hovuz
error→ log — terminate qilingan ulanish iz qoldiradi. idle_in_transaction_session_timeoutvalock_timeout— API'da yo'q. Sababi: tranzaksiyalar faqat ombor ichida,try/finallybilan, va bitta foydalanuvchi. Serverga chiqarishda ularnivazifalar_apiroligaALTER ROLE … SETbilan qo'yish — «Qayerga qo'yish» bo'limidagi namuna.
O'zingiz takrorlang: ikki terminalda docker exec -it kanon27-pg psql -U postgres -d vazifalar oching. Birinchisida BEGIN; UPDATE vazifalar SET bajarildi = NOT bajarildi WHERE id = 1; (COMMIT'siz), ikkinchisida xuddi shu qatorni yangilang. Uchinchi terminalda «Kanon tajribasi: A unutdi, B kutyapti» bo'limidagi so'rov bilan zanjirni toping va avval cancel, keyin terminate qilib ko'ring.
12. Real ishda
- "Sayt qotdi" ning yarmi — qulf navbati, ko'pincha unutilgan tranzaksiya yoki kunduzi yurgizilgan migratsiya.
- Katta jamoalarda yuqoridagi tartib "runbook" (navbatchi yo'riqnomasi) bo'lib yoziladi,
pg_terminate_backendkim va qachon chaqirishi kelishiladi. - Intervyuda: "
idle in transactionnima va nega xavfli?", "cancel va terminate farqi?", "Migratsiya saytni qanday to'xtatishi mumkin?"
Xulosa
pg_stat_activity:state+wait_event_type+pg_blocking_pids— kim, nima qilyapti, kim to'syapti.idle in transaction— qulf ushlab, hech narsa qilmayotgan eng xavfli holat.- Avval bosh tosuvchini toping; cancel — so'rovni, terminate — ulanishni (tranzaksiya ROLLBACK).
- Sukut bo'yicha hamma timeout 0; ularni rol darajasida qo'ying,
lock_timeout— migratsiyalarga. - Ma'lumot diski to'lsa — so'rov bekor, server ishlaydi; WAL diski to'lsa — server to'xtaydi: 80 % da ogohlantirish.
Keyingi dars: Postgres versiyasini yangilash — 17 dan 18 ga: dump/restore, pg_upgrade --link va Docker image tuzog'i.
Manbalar
- PostgreSQL 18 hujjati — The Cumulative Statistics System (
pg_stat_activity,pg_stat_database,pg_stat_archiver): https://www.postgresql.org/docs/18/monitoring-stats.html pg_locks: https://www.postgresql.org/docs/18/view-pg-locks.html- Server signalling functions (
pg_cancel_backend,pg_terminate_backend,pg_blocking_pids): https://www.postgresql.org/docs/18/functions-admin.html - Client connection defaults (
statement_timeout,lock_timeout,idle_in_transaction_session_timeout,transaction_timeout): https://www.postgresql.org/docs/18/runtime-config-client.html - WAL diski to'lishi: https://www.postgresql.org/docs/18/disk-full.html
- postgres_exporter: https://github.com/prometheus-community/postgres_exporter; pgwatch: https://github.com/cybertec-postgresql/pgwatch
- O'qilgan sana — 2026-10-25. Kanon o'lchovi (IlmHamroh, 2026-10): A/B qulf zanjiri,
pg_locks, cancel, terminate, idle va lock timeout, VACUUM FULL qulfi,pg_stat_database, disk to'lishi; PostgreSQL 18.6. Biz ishga tushirdik (PostgreSQL 17.6, holat 11): o'z sessiyamiz,AccessExclusiveLock, cancel, timeout sozlamalari vastatement_timeout,pg_stat_archiver, 2–3-mashqlar.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!