婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > php基于redis的分布式鎖實例詳解

php基于redis的分布式鎖實例詳解

熱門標簽:百度商鋪地圖標注 常州地圖標注服務商 地圖標注平臺怎么給錢注冊 衡水外呼系統(tǒng)平臺 注冊400電話申請 福州人工外呼系統(tǒng)哪家強 新河科技智能外呼系統(tǒng)怎么樣 釘釘打卡地圖標注 安裝電銷外呼系統(tǒng)

在使用分布式鎖進行互斥資源訪問時候,我們很多方案是采用redis的實現(xiàn)。
固然,redis的單節(jié)點鎖在極端情況也是有問題的,假設你的業(yè)務允許偶爾的失效,使用單節(jié)點的redis鎖方案就足夠了,簡單而且效率高。

redis鎖失效的情況:

客戶端1從master節(jié)點獲取了鎖
master宕機了,存儲鎖的key還沒來得及同步到slave節(jié)點上
slave升級為master
客戶端2從新的master上獲取到同一個資源的鎖
于是,客戶端1和客戶端2同事持有了同一個資源的鎖,鎖的安全性被打破。
如果我們不考慮這種極端情況,需要實現(xiàn)一個基于單節(jié)點redis鎖的大致流程:

set cache_key random_seed NX PX 30000

上面這個set命令拆解開就是:

setnx cache_key random_seed 
expire cache_key 30

雖然這兩組命令執(zhí)行的效果一樣,但是第二個是非原子性操作,如果執(zhí)行了setnx成功,但是expire失敗的話,就會造成這個key一直存在了,無法釋放的情況。

redis的作者也指出,在使用單節(jié)點redis鎖的時候,設置一個隨機種子作為key的值是很有必要的,保證了一個客戶端釋放的鎖必須是自己所持有的那個鎖。假設獲取鎖時set的不是一個隨機數(shù),而是一個固定值,

那么可能會出現(xiàn)下面的情況:

客戶端1獲取鎖成功
客戶端1在某個操作上阻塞了很長時間
過期時間到了,鎖自動釋放(但是在客戶端1看來自己還是持有鎖中)
客戶端2獲取到了對應同一個資源的鎖
客戶端1從阻塞中恢復了,釋放掉自己持有的鎖,也就是釋放掉了客戶端2持有的鎖
客戶端2的鎖被客戶端1是否,失去安全性。
釋放鎖的操作,很多人直接用del命令,這會有很大的問題,保證不了這個key是被加鎖人鎖刪。這時候需要用到隨機數(shù)了。

釋放鎖的操作有三步:

get 所持有鎖
判斷這個鎖是否自己所持有
刪除持有鎖
所以,這三步要保證原子性。用lua腳本來執(zhí)行,redis官方已經(jīng)提供腳本文件。

if redis.call("get",KEYS[1]) == ARGV[1] then
  return redis.call("del",KEYS[1])
else
  return 0
end

這段腳本在執(zhí)行的時候,需要把前面的隨機數(shù)作為argv[1] 的值傳進去,把cache_key作為keys[1]的值傳進去。

public class RedisLockHelper {
  @Resource
  private R2mClusterClient r2mClusterClient;

  /**
   * 類似于setNx的功能,同時設置過期時間為expire毫秒
   *
   * @param key  加鎖key
   * @param value 確保在加鎖時間內(nèi)的唯一因子
   * @param expire 過期時間的毫秒數(shù)
   * @return
   */
  private String setLock(String key, String value, long expire) {
    return this.set(key, value, "NX", "PX", expire);
  }

  /**
   * 刪除指定key value
   * 如果 r2m中 key 對應的value==value  返回 1
   * 如果 r2m中 key 對應的value!=value  返回 0
   *
   * @param key
   * @return
   */
  private boolean atomDelete(String key, String value) {
    ListString> values = new ArrayList>();
    values.add(value);
    String sb = "if redis.call('get',KEYS[1])==ARGV[1] then " +
        " return redis.call('del',KEYS[1]) " +
        " else " +
        " return 0" +
        " end";
    if (this.eval(sb, key, values) == 1) {
      return true;
    }
    return false;
  }

  private Long eval(String mobel, String key, ListString> value) {
    return (Long) this.r2mClusterClient.eval(mobel, key, value);
  }

  private String set(String key, String value, String nxxx, String expx, long time) {
    return this.r2mClusterClient.set(key, value, nxxx, expx, time);
  }
}

r2mClusterClient 就是jedis客戶端的封裝。

到此這篇關于php基于redis的分布式鎖實例詳解的文章就介紹到這了,更多相關php基于redis的分布式鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • 詳解PHP解決守護進程Redis假死
  • thinkphp5redis緩存新增方法實例講解
  • PHP使用Redis隊列執(zhí)行定時任務實例講解
  • Thinkphp5+Redis實現(xiàn)商品秒殺代碼實例講解
  • PHP操作Redis常用命令的實例詳解
  • php在linux環(huán)境中如何使用redis詳解
  • php操作redis命令及代碼實例大全
  • php之redis短線重連案例講解

標簽:六安 鶴崗 克拉瑪依 柳州 白城 鷹潭 遼陽 唐山

巨人網(wǎng)絡通訊聲明:本文標題《php基于redis的分布式鎖實例詳解》,本文關鍵詞  php,基于,redis,的,分布式,;如發(fā)現(xiàn)本文內(nèi)容存在版權問題,煩請?zhí)峁┫嚓P信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《php基于redis的分布式鎖實例詳解》相關的同類信息!
  • 本頁收集關于php基于redis的分布式鎖實例詳解的相關信息資訊供網(wǎng)民參考!
  • 推薦文章
    主站蜘蛛池模板: 夹江县| 正宁县| 山阴县| 霍城县| 大新县| 观塘区| 桐城市| 客服| 阿拉善右旗| 常熟市| 丹江口市| 镶黄旗| 德钦县| 陈巴尔虎旗| 农安县| 宁化县| 常山县| 绥滨县| 石渠县| 浪卡子县| 和硕县| 汝南县| 磴口县| 错那县| 比如县| 米林县| 宿迁市| 荣成市| 江门市| 镇坪县| 满洲里市| 景宁| 朝阳市| 白朗县| 城步| 香港 | 临江市| 来凤县| 建阳市| 海城市| 台州市|