lua腳本在redis中執行是否是原子性?
以及是否會阻塞其他腳本的執行【客戶端的請求】?
先解答第二個問題:
是的,保持原子執行。這也是redis中支持lua腳本執行的原因。
Lua 腳本在 Redis 中是以原子方式執行的,在 Redis 服務器執行EVAL命令時,在命令執行完畢并向調用者返回結果之前,只會執行當前命令指定的 Lua 腳本包含的所有邏輯,其它客戶端發送的命令將被阻塞,直到EVAL命令執行完畢為止。因此 LUA 腳本不宜編寫一些過于復雜了邏輯,必須盡量保證 Lua 腳本的效率,否則會影響其它客戶端。
Redis 提供了豐富的命令來供我們使用以實現一些計算。Redis 的單個命令都是原子性的,有時候我們希望能夠組合多個 Redis 命令,并讓這個組合也能夠原子性的執行,甚至可以重復使用。Redis 開發者意識到這種場景還是很普遍的,就在 2.6 版本中引入了一個特性來解決這個問題,這就是 Redis 執行 Lua 腳本。
lua腳本是否在redis主線程中執行?
在 Redis 中,Lua 腳本的執行是在主線程中進行的。當客戶端發送 Lua 腳本到 Redis 服務器時,Redis 會將腳本解析并編譯成字節碼,并將其存儲在服務器內部的腳本緩存中。當客戶端再次執行同一個腳本時,Redis 可以直接使用緩存中的字節碼來執行腳本,從而避免了重復解析和編譯的開銷。
因為 Lua 腳本是在 Redis 主線程中執行的,所以執行較長時間的腳本可能會導致阻塞其他客戶端請求的執行。為了避免這種情況,可以將一些長時間執行的操作拆分成多個步驟,使用 Redis 的 Lua 腳本執行和服務器端腳本緩存來優化腳本的性能。同時,還可以使用 Redis 的任務隊列或消息隊列來將長時間執行的操作移動到后臺處理,從而避免阻塞主線程并提高系統的并發性能。
了解了上面這些知識基本上可以滿足開發一些簡單的 Lua 腳本了。但是實際開發中還是有一些要點的。
- 務必對 Lua 腳本進行全面測試以保證其邏輯的健壯性,當 Lua 腳本遇到異常時,已經執行過的邏輯是不會回滾的。【如果是redis本身自帶支持的命令呢?都是原子性的,也就是只會存在兩種狀態,成功or失敗】
- 盡量不使用 Lua 提供的具有隨機性的函數,參見相關官方文檔。
- 在 Lua 腳本中不要編寫function函數, 整個腳本作為一個函數的函數體。
- 在腳本編寫中聲明的變量全部使用local關鍵字。
- 在集群中使用 Lua 腳本要確保邏輯中所有的key分到相同機器,也就是同一個插槽(slot)中,可采用Redis Hash Tag技術。
- 再次重申 Lua 腳本一定不要包含過于耗時、過于復雜的邏輯。(否則將導致redis宕機, 影響所有使用到redis的服務)