最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

通過lua實(shí)現(xiàn)redis 分布式鎖的項(xiàng)目實(shí)踐

 更新時(shí)間:2026年02月04日 10:28:10   作者:哈里謝頓  
在Redis中使用Lua腳本實(shí)現(xiàn)分布式鎖 是一種高效、原子、安全的方式,本文就來介紹一下通過lua實(shí)現(xiàn)redis分布式鎖,具有一定的參考價(jià)值,感興趣的可以了解一下

在 Redis 中使用 Lua 腳本實(shí)現(xiàn)分布式鎖 是一種高效、原子、安全的方式。由于 Lua 腳本在 Redis 中是單線程、原子執(zhí)行的,可以避免多個(gè)客戶端在加鎖/解鎖時(shí)出現(xiàn)競態(tài)條件(Race Condition)。

下面將為你提供一個(gè) 完整、生產(chǎn)可用的 Redis 分布式鎖 Lua 實(shí)現(xiàn)方案,包含:

  • 加鎖(lock)
  • 解鎖(unlock)
  • 自動(dòng)續(xù)期(可選)
  • 防止誤刪他人鎖
  • 支持可重入(可選)

? 一、核心設(shè)計(jì)原則

  1. 鎖的唯一標(biāo)識(shí):每個(gè)客戶端使用唯一的 value(如 UUID)作為鎖標(biāo)識(shí),防止 A 客戶端釋放 B 客戶端的鎖。
  2. 原子性操作:加鎖和解鎖必須通過 Lua 腳本保證原子性。
  3. 自動(dòng)過期:設(shè)置 TTL(如 30 秒),防止死鎖。
  4. 可重入支持(可選) :同一個(gè)客戶端可多次加鎖(需記錄重入次數(shù))。

本文先實(shí)現(xiàn) 基礎(chǔ)版(不可重入) ,再給出 可重入增強(qiáng)版。

? 二、基礎(chǔ)版:不可重入分布式鎖

?? 1. 加鎖腳本(lock.lua)

-- KEYS[1] = 鎖的 key(如 "my_lock")
-- ARGV[1] = 鎖的 value(唯一標(biāo)識(shí),如 UUID)
-- ARGV[2] = 過期時(shí)間(毫秒,如 "30000")

local key = KEYS[1]
local value = ARGV[1]
local ttl = tonumber(ARGV[2])

-- 嘗試加鎖:只有當(dāng) key 不存在時(shí)才設(shè)置成功
if redis.call("SET", key, value, "NX", "PX", ttl) then
    return 1  -- 加鎖成功
else
    return 0  -- 加鎖失?。ㄒ驯徽加茫?
end

? SET key value NX PX ttl 是 Redis 2.6.12+ 的原子命令:

  • NX:僅當(dāng) key 不存在時(shí)設(shè)置
  • PX:設(shè)置過期時(shí)間(毫秒)

?? 2. 解鎖腳本(unlock.lua)

-- KEYS[1] = 鎖的 key
-- ARGV[1] = 鎖的 value(用于驗(yàn)證是否是自己的鎖)

local key = KEYS[1]
local value = ARGV[1]

-- 獲取當(dāng)前鎖的 value
local current_value = redis.call("GET", key)

-- 如果存在且等于自己的 value,則刪除
if current值 == value then
    redis.call("DEL", key)
    return 1  -- 解鎖成功
else
    return 0  -- 不是自己的鎖,拒絕刪除
end

?? 注意:不能直接 DEL,否則可能誤刪別人的鎖!

? 三、Python 示例(使用 redis-py)

import redis
import uuid
import time

# 初始化 Redis 連接
r = redis.StrictRedis(host='localhost', port=6379, decode_responses=True)

# 加載 Lua 腳本(推薦使用 script_load + evalsha 提高性能)
lock_script = r.register_script("""
if redis.call("SET", KEYS[1], ARGV[1], "NX", "PX", ARGV[2]) then
    return 1
else
    return 0
end
""")

unlock_script = r.register_script("""
if redis.call("GET", KEYS[1]) == ARGV[1] then
    return redis.call("DEL", KEYS[1])
else
    return 0
end
""")

def acquire_lock(lock_name, acquire_timeout=10, lock_timeout=30):
    """獲取分布式鎖"""
    identifier = str(uuid.uuid4())
    lock_timeout_ms = int(lock_timeout * 1000)
    end_time = time.time() + acquire_timeout

    while time.time() < end_time:
        # 執(zhí)行 Lua 腳本嘗試加鎖
        if lock_script(keys=[lock_name], args=[identifier, lock_timeout_ms]):
            return identifier  # 返回鎖標(biāo)識(shí)
        time.sleep(0.01)  # 短暫等待后重試

    return False

def release_lock(lock_name, identifier):
    """釋放分布式鎖"""
    unlock_script(keys=[lock_name], args=[identifier])

# ===== 使用示例 =====
lock_key = "order:123:lock"

# 嘗試獲取鎖
lock_id = acquire_lock(lock_key, acquire_timeout=5, lock_timeout=30)
if lock_id:
    try:
        print("? 獲取鎖成功,執(zhí)行業(yè)務(wù)邏輯...")
        time.sleep(5)  # 模擬業(yè)務(wù)處理
    finally:
        # 釋放鎖
        release_lock(lock_key, lock_id)
        print("?? 鎖已釋放")
else:
    print("? 獲取鎖超時(shí)")

? 四、增強(qiáng)版:支持可重入鎖(Reentrant Lock)

適用于同一線程/協(xié)程需要多次進(jìn)入臨界區(qū)的場景。

設(shè)計(jì)思路:

  • 使用 Hash 結(jié)構(gòu) 存儲(chǔ)鎖:

    • field = 客戶端 ID(UUID)
    • value = 重入次數(shù)(counter)
  • 設(shè)置整體 TTL

?? 可重入加鎖腳本(reentrant_lock.lua)

-- KEYS[1] = 鎖 key
-- ARGV[1] = 客戶端 ID
-- ARGV[2] = 鎖過期時(shí)間(毫秒)

local key = KEYS[1]
local client_id = ARGV[1]
local ttl = tonumber(ARGV[2])

-- 檢查是否已持有鎖
local current_client = redis.call("HGET", key, client_id)

if current_client then
    -- 已持有:重入次數(shù) +1,刷新 TTL
    redis.call("HINCRBY", key, client_id, 1)
    redis.call("PEXPIRE", key, ttl)
    return 1
else
    -- 未持有:嘗試獲取鎖
    if redis.call("HLEN", key) == 0 then
        -- 鎖空閑,創(chuàng)建
        redis.call("HMSET", key, client_id, 1)
        redis.call("PEXPIRE", key, ttl)
        return 1
    else
        -- 鎖被他人持有
        return 0
    end
end

?? 可重入解鎖腳本(reentrant_unlock.lua)

-- KEYS[1] = 鎖 key
-- ARGV[1] = 客戶端 ID

local key = KEYS[1]
local client_id = ARGV[1]

-- 檢查是否持有鎖
local counter = redis.call("HGET", key, client_id)

if not counter then
    return 0  -- 未持有鎖
end

counter = tonumber(counter)

if counter > 1 then
    -- 重入次數(shù) >1,減1
    redis.call("HINCRBY", key, client_id, -1)
    return 1
else
    -- 最后一次,刪除整個(gè) key
    redis.call("DEL", key)
    return 1
end

?? 使用方式與基礎(chǔ)版類似,只需替換 Lua 腳本。

? 五、注意事項(xiàng)與最佳實(shí)踐

問題解決方案
鎖過期但業(yè)務(wù)未完成使用“看門狗”(Watchdog)線程自動(dòng)續(xù)期(如 Redisson 的機(jī)制)
主從切換導(dǎo)致鎖丟失使用 Redlock 算法(多 Redis 實(shí)例),但爭議較大;更推薦強(qiáng)一致存儲(chǔ)(如 etcd)
Lua 腳本調(diào)試?yán)щy在開發(fā)環(huán)境打印日志(redis.log(redis.LOG_WARNING, "msg"))
性能優(yōu)化使用 SCRIPT LOAD + EVALSHA 避免每次傳輸腳本

?? 重要提醒:
Redis 分布式鎖 不保證絕對(duì)安全(尤其在主從異步復(fù)制場景)。
對(duì)一致性要求極高的場景(如金融),建議使用 etcd / ZooKeeper。

? 六、總結(jié)

功能基礎(chǔ)版可重入版
原子加鎖??
防止誤刪??
自動(dòng)過期??
同客戶端多次加鎖??
復(fù)雜度

推薦:

  • 普通場景 → 用 基礎(chǔ)版
  • 需要遞歸調(diào)用/嵌套鎖 → 用 可重入版

通過以上 Lua 腳本 + 客戶端封裝,你可以在 Redis 中實(shí)現(xiàn)一個(gè)高效、安全、可靠的分布式鎖系統(tǒng)。

到此這篇關(guān)于通過lua實(shí)現(xiàn)redis 分布式鎖的項(xiàng)目實(shí)踐的文章就介紹到這了,更多相關(guān)lua redis 分布式鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • redis-benchmark并發(fā)壓力測(cè)試的問題解析

    redis-benchmark并發(fā)壓力測(cè)試的問題解析

    這篇文章主要介紹了redis-benchmark并發(fā)壓力測(cè)試的問題解析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • 淺談redis內(nèi)存數(shù)據(jù)的持久化方式

    淺談redis內(nèi)存數(shù)據(jù)的持久化方式

    這篇文章主要介紹了淺談redis內(nèi)存數(shù)據(jù)的持久化方式,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-03-03
  • 淺談Redis緩存擊穿、緩存穿透、緩存雪崩的解決方案

    淺談Redis緩存擊穿、緩存穿透、緩存雪崩的解決方案

    這篇文章主要介紹了淺談Redis緩存擊穿、緩存穿透、緩存雪崩的解決方案,緩存是分布式系統(tǒng)中的重要組件,主要解決在高并發(fā)、大數(shù)據(jù)場景下,熱點(diǎn)數(shù)據(jù)訪問的性能問題,需要的朋友可以參考下
    2023-03-03
  • Redis 延遲雙刪的實(shí)現(xiàn)示例

    Redis 延遲雙刪的實(shí)現(xiàn)示例

    延遲雙刪是在Cache-Aside基礎(chǔ)上,為了解決并發(fā)讀寫導(dǎo)致緩存回填舊值問題而設(shè)計(jì)的方案,本文就來詳細(xì)的介紹一下Redis 延遲雙刪的實(shí)現(xiàn)示例,感興趣的可以了解一下
    2026-05-05
  • Redis 高可用與集群原理深度解析

    Redis 高可用與集群原理深度解析

    Redis高可用機(jī)制涵蓋主從復(fù)制、哨兵自動(dòng)故障轉(zhuǎn)移及Cluster集群分片與高可用,依賴Gossip協(xié)議實(shí)現(xiàn)節(jié)點(diǎn)通信與狀態(tài)同步,源碼解析了故障轉(zhuǎn)移流程,為后續(xù)持久化內(nèi)容奠定基礎(chǔ),本文給大家介紹Redis高可用與集群原理,感興趣的朋友跟隨小編一起看看吧
    2025-09-09
  • SpringBoot整合Redis實(shí)現(xiàn)序列化存儲(chǔ)Java對(duì)象的操作方法

    SpringBoot整合Redis實(shí)現(xiàn)序列化存儲(chǔ)Java對(duì)象的操作方法

    這篇文章主要介紹了SpringBoot整合Redis實(shí)現(xiàn)序列化存儲(chǔ)Java對(duì)象,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03
  • 遠(yuǎn)程連接阿里云服務(wù)器上的redis報(bào)錯(cuò)的問題解決

    遠(yuǎn)程連接阿里云服務(wù)器上的redis報(bào)錯(cuò)的問題解決

    本文主要介紹了遠(yuǎn)程連接阿里云服務(wù)器上的redis報(bào)錯(cuò)的問題,出現(xiàn)?Redis Client On Error: Error: connect ECONNREFUSED 47.100.XXX.XX:6379?錯(cuò)誤,下面就來介紹一下解決方法,感興趣的可以了解一下
    2025-04-04
  • Redis @type坑的解決

    Redis @type坑的解決

    新建一個(gè)對(duì)象存入redis中,對(duì)象中會(huì)出現(xiàn)一個(gè)字段@type,本文主要介紹了Redis @type坑的解決,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-06-06
  • Redis String 類型和 Hash 類型學(xué)習(xí)筆記與總結(jié)

    Redis String 類型和 Hash 類型學(xué)習(xí)筆記與總結(jié)

    這篇文章主要介紹了Redis String 類型和 Hash 類型學(xué)習(xí)筆記與總結(jié),本文分別對(duì)String 類型的一些方法和Hash 類型做了詳細(xì)介紹,需要的朋友可以參考下
    2015-06-06
  • Redis的數(shù)據(jù)復(fù)制過程詳解

    Redis的數(shù)據(jù)復(fù)制過程詳解

    Redis 的復(fù)制功能分為同步(sync)和命令傳播(command propagate)這兩個(gè)操作,這篇文章主要介紹了Redis的數(shù)據(jù)復(fù)制,需要的朋友可以參考下
    2022-12-12

最新評(píng)論

长沙县| 定南县| 日土县| 邢台县| 奇台县| 纳雍县| 顺平县| 多伦县| 金溪县| 莒南县| 应城市| 常德市| 巴东县| 桑植县| 闸北区| 石楼县| 隆昌县| 信宜市| 新蔡县| 东阿县| 丰县| 绥芬河市| 凤台县| 湟源县| 隆安县| 屏南县| 察隅县| 西丰县| 吉首市| 延长县| 原阳县| 鄂尔多斯市| 吉林省| 胶南市| 沐川县| 合阳县| 遂平县| 贵阳市| 乌拉特前旗| 叙永县| 梁河县|