在單程序的系統中,當遇到併發情況下,會出現一些資料異常的問題,但是如果這些資料是需要保證唯一性的話,那我們就希望在同一時刻,只能有乙個執行緒在執行這塊**,通常我們一般都是通過簡單的加鎖或同步來實現並解決這個問題。
但是以上都是單程序多執行緒的情況,如果出現多程序多執行緒,顯然會出現問題。因為多執行緒之間是可以共享記憶體的,但是多程序之間是不行的,所以這個時候需要用到分布式鎖。
分布式鎖常用實現方案
分布式鎖通常是借助於乙個第三方元件並利用它自身的排他性來達到多程序的互斥。如下:
基於資料庫實現分布式鎖
基於快取,實現分布式鎖,如redis
基於zookeeper實現分布式鎖
基於資料庫:鎖實現也有兩種方式,一是基於資料庫表(建立一張鎖表),另一種是基於資料庫排他鎖。
基於zookeeper:鎖的實現是依靠臨時有序節點,每個客戶端對某個方法加鎖時,在zookeeper上的與該方法對應的指定節點的目錄下,生成乙個唯一的瞬時有序節點。
基於快取:下面我們要重點講的就是redis。基於 redis 的 nx ex 引數。
基於redis的分布式鎖實現
redis有一系列的命令,其特點是以nx結尾,nx的意思可以理解為 not exists(不存在),setnx命令 (set if not exists) 可以理解為如果不存在則插入,redis分布式鎖的實現主要就是使用setnx命令
1、使用setnx() 設定鎖
$expire = 10;//有效期10秒
$key = 'lock';//key
$value = time() + $expire;//鎖的值 = unix時間戳 + 鎖的有效期
$lock = $redis->setnx($key, $value);
//判斷是否上鎖成功,成功則執行下步操作
if(!empty($lock))
如果返回 1 ,則表示當前程序獲得鎖,並獲得了當前插入/更新快取的操作許可權。
如果返回 0,表示鎖已被其他程序獲取,這是程序可以返回結果或者等待當前鎖失效再請求。
2、存在死鎖的問題
如果單單只用setnx命令設定鎖的話,如果當持有鎖的程序崩潰或刪除鎖失敗時,其他程序將無法獲取到鎖,問題就大了。
解決方法是在獲取鎖失敗的同時獲取鎖的值,並將值與當前時間進行對比,如果值小於當前時間說明鎖以過期失效,程序可運用redis的del命令刪除該鎖
$expire = 10;//有效期10秒
$key = 'lock';//key
$value = time() + $expire;//鎖的值 = unix時間戳 + 鎖的有效期
$status = true;
while($status)
}else
}但是,簡單粗暴的用del命令刪除鎖再setnx命令上鎖也會出現問題。比如,程序1獲得鎖後崩潰或刪除鎖失敗,這時程序2檢測到鎖存在當已過期,用del命令刪除鎖並用setnx命令設定鎖,程序3也檢測到鎖過期,也用del命令刪除鎖也用setnx命令設定了鎖,這時程序2和程序3同時獲得了鎖。問題大了
為了解決這個問題,這裡用到了redis的getset命令,getset命令在給鎖設定新值的同時返回鎖的舊值,這裡利用了getset命令同時獲取和賦值的特性,在此期間其他程序無法修改鎖的值。
例如:程序1獲得鎖後操作超時/崩潰/刪除鎖失敗,
程序2檢測到鎖已存在,但獲取鎖的值對比當前時間發現鎖已過期,
程序2通過getset命令重新給鎖賦予新的值,並獲取到的鎖的舊值,再次對比鎖的舊值與當前時間,如果鎖的舊值依然小於當前時間的話,這時程序2就可以忽略程序1餘留下的廢鎖進行下步操作了。
程序2完成下步操作後返回前應該刪除鎖,但在刪除鎖時可以先檢測鎖是否還未過期,未過期才做刪除操作,已過期的就沒必要在去刪除鎖了,因為很有可能其他程序檢測到鎖過期時已經去獲取鎖了。
這裡要說明的是,如果有其他程序在程序2之前獲取到鎖,那麼程序2將獲取鎖失敗,但是程序2在用getset獲取鎖的舊值時也賦予了鎖新的值,改寫了其他程序賦予鎖的超時值。看到這大家可能會有疑問了,程序2沒獲取到鎖怎麼能改變鎖的值呢?是的,程序2改變了鎖的原有值,但這一點小小的時間誤差帶來的影響是可以忽略。
3、以下是redis實現分布式鎖的完整php**:
<?php
/*** 實現redis分布鎖
*/$key = 'test'; //要更新資訊的快取key
$lockkey = 'lock:'.$key; //設定鎖key
$lockexpire = 10; //設定鎖的有效期為10秒
//獲取快取資訊
$result = $redis->get($key);
//判斷快取中是否有資料
if(empty($result))
else
}
redis 分布式鎖 PHP
redis分布式 1.redis是單執行緒操作 2.分布式會出現的問題,死鎖 3.redis分布式 集群 多台伺服器裡面都有多個單機redis。然後這些redis之間相互鏈結。還有檢視各個單台伺服器之間是否鏈結成功,也就是心跳檢測 4.在資料方面,他們之間有個鎖的問題,叫redis分布式鎖 常規流程...
Redis實現分布式鎖 php
一 分布式鎖的作用 redis寫入時不帶鎖定功能,為防止多個程序同時進行乙個操作,出現意想不到的結果,so.對快取進行插入更新操作時自定義加鎖功能。二 redis的nx字尾命令 redis有一系列的命令,其特點是以nx結尾,nx的意思可以理解為 not exists 不存在 setnx命令 set ...
PHP實現Redis分布式鎖
鎖在我們的日常開發可謂用得比較多。通常用來解決資源併發的問題。特別是多機集群情況下,資源爭搶的問題。但是,很多新手在鎖的處理上常常會犯一些問題。今天我們來深入理解鎖。一 redis 鎖錯誤使用之一 我曾經見過有的專案把查詢結果儲存到 redis 當中時的偽 如下 redis new redis 12...