今日已更新 339 条资讯 | 累计 19899 条内容
关于我们

标签:#locking

找到 5 篇相关文章

AI 资讯

Lock Monitoring — Production Lock Analysis

Production lock analysis: vì sao pg_stat_activity một mình không đủ, và join với pg_locks mới ra root cause Lock contention trong Postgres hiếm khi báo bằng error — nó báo bằng wait_event_type = 'Lock' ở pg_stat_activity và bằng latency tăng từ phía application. Khi một incident xảy ra ("API treo, không ai biết tại sao"), thứ team cần trong 60 giây đầu là một bức tranh: PID nào đang đợi, đợi lock loại gì trên object nào, bị block bởi PID nào, PID block đó đang chạy query gì và đã giữ transaction bao lâu . pg_stat_activity một mình chỉ trả lời được nửa câu hỏi ("ai đang đợi"); pg_locks một mình chỉ trả lời nửa còn lại ("ai giữ gì"). Phải join hai view này — và bám theo pg_blocking_pids() — để dựng được blocking tree. Không có dashboard cho luồng dữ liệu này là lý do điển hình một production freeze kéo dài 30 phút thay vì 3 phút: incident commander phải mò ad-hoc bằng psql , gõ sai query, miss idle in transaction đang giữ AccessExclusiveLock của một migration nửa đời trước. Cơ chế hoạt động pg_locks là một view phơi nội dung trực tiếp của shared lock manager trong shared memory. Mỗi dòng là một lock request (đã granted hoặc đang chờ) thuộc một backend. Theo Postgres docs phần "System Views → pg_locks", các column then chốt: locktype ( relation , transactionid , tuple , virtualxid , advisory ...), relation (OID — join pg_class ), transactionid , virtualtransaction , pid (backend PID), mode ( AccessShareLock , RowExclusiveLock , ShareUpdateExclusiveLock , AccessExclusiveLock ...), granted (bool), fastpath (lock đi qua fast-path tránh shared lock manager), và waitstart (timestamp bắt đầu chờ — bổ sung sau v14, hữu ích để đo lock wait time mà không cần snapshot diff). pg_stat_activity là view phơi trạng thái runtime của mỗi backend: pid , usename , datname , application_name , client_addr , backend_start , xact_start , query_start , state ( active , idle , idle in transaction , idle in transaction (aborted) ), wait_event_type , wait_event , backend_xid , backend_xmin , qu

2026-07-07 原文 →
AI 资讯

Deadlock — Deadlock Detection

Deadlock detection: vì sao Postgres chỉ dò cycle sau deadlock_timeout , và vì sao retry mù làm vỡ thêm Deadlock xảy ra khi hai (hoặc nhiều) transaction đang giữ lock mà bên kia cần, tạo thành một vòng tròn đợi không thoát ra được nếu không có trọng tài. Postgres là trọng tài đó: nó dựng wait-for graph từ trạng thái lock hiện tại, phát hiện cycle, và chủ động abort một transaction để cắt vòng. Dev gặp class lỗi này không phải vì viết code "sai" mà vì hai code path đụng cùng tài nguyên theo thứ tự khác nhau dưới load cao — ở môi trường dev một mình thì không thấy, lên production concurrent đủ thì ERROR: deadlock detected (SQLSTATE 40P01 ) ném ra, một transaction bị rollback, request user trả 500. Hậu quả nặng nhất không phải bản thân deadlock, mà là retry layer viết kiểu "cứ lỗi thì retry vô hạn": cùng pattern lock sai thứ tự, cùng tạo lại cycle, deadlock counter tăng tuyến tính với traffic, log Postgres ngập, và database CPU bị burn vào việc chạy graph algorithm thay vì việc thật. Cơ chế hoạt động Postgres không dò deadlock liên tục. Mỗi lần một backend phải đợi lock, nó đăng ký với lock manager và đi ngủ; chỉ khi ngủ vượt deadlock_timeout (mặc định 1 giây, GUC ở runtime-config-locks ), backend đó mới được đánh thức để chạy thuật toán dò cycle. Đây là quyết định thiết kế nêu trong Postgres docs về Lock Management: phần lớn lock chờ trong workload bình thường chỉ kéo dài vài ms (chờ một UPDATE ngắn commit) — chạy graph algorithm trên mọi lần lock-wait sẽ tốn CPU vô ích. Lazy detection đánh đổi: nếu có cycle thật, mọi transaction trong cycle treo ít nhất deadlock_timeout trước khi được giải phóng. Khi timer kích hoạt, backend đó dựng wait-for graph từ lock manager: với mỗi process đang đợi lock, vẽ một cạnh hướng từ "process đợi" sang "process giữ lock đó". Postgres còn phải xử lý lock soft-conflict (hai process cùng đợi, không ai giữ — nếu được sắp xếp lại thứ tự thì cả hai đều chạy được mà không cần kill ai); thuật toán thật trong deadlock.c (source tree Postgres) th

2026-07-07 原文 →
AI 资讯

Table Lock — DDL Lock

DDL lock: vì sao một ALTER TABLE 50ms vẫn đủ làm sập cả API trong giờ cao điểm DDL trong Postgres không phải "vài lệnh schema chạy nhanh". Hầu hết các form của ALTER TABLE , toàn bộ DROP TABLE , TRUNCATE , REINDEX , CLUSTER , VACUUM FULL , và cả REFRESH MATERIALIZED VIEW (không có CONCURRENTLY ) đều yêu cầu ACCESS EXCLUSIVE — lock mode mạnh nhất, xung đột với mọi mode khác kể cả ACCESS SHARE mà một SELECT thuần đọc cũng cần. Một DDL chạy 50ms vẫn có thể chôn cả service vài phút vì hai thứ Postgres làm theo design: lock được giữ tới hết transaction (không nhả sớm), và lock queue là FIFO — bên đến sau dù mode tương thích vẫn phải đứng sau bên đang đợi. "Migration chạy lúc giờ cao điểm, toàn bộ API treo 5 phút" gần như luôn là class incident này. Cơ chế hoạt động Mỗi lệnh DDL acquire một relation-level lock trên các object nó chạm, theo bảng mode cố định trong Postgres docs mục Explicit Locking . Có ba nhóm cần thuộc: ACCESS EXCLUSIVE — xung đột với mọi mode. Cấp bởi: phần lớn ALTER TABLE (kể cả những form không rewrite data), DROP TABLE , TRUNCATE , REINDEX (non-concurrently), CLUSTER , VACUUM FULL , REFRESH MATERIALIZED VIEW (non-concurrently), LOCK TABLE không kèm mode. Đây là lock "đông cứng" object. SHARE — xung đột với mọi mode ghi ( ROW EXCLUSIVE , SHARE UPDATE EXCLUSIVE , SHARE ROW EXCLUSIVE , EXCLUSIVE , ACCESS EXCLUSIVE ). Cấp bởi: CREATE INDEX (non-concurrently). Cho đọc đi qua, nhưng chặn mọi INSERT / UPDATE / DELETE — trên bảng OLTP nóng đó là downtime ghi. SHARE UPDATE EXCLUSIVE — xung đột với chính nó và các mode mạnh hơn, nhưng không xung đột với ROW EXCLUSIVE . Cấp bởi: CREATE INDEX CONCURRENTLY , REINDEX CONCURRENTLY , VACUUM (không FULL), ANALYZE , ALTER TABLE ... VALIDATE CONSTRAINT , ALTER TABLE ... SET STATISTICS , ALTER INDEX ... RENAME . Đây là mode "online maintenance": cho cả đọc lẫn ghi đi qua, chỉ tự khoá lẫn nhau. Quan trọng: lock giữ tới hết transaction , không có cách nhả sớm. BEGIN; ALTER TABLE ...; <30 phút làm việc khác>; COMMIT; giữ A

2026-07-07 原文 →
AI 资讯

Row Lock — FOR UPDATE

FOR UPDATE: pessimistic row lock để chặn lost update, và cái giá deadlock khi không lock theo thứ tự SELECT ... FOR UPDATE là cách rõ ràng nhất để nói với Postgres "tao sẽ sửa row này, đừng cho ai khác đụng vào cho tới khi tao commit". Nó là một row-level lock thật sự — khác SELECT thường (chỉ chụp snapshot MVCC, không ngăn ai update song song). Lý do dev gặp nó trong việc thật là class bug lost update : hai transaction cùng đọc một row, cùng tính giá trị mới dựa trên giá trị đọc được, rồi cùng UPDATE — bản ghi cuối đè bản trước, một nửa thay đổi biến mất không log lỗi gì. FOR UPDATE ép hai bên xếp hàng tại bước đọc, một bên đợi bên kia commit rồi tự đọc lại bản mới. Đổi lại, nếu nhiều code path khoá nhiều row theo thứ tự khác nhau, Postgres sẽ bắn ERROR: deadlock detected và một bên transaction bay theo. Cơ chế hoạt động Khi một transaction chạy SELECT ... FOR UPDATE , Postgres không ghi row lock vào lock table chính (như cách nó làm với relation-level lock). Thay vào đó, nó ghi xid của transaction hiện tại vào xmax của chính tuple đó trên heap, kèm cờ infomask đánh dấu "đây là lock chứ chưa phải delete". Hệ quả: ôm row lock cho hàng triệu row gần như không tốn shared memory. Khi một transaction khác chạm cùng row (qua UPDATE , DELETE , hay một SELECT ... FOR UPDATE nữa), nó đọc xmax , thấy transaction kia còn sống, và đăng ký một heavyweight lock kiểu transactionid trong pg_locks để đợi xid đó kết thúc. Đó là cơ chế "đợi xid" lộ ra qua wait_event = 'transactionid' ở pg_stat_activity . Khi bên giữ COMMIT hoặc ROLLBACK , bên đợi được đánh thức, đọc lại tuple (visibility check theo isolation level), rồi mới chạy tiếp. -- Session A BEGIN ; SELECT id , balance FROM accounts WHERE id = 42 FOR UPDATE ; -- giữ row lock trên id=42, chưa commit -- Session B (terminal khác) BEGIN ; UPDATE accounts SET balance = balance - 100 WHERE id = 42 ; -- treo, đợi xid của Session A FOR UPDATE có bốn biến thể, mạnh dần ngược lại: FOR KEY SHARE (yếu nhất, chỉ chặn thay đổi key — đây là l

2026-07-07 原文 →
AI 资讯

Lock Manager — Lock Overview

Lock trong Postgres: hai tầng heavyweight/lightweight, vì sao một ALTER đứng yên kéo theo cả service Postgres chia khoá thành hai tầng chạy song song. Heavyweight lock (Postgres docs gọi là "regular locks" hay table-level/row-level lock) giữ vai trò bảo vệ object logic — relation, tuple, transactionid — sống suốt một transaction, hiện ra trong view pg_locks và là loại mà application code "thấy" được. Lightweight lock (LWLock) bảo vệ các vùng nhớ chia sẻ bên trong server — buffer descriptor, WAL insert position, hash table của chính lock manager — chỉ ôm trong thời gian rất ngắn, không hiện trong pg_locks nhưng lộ ra qua wait_event_type = 'LWLock' ở pg_stat_activity . Hai tầng có hai cơ chế chờ khác nhau, hai loại sự cố production khác nhau, và nếu chỉ "biết row lock" thì sẽ bỏ qua hai class incident kinh điển: một ALTER TABLE đứng đợi ACCESS EXCLUSIVE làm đông cứng mọi SELECT đến sau nó, và LockManager partition LWLock thành điểm nghẽn khi đụng nhiều partition trong một query. Cơ chế hoạt động Heavyweight lock được quản lý bằng một hash table trong shared memory, chia thành nhiều partition để giảm contention (số partition là NUM_LOCK_PARTITIONS , set tại compile time). Mỗi entry ứng với một (locktag, mode) ; locktag là tuple (locktype, database, relation, ...) nhận diện object cần khoá. Tám lock mode trên relation chia thành ma trận xung đột cố định: ACCESS SHARE (cấp bởi SELECT ) xung đột duy nhất với ACCESS EXCLUSIVE (cấp bởi DROP TABLE , TRUNCATE , hầu hết ALTER TABLE , REINDEX , CLUSTER ); ROW EXCLUSIVE (cấp bởi INSERT / UPDATE / DELETE ) xung đột với SHARE trở lên; SHARE UPDATE EXCLUSIVE (cấp bởi VACUUM không-FULL, ANALYZE , CREATE INDEX CONCURRENTLY ) tự xung đột với chính nó — đó là lý do chỉ một autovacuum hoặc một CREATE INDEX CONCURRENTLY chạy mỗi lần trên cùng bảng. Ma trận này nằm trong docs Postgres mục Explicit Locking và là kiến thức nền cho mọi quyết định migration online. -- xem mode đang giữ trên một bảng SELECT pid , mode , granted , locktype , re

2026-07-07 原文 →