dataiotech Labs
dbaguidedbaguideDBAdataxtoolsdataopsphere
Runbooks Library/postgresql/#3
Runbook #3
postgresql
LockingSEV2 · DEGRADATION15-30 dakika / 15-30 minssuperuser / postgres / rds_superuser

PostgreSQL Lock Chain and Blocking: Find and Resolve the Root Blocker

Finds the session at the head of a lock chain and resolves it safely. Covers the DDL queue trap and prevention methods.

Related Metrics:M8M7
Related Scripts:S2S1
#locks#blocking#pg_blocking_pids#lock_timeout

Operational Safety & Risk Notice

This runbook contains operational intervention steps; several are write-impacting (KILL, terminate, DROP, RESIZE). Verify in a staging environment first, and apply sequentially in production with verification.

🟢 Salt Okunur (Read-Only)·🟡 Geri Alınabilir (Reversible)·🔴 Yüksek Etkili / Geri Alınamaz (High Impact)

1. Symptom & Signals

- Sorgular uzun süre bekliyor, uygulamada zaman aşımı.

- `pg_stat_activity` içinde `wait_event_type = 'Lock'` olan çok sayıda oturum.

- M8 (kilit bekleyen oturum) eşiği aşıldı.

2. Business & Technical Impact

Etkilenen tablolara okuma/yazma gecikir veya durur. Zincir uzadıkça bağlantı havuzu dolar ve `pg-too-many-connections` senaryosuna dönüşebilir.

3. Diagnosis & Root-Cause Analysis

🟢 Read-Only1. Bloklanan ve bloklayan oturumları eşleştirin (S2):
sql
SELECT blocked.pid AS blocked_pid, left(blocked.query,100) AS blocked_query,
       blocker.pid AS blocking_pid, blocker.state AS blocking_state,
       left(blocker.query,100) AS blocking_query,
       now() - blocker.xact_start AS blocker_tx_age
FROM pg_stat_activity blocked
JOIN LATERAL unnest(pg_blocking_pids(blocked.pid)) AS b(pid) ON true
JOIN pg_stat_activity blocker ON blocker.pid = b.pid;
🟢 Read-Only2. **Kök bloklayıcı:** Kendisi bloklanmayan ve başkalarını bloklayan pid. Zincir A→B→C ise A kökütür.
🟢 Read-Only3. Kökün durumuna bakın:

- `idle in transaction`: uygulama transaction'ı açık unutmuş. En sık neden.

- `active` ve uzun: ağır bir DDL veya toplu güncelleme çalışıyor.

- `ALTER TABLE` bekliyor olabilir (aşağıdaki tuzağa bakın).

🟢 Read-Only4. Hangi nesnede kilit olduğunu görmek için:
sql
SELECT l.pid, l.locktype, l.mode, l.granted, l.relation::regclass
FROM pg_locks l WHERE NOT l.granted OR l.pid = <kok_pid>;

4. Remediation & Action Plan

🟡 Reversible1. Önce nazik iptal (sorguyu iptal eder, bağlantı kalır):
sql
SELECT pg_cancel_backend(<kok_pid>);
🔴 HIGH RISK / IRREVERSIBLE2. İptal işe yaramazsa veya oturum `idle in transaction` ise bağlantıyı sonlandırın (açık transaction geri alınır, uzun transaction'da rollback süre alabilir):
sql
SELECT pg_terminate_backend(<kok_pid>);

3. Sonlandırmadan önce **sorgu sahibini** (`usename`, `application_name`) ve işin kritikliğini kontrol edin. Veri taşıma veya fatura kesimi gibi işleri körlemesine kesmeyin.

4. **DDL kuyruğu tuzağı:** Uzun bir okuma transaction'ı varken `ALTER TABLE` gelirse, DDL `ACCESS EXCLUSIVE` kilidini bekler ve **arkasından gelen tüm basit SELECT'ler de DDL'in arkasında kuyruğa girer.** Çözüm: bekleyen DDL'i iptal edin (`pg_cancel_backend`), tüm tablo trafiği normale döner.

5. **Önleme:**

sql
-- Migration oturumunda:
SET lock_timeout = '3s';
SET statement_timeout = '5min';
-- Genel güvenlik ağı:
ALTER SYSTEM SET idle_in_transaction_session_timeout = '5min';

Migration'larda `CREATE INDEX CONCURRENTLY` ve kısa transaction kullanın.

5. Verification & Health Checks

- Adım 1 sorgusu boş dönüyor, M8 normale döndü.

- Bekleyen uygulama sorguları tamamlandı, hata oranı düştü.

- Kök nedenin (açık kalan transaction, uygulama hatası, migration) kaydı tutuldu.

6. Rollback & Contingency Plan

- `pg_cancel_backend` ve `pg_terminate_backend` geri alınamaz; ilgili işlem rollback olur ve uygulama tarafından yeniden denenmelidir.

- `lock_timeout` değişikliği oturum bazlıysa oturum kapanınca kendiliğinden kalkar.

More POSTGRESQL Runbooks