《分佈式鎖》原理與實現

hi,已經忘記多久沒有寫博客,現在正式迴歸! 今天要分享的是分佈式鎖的原理與實現;在系統軟件開發過程中,很多時候我們會有一種這麼一種場景: 我們有很多需要同時處理的任務,而這些任務執行過程中都需要去訪問修改一個公共資源;如果每個線程都可以隨意的去修改資源,那我們的公共資源的最終結果可能和我們預期的會不一致(例如:扣庫存);此時我們就需要同一個時間,只能有一個線程訪問修改公共資源;要實現這個功能,我們就需要用到鎖;JDK 的JUC提供了很多相關的實現,如:synchronized,ReenreantLock等;但是,程序同時部署到多個服務器上時,我們就需要用到分佈式鎖。 針對分佈式鎖的實現,目前比較常用的有以下幾種方案:

  • 1、數據庫實現分佈式鎖:原理簡單,性能較差
  • 2、redis實現的分佈式鎖:性能最好
  • 3、zookeeper實現的分佈式鎖:分佈式鎖:可靠性最好

一、基於數據庫表 方法1:通過創建單獨數據庫表biz_lock

CREATE TABLE `biz_lock` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `biz_name` varchar(64) NOT NULL DEFAULT '' COMMENT '鎖定的業務/資源',
  `remarks` varchar(1024) NOT NULL DEFAULT '備註信息',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '保存數據時間,自動生成',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uidx_biz_name` (`biz_name`) USING BTREE
)
 ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='鎖定中的業務/資源';

使用方式:當我們要鎖住某個方法或資源的時候,我們就在該表中增加一條記錄,想要釋放鎖的時候就刪除這條記錄。

(1).獲取鎖
insert into biz_lock(biz_name,remarks) values ('resort_room_stock_operate','酒店房間庫存操作')
(2).釋放鎖
delete from methodLock where biz_name ='biz_name'

方法2:基於數據庫表做樂觀鎖

   常用的方法是爲數據增加一個版本標識,每次修改記錄的時候需要比對版本號是否一致;
(1).查詢商品記錄下本次操作前的version
     select (id,status,version) from t_goods_info where id=#{id}
(2).根據商品信息生成訂單
(3).修改商品status爲2
     update t_goods_info
     set status=2,version=version+1
     where id=#{id} and version=#{version};

方法3:數據庫悲觀鎖 每次要操作前,先去數據庫獲取鎖,然後做操作完成提交

select * from t_goods_info  where id = #{id}  for update

二、redis實現的分佈式鎖(大概有三種方式)

(1).jredis自己實現

a.【setnx】+命令實現分佈式鎖(set if not exist)
b.lua腳本實現redis分佈式鎖

(2).Redisson實現

RedissonLock、RedissonRedLock

三、zookeeper

(1)、使用zookeeper API根據節點監聽和臨時有序節點功能實現
(2)、Apache Curator
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章