首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

基於 PostgreSQL 實現分布式鎖:會話鎖與期限鎖兩種方案詳解

     編輯:Java 綜合教學

關係型數據庫實現分布式鎖:PostgreSQL 會話級諮詢鎖與表級期限鎖實戰

分布式鎖不一定非要用 Redis/ZooKeeper。PostgreSQL 內建的諮詢鎖與表級鎖即可輕鬆實現,且天然支援故障自動釋放、HA 高可用。本文詳細演示兩種方案的 SQL 實現、適用場景與優缺點對比。

一、方案 1:會話級諮詢鎖 —— 輕量、自動釋放、適合短時持有

核心函數

函數說明
pg_advisory_lock(key bigint)阻塞獲取排他鎖,會話級
pg_try_advisory_lock(key bigint)非阻塞嘗試獲取,立即返回 true/false
pg_advisory_unlock(key bigint)釋放鎖
pg_advisory_lock_shared(key bigint)共享鎖(讀鎖),多會話可同時持有

使用示例

-- 獲取鎖(阻塞直到成功)
SELECT pg_advisory_lock(123456);  -- key 可為業務 ID(訂單號、用戶 ID)

-- 業務邏輯執行...
-- 更新庫存、扣款等

-- 釋放鎖
SELECT pg_advisory_unlock(123456);

關鍵特性

  • 會話綁定:鎖綁定於物理連接,連接斷開(客戶端崩潰、網絡中斷、顯式關閉)**自動釋放**,無需擔心死鎖殘留
  • 無需建表:純內存鎖,性能極高(微秒級)
  • 長連接成本:持有鎖期間必須保持連接,數據庫連接資源有限(通常幾千),**不適合長時間持有(>秒級)**
  • TCP Keepalive 必開:防止「網絡斷開但兩端未感知」導致鎖未釋放

連接池配置建議

# PostgreSQL 服務端 postgresql.conf
tcp_keepalives_idle = 60      # 空閒 60s 發送探針
tcp_keepalives_interval = 10  # 每 10s 重試
tcp_keepalives_count = 6      # 重試 6 次失效判定斷開

# 客戶端連接池
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.connection-timeout=30000

二、方案 2:表級期限鎖 —— 重量、持久化、適合長時持有/跨事務

建表

CREATE TABLE dist_lock (
    id              INT PRIMARY KEY,      -- 業務鍵
    owner           TEXT,                 -- 持有者標識
    expired_time    INTERVAL,             -- 租約時長
    ts              TIMESTAMPTZ           -- 最後續租時間
);

INSERT INTO dist_lock(id) VALUES (1);  -- 預置鎖記錄

獲取鎖(原子更新 + 條件判斷)

-- 參數:$1=鎖ID, $2=持有者, $3=租約間隔
UPDATE dist_lock
SET owner = $2, ts = now(), expired_time = $3
WHERE id = $1
  AND (owner = $2               -- 自己已持有(續租)
       OR owner IS NULL          -- 無人持有
       OR now() > ts + expired_time);  -- 租約過期(搶佔)
-- 返回 UPDATE 1 表示獲取成功,0 表示失敗

續租(定期執行,如每 10 秒)

UPDATE dist_lock
SET ts = now()
WHERE id = $1 AND owner = $2;

釋放鎖

UPDATE dist_lock
SET owner = NULL, ts = now()
WHERE id = $1 AND owner = $2;

關鍵特性

  • 持久化:鎖信息寫入表,配合 PostgreSQL 流複製/同步複製,**主備切換不丟鎖**
  • 租約機制:持有者崩潰無法續租 → 租約過期 → 其他節點可搶佔,實現故障自動恢復
  • 性能代價:每次鎖操作都是表更新(WAL 寫入、索引維護),**不適合高頻(>100 QPS)短鎖場景**
  • 時鐘同步要求:集群節點需 NTP 同步,避免租約誤判

三、方案對比與選型指南

維度會話諮詢鎖表級期限鎖
實現複雜度極低(2 個函數調用)中(建表 + 多條 SQL + 續租邏輯)
性能極高(純內存,微秒)中等(磁盤 I/O,毫秒)
持有時長短(< 秒級,受限連接數)長(分鐘~小時,無連接限制)
故障恢復連接斷開自動釋放租約過期自動釋放
高可用依賴連接池/驅動重連依賴 PG 流複製/同步複製
適用場景短關鍵區、單實例/低併發長事務、跨服務協調、強一致性要求

四、生產環境最佳實踐

  1. 短鎖優先諮詢鎖:如「扣減庫存」「防重提交」,用 pg_try_advisory_lock 非阻塞模式,失敗直接返回「系統繁忙」
  2. 長業務流程用表鎖:如「訂單狀態機流轉」「分佈式事務協調器」,租約 30 秒 + 後台續租線程
  3. 鎖 Key 設計:業務維度(order:{id}、user:{uid}:withdraw),避免大顆粒度鎖(如 global_lock)
  4. 監控指標:鎖等待時間、持有時長、獲取失敗率、死鎖檢測(pg_locks 視圖)
  5. 避免在鎖內做 RPC/外部調用:持有時間不可控,極易擴大衝突窗口

五、總結

PostgreSQL 同時提供了輕量級會話鎖與重量級持久鎖,覆蓋從毫秒級關鍵區到分鐘級協調流程的全谱系需求。選型原則:**能用諮詢鎖就不用表鎖,能用表鎖就不用 Redis/ZK**,在「足夠好」與「運維成本」間找到平衡點。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved