Docker中Redis執(zhí)行Lua腳本的兩種方案
最近在做Redis分布式鎖、接口限流的時候,用到了Lua腳本,畢竟Redis單線程執(zhí)行Lua,能保證操作的原子性,避免并發(fā)問題,但在實際落地時卻發(fā)現(xiàn)一個問題:項目部署在 Docker 環(huán)境下時,Redis 的 Lua 腳本到底該怎么放、怎么執(zhí)行才最穩(wěn)妥。
先提前說個核心結(jié)論:Redis的Lua腳本不需要編譯、不需要安裝,核心就是“讓Redis能找到腳本文件”,再用簡單的命令執(zhí)行就行。Docker部署 Redis Lua,優(yōu)先用「目錄掛載」,測試用「直接復(fù)制文件」
一、Redis Lua腳本執(zhí)行的本質(zhì)
很多人會誤以為Lua腳本需要像部署應(yīng)用一樣,安裝依賴、啟動服務(wù)——其實完全不用!
Redis本身就內(nèi)置了Lua解釋器,只要Redis能讀取到Lua腳本文件,或者你直接把腳本內(nèi)容傳給Redis,它就能直接執(zhí)行。咱們在Docker里要做的,本質(zhì)就是「讓Redis容器能訪問到Lua腳本」,剩下的就是Redis的原生命令操作。
另外補充兩個關(guān)鍵知識點:
- Redis執(zhí)行Lua腳本有兩種方式:直接傳腳本內(nèi)容(EVAL命令)、緩存腳本后用SHA值調(diào)用(SCRIPT LOAD + EVALSHA,性能更高,生產(chǎn)推薦);
- Docker里的Redis容器,默認沒有宿主機的文件權(quán)限,所以不能直接讀取宿主機的腳本,要么掛載目錄,要么把腳本復(fù)制進容器。
二、生產(chǎn)環(huán)境首選:目錄掛載(最規(guī)范,方便維護)
這種方式是生產(chǎn)環(huán)境最推薦的,核心邏輯是「把宿主機的一個文件夾,掛載到Redis容器里」,這樣我們在宿主機修改、新增Lua腳本,容器里就能實時同步,不用每次都復(fù)制文件,后期維護特別方便。
步驟1:啟動Redis容器,掛載目錄
先停止并刪除舊的Redis容器(如果有的話),然后執(zhí)行以下命令,啟動一個新的Redis容器,并掛載宿主機目錄:
# 先創(chuàng)建宿主機存放Lua腳本的目錄(自定義路徑,我這里用/home/redis/lua) mkdir -p /home/redis/lua chmod 777 /home/redis/lua # 給權(quán)限,避免容器訪問不到 # 啟動Redis容器,掛載目錄 docker run -d \ --name wzxgRedis # 容器名字,自定義 -p 6379:6379 # 端口映射,宿主機6379對應(yīng)容器6379 -v /home/redis/lua:/lua # 掛載:宿主機路徑:/容器內(nèi)路徑 redis:latest redis-server # 啟動Redis服務(wù)
注:-v /home/redis/lua:/lua 這一句,就是把宿主機的/home/redis/lua文件夾,和容器里的/lua文件夾關(guān)聯(lián)起來,相當于“共享文件夾”,宿主機放腳本,容器里就能直接看到。
步驟2:在宿主機編寫Lua腳本
在宿主機的掛載目錄里寫腳本,容器里會自動同步,不用再手動復(fù)制。比如寫一個簡單的“自增計數(shù)”腳本。
# 進入宿主機的Lua腳本目錄 cd /home/redis/lua # 創(chuàng)建并編輯腳本(也可以用記事本編輯后上傳) vim wzxg.lua
腳本內(nèi)容
-- KEYS[1]:傳入的第一個key(后續(xù)執(zhí)行時指定)
-- redis.call():調(diào)用Redis原生命令
local key = KEYS[1]
-- 對key進行自增,返回自增后的值
local count = redis.call("INCR", key)
return count
保存退出vim(按ESC,輸入:wq,回車即可)。這時候,容器里的/lua目錄下,wzxg.lua腳本,因為我們掛載了目錄。
步驟3:進入容器,執(zhí)行Lua腳本
腳本準備好了,接下來進入Redis容器,用Redis命令執(zhí)行腳本,兩種方式任選,優(yōu)先推薦方式2(性能更高)。
# 進入Redis容器的redis-cli客戶端 docker exec -it wzxgRedis redis-cli
方式1:直接加載文件執(zhí)行(測試用,簡單)
直接讀取容器內(nèi)的腳本文件,一次性執(zhí)行,適合測試腳本是否能正常運行:
EVAL "$(cat /lua/wzxg.lua)" 1 mycounter
拆解一下這個命令:
- EVAL:Redis執(zhí)行Lua腳本的核心命令;
- “$(cat /lua/test.lua)”:讀取容器內(nèi)/lua目錄下的test.lua腳本內(nèi)容;
- 1:表示后續(xù)傳入的KEYS數(shù)量(這里我們只傳一個key,就是mycounter);
- mycounter:傳入的KEYS[1],也就是腳本里的key變量。
執(zhí)行后,會返回1(第一次自增),再執(zhí)行一次返回2,說明腳本執(zhí)行成功!
方式2:緩存腳本,用SHA值調(diào)用(生產(chǎn)推薦)
如果腳本需要頻繁執(zhí)行,每次都傳腳本內(nèi)容會浪費帶寬,這時候可以把腳本緩存到Redis里,Redis會返回一個唯一的SHA值,后續(xù)直接用SHA值調(diào)用即可,性能更高。
# 1. 緩存腳本,返回SHA值 SCRIPT LOAD "$(cat /lua/wzxg.lua)"
SHA 值是 Redis 對 Lua 腳本內(nèi)容進行哈希計算后,生成的一串唯一字符串(比如 54cfc1234567890abcdef...),相當于這個腳本的 “專屬標識”—— 只要腳本內(nèi)容不變,SHA 值就不變;腳本一改,SHA 值就會變。
# 2. 用SHA值執(zhí)行腳本,參數(shù)和EVAL一樣 EVALSHA 54cfc1234567890abcdef 1 mycounter
效果和方式1一樣,但后續(xù)每次執(zhí)行,只需要傳SHA值,不用再傳整個腳本,適合生產(chǎn)環(huán)境頻繁調(diào)用的場景。
三、測試用簡易方案:直接復(fù)制腳本進容器
如果只是臨時測試腳本,不想掛載目錄,也可以直接把宿主機的腳本復(fù)制進Redis容器,步驟更簡單,適合快速測試。
# 1. 宿主機創(chuàng)建腳本(比如還是wzxg.lua,路徑隨意,比如~/wzxg.lua) # 2. 復(fù)制腳本到Redis容器的/lua目錄(沒有這個目錄會自動創(chuàng)建) docker cp ~/wzxg.lua wzxgRedis:/lua/wzxg.lua # 3. 進入redis-cli執(zhí)行(和上面步驟3一樣) docker exec -it wzxgRedis redis-cli EVAL "$(cat /lua/wzxg.lua)" 1 mycounter
注意:這種方式,宿主機修改腳本后,不會同步到容器里,需要重新執(zhí)行docker cp命令復(fù)制,所以只適合測試,不適合生產(chǎn)環(huán)境。
四、踩過的坑
- 掛載目錄時,一定要給宿主機目錄權(quán)限(chmod 777),否則容器里會提示“權(quán)限不足”,讀不到腳本;
- 執(zhí)行腳本時,KEYS的數(shù)量一定要寫對(EVAL后面的數(shù)字),比如傳2個key,就寫2,否則會報錯;
- 生產(chǎn)環(huán)境一律用「SCRIPT LOAD + EVALSHA」,避免每次傳腳本浪費帶寬;
- Lua腳本里只能用Redis支持的命令(redis.call()),不能寫復(fù)雜的循環(huán)和邏輯,因為Redis是單線程,腳本執(zhí)行時間過長會阻塞Redis;
- 如果腳本里有中文注釋,保存時一定要用UTF-8編碼,否則會出現(xiàn)亂碼,導(dǎo)致腳本執(zhí)行失敗。
以上就是Docker中Redis執(zhí)行Lua腳本的兩種方案的詳細內(nèi)容,更多關(guān)于Docker Redis執(zhí)行Lua腳本的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
云原生Docker創(chuàng)建并進入mysql容器的全過程
前面我們已經(jīng)安裝好了Docker,也簡單了解了Docker,下面這篇文章主要給大家介紹了關(guān)于云原生Docker創(chuàng)建并進入mysql容器的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-02-02
Docker拉取鏡像時遇到dial tcp...443:i/o timeout錯誤的解決方案
本文介紹了如何解決在使用Docker時遇到的網(wǎng)絡(luò)超時問題,包括配置鏡像加速服務(wù)以提高鏡像拉取速度和穩(wěn)定性2025-12-12
如何批量刪除Docker中已經(jīng)停止的容器的幾種方法
本文主要介紹了批量刪除Docker中已經(jīng)停止的容器的幾種方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
ssh 直接登錄docker容器的操作方法(不用通過宿主機進入)
這篇文章主要介紹了ssh 直接登錄docker容器的操作方法(不用通過宿主機進入),本文給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧2024-06-06
docker入門教程(利用docker部署web應(yīng)用)
docker是一個用來裝應(yīng)用的容器,就像杯子可以裝水,筆筒可以放筆,書包可以放書,可以把hello word放在docker中,可以把網(wǎng)站放入docker中,可以把任何想得到的程序放在docker中,這篇文章主要介紹了docker入門(利用docker部署web應(yīng)用),需要的朋友可以參考下2023-02-02

