⑴ Redis 中使用 Lua 腳本
Redis 本身已經提供了豐富的命令,但是直接用來處理一些復雜業務時可能還不夠方便,會有一定的局限性。因此,在 Redis2.6 版本開始提供了對 Lua 腳本的支持,Lua 腳本的使用還是比較廣泛的,比如商品秒殺、分布式鎖等,使用 Lua 腳本可以帶來以下的好處:
為了讓例子更加的貼近實際應用,這里實現一個簡單版的分布式鎖。這里先用 Jedis 操作。
上邊詳細的介紹了分布式鎖的實現過程,以及可能出現的問題,最終,我們決定刪除鎖的操作使用 Lua 腳本實現,對應的腳本如下:
Lua 腳本中執行具體的 Redis 命令,需要使用 redis.call() 方法, KEYS 表示客戶端發起腳本執行命令時攜帶的 Redis key 的一個集合, ARGV 則是其它參數的一個集合,主意下標從1開始。結合我們的業務,這里的 KEYS[1] 則表示 lock , ARGV[1] 則是一個隨機字元串。整個腳本的含義就是,如果客戶端傳遞的 lock 的 value 和 Redis 中存儲的一致,就刪除 lock 。
Lua 腳本的語法還是比較簡單的,具體內容可以自行學習。
前邊的准備工作基本結束了,文章開始說過執行腳本有兩種途徑,下邊我們具體來看:
這里使用 jedis.eval() 發送腳本到 Redis 伺服器執行,後兩個參數分別是 key 的集合,以及 value 參數的集合。
先將腳本以文件形式放到 Redis 里,例如這樣:
然後通過如下命令讓 Redis 伺服器緩存腳本:
script load 命令會在 Redis 伺服器緩存 Lua 腳本,並且腳本內容經過 SHA-1 簽名演算法處理後,會返回腳本內容的 SHA1 校驗和的編碼,然後在端調用時,傳入編碼字元串作為參數,這樣 Redis 伺服器就會執行對應緩存的腳本了,就不用了每次發送具體的腳本內容了。
還有兩個比較有用的命令:
除了使用上邊的命令緩存腳本、生成腳本的 SHA1 校驗和的編碼,還可以使用 Jedis 實現,但最終的 SHA1 編碼內容是不同的:
實際的項目中,可能更多的會在 SpringBoot 項目中整合 Redis,此時執行 Lua 腳本的基本流程如下:
核心的類就是 DefaultRedisScript ,它實現了 RedisScript 介面。 execute() 方法最後一個參數是可變類型的,用來傳遞多個 value 參數。初次執行 execute() 方法時,其內部會自動緩存 Lua 腳本到 Redis 伺服器;同時每次執行腳本時會根據腳本內容自動計算出對應的 SHA1 校驗和的編碼,去匹配、執行緩存的腳本。
具體的 SHA1 校驗和的編碼,可以在 execute() 方法執行後,使用 redisScript.getSha1() 查看。使用 SpringBoot 方式 執行 Lua 腳本生成的 SHA1 校驗和的編碼和前邊直接使用 Jedis 生成的一致。
無論用那種方式在 Redis 中使用 Lua 腳本,其中的原理都是類似的。
⑵ 為什麼在 Redis 實現 Lua 腳本事務
數據完整性
從很多方面來看,Redis 很像當初採用 InnoDB 前的 MySQL。而 Redis 採用了一種很合理的方式來保證數據完整性(復制,AOF 等),並且從 Redis2.6 開始引入的 Lua 腳本在功能與易用性方面為 Redis 的成長提供了很大助力。
相對來說,Lua 腳本與其他資料庫中的存儲過程很相似,但腳本的執行有些許不同。在本文中最重要的一點就是一旦將腳本寫入資料庫,它會一直執行直到以下任一種情況出現:
1. 完成所有工作,所有寫操作處理完成後腳本會自動退出。
2. 腳本運行時出錯並中途退出,所有以前執行的寫操作都已發生,但不會再有其他寫操作。
3. Redis 通過 SHUTDOWN NOSAVE 關閉時(不保存)。
4. 你附加了調試器來「使」腳本完成 #1 與 #2 (或其他手段來保證不會丟失數據)。
對於使用資料庫開發軟體的人,我想你也認同只有情景 #1 是最理想的。情景 #2,#3,#4 都會導致數據異常(#2 與
#4)和/或數據丟失(#3 和 #4)。如果你很重視數據,你應該盡可能地阻止數據異常與丟失。這不是哲學,而是工作(This is not
philosophy, this is doing your job)。但很遺憾目前的 Redis 也幫不了你多少。所以我決定改變這種情況。
⑶ redis lua腳本有什麼用
主要用途是: (1)描述界面:WOW和劍網三的界面都是用LUA寫的; (2)溝通引擎:游戲圖形引擎提供了一些介面庫,可以在LUA中調用; (3)伺服器端:有些游戲,例如劍網三,在伺服器端也會大量使用LUA。