首頁 資料庫 Redis Go語言中怎麼透過Lua腳本操作Redis

Go語言中怎麼透過Lua腳本操作Redis

May 27, 2023 pm 07:52 PM
redis lua go語言

前言

為了在我的一個基本函式庫中降低Redis的通訊成本,我將一系列作業封裝到LUA腳本中,借助Redis提供的EVAL指令來簡化操作。

EVAL能夠提供的特性:

  • #可以在LUA腳本中封裝若干操作,如果有多條Redis指令,封裝好之後只需向Redis一次發送所有參數即可獲得結果

  • Redis可以保證Lua腳本運行期間不會有其他命令插入執行,提供像資料庫事務一樣的原子性

  • Redis會根據腳本的SHA值快取腳本,已經快取過的腳本不需要再次傳輸Lua程式碼,減少了通訊成本,此外在自己程式碼中改變Lua腳本,執行時Redis必定也會使用最新的程式碼。

導入常見的Go函式庫如 "github.com/go-redis/redis",就可以實作下列程式碼。

產生一段Lua腳本

1

2

3

4

5

6

7

8

// KEYS: key for record

// ARGV: fieldName, currentUnixTimestamp, recordTTL

// Update expire field of record key to current timestamp, and renew key expiration

var updateRecordExpireScript = redis.NewScript(`

redis.call("EXPIRE", KEYS[1], ARGV[3])

redis.call("HSET", KEYS[1], ARGV[1], ARGV[2])

return 1

`)

登入後複製

該變數建立時,Lua程式碼不會被執行,也不需要有已儲存的Redis連線。

Redis提供的Lua腳本支持,預設有KEYS、ARGV兩個數組,KEYS代表腳本運行時傳入的若干鍵值,ARGV代表傳入的若干參數。由於Lua程式碼需要保持簡潔,難免難以讀懂,最好為這些參數寫一些註解

#注意:上面一段程式碼使用``跨行,`所在的行雖然空白回車,也會被認為是一行,報錯時不要看錯代碼行號。

執行一段Lua腳本

1

2

3

 updateRecordExpireScript.Run(c.Client, []string{recordKey(key)}, 

         expireField,

         time.Now().UTC().UnixNano(), int64(c.opt.RecordTTL/time.Second)).Err()

登入後複製

執行時,Run將會先透過EVALSHA嘗試透過快取執行腳本。如果沒有緩存,則使用EVAL運行,這時Lua腳本才會被整個傳入Redis。

Lua腳本的限制

  • Redis不提供引入額外的包,例如os等,只有redis這一包可用。

  • Lua腳本將會在一個函數中執行,所有變數必須使用local宣告

  • return傳回多個值時,Redis將會只給你第一個

腳本中的型別限制

  • #腳本回傳nil時,Go中得到的是err = redis.Nil(與Get找不到值相同)

  • #腳本回傳false時,Go中得到的是nil,當腳本回傳true時, Go中得到的是int64型別的1

  • 在腳本回傳{"ok": ...}時,Go中得到的是redis的status型別(true/false)

  • 腳本回傳{"err": ...}時,Go中得到的是err值,也可以透過return redis.error_reply("My Error")達成

  • 腳本傳回number型別時,Go中得到的是int64型別

  • 在腳本中,如果需要將傳入的KEYS/ ARGV中的值從字串類型轉換為數字類型,則應使用to_number函數

#如果腳本運行了很久會發生什麼?

Lua腳本運行期間,為了避免被其他操作污染數據,這段期間將不能執行其它命令,一直等到執行完畢才可以繼續執行其它請求。當Lua腳本執行時間超過了lua-time-limit時,其他請求將會收到Busy錯誤,除非這些請求是SCRIPT KILL(殺掉腳本)或SHUTDOWN NOSAVE(不儲存結果直接關閉Redis)

更多內容參考以下地址,我這裡主要是根據使用Go的經驗提供一些總結。 https://redis.io/commands/eval

一段更「複雜」的腳本,它要求在取得一個key值時,如果該值訪問較多,就延長生存週期。另外也要比較更新時間,如果不需要更新,直接傳回取到的值,否則回傳redis.Nil

1

2

3

4

5

6

7

8

// KEYS: rec:key, key

// ARGV: currentUnixTimestamp, hotHit, recordTTL, ttl

// When there's a hit,

var fetchRecordScript = redis.NewScript(local value = redis.call("GET", KEYS[2]) if(value == nil) then return nil end local hit = redis.call("HINCRBY", KEYS[1], "hit", 1) redis.call("EXPIRE", KEYS[1], ARGV[3]) local minHotHit = tonumber(ARGV[2]) local keyTTL = tonumber(ARGV[4]) if(hit > minHotHit)then keyTTL = keyTTL * 2 end redis.call("EXPIRE", KEYS[2], keyTTL) local expire = tonumber(redis.call("HGET", KEYS[1], "expire")) local unixTime = tonumber(ARGV[1]) if(expire == nil or expire < unixTime) then return nil else return value end)

// KEYS: key for record

// ARGV: fieldName, currentUnixTimestamp, recordTTL

// Update expire field of record key to current timestamp, and renew key expiration

var updateRecordExpireScript = redis.NewScript(redis.call("EXPIRE", KEYS[1], ARGV[3]) redis.call("HSET", KEYS[1], ARGV[1], ARGV[2]) return 1)

登入後複製

以上是Go語言中怎麼透過Lua腳本操作Redis的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱門文章

倉庫:如何復興隊友
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱門文章

倉庫:如何復興隊友
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱門文章標籤

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

Windows11安裝10.0.22000.100跳出0x80242008錯誤解決方法 Windows11安裝10.0.22000.100跳出0x80242008錯誤解決方法 May 08, 2024 pm 03:50 PM

Windows11安裝10.0.22000.100跳出0x80242008錯誤解決方法

golang 如何使用反射存取私有欄位和方法 golang 如何使用反射存取私有欄位和方法 May 03, 2024 pm 12:15 PM

golang 如何使用反射存取私有欄位和方法

Golang API快取策略與最佳化 Golang API快取策略與最佳化 May 07, 2024 pm 02:12 PM

Golang API快取策略與最佳化

PHP開發中的快取機制與應用實戰 PHP開發中的快取機制與應用實戰 May 09, 2024 pm 01:30 PM

PHP開發中的快取機制與應用實戰

Go語言中的效能測試與單元測試的差異 Go語言中的效能測試與單元測試的差異 May 08, 2024 pm 03:09 PM

Go語言中的效能測試與單元測試的差異

Win11英文21996怎麼升級到簡體中文22000_Win11英文21996升級到簡體中文22000的方法 Win11英文21996怎麼升級到簡體中文22000_Win11英文21996升級到簡體中文22000的方法 May 08, 2024 pm 05:10 PM

Win11英文21996怎麼升級到簡體中文22000_Win11英文21996升級到簡體中文22000的方法

Golang技術在設計分散式系統時應注意哪些陷阱? Golang技術在設計分散式系統時應注意哪些陷阱? May 07, 2024 pm 12:39 PM

Golang技術在設計分散式系統時應注意哪些陷阱?

Golang技術在機器學習中使用的函式庫和工具 Golang技術在機器學習中使用的函式庫和工具 May 08, 2024 pm 09:42 PM

Golang技術在機器學習中使用的函式庫和工具

See all articles