首頁>技術>

2、為什麼需要Lua指令碼?

簡而言之:效能提升。您在Redis中執行的大多數任務都涉及許多步驟。您可以使用Lua在Redis內部進行操作,而不必使用應用程式語言來執行這些步驟。

這可能會導致更好的效能。同樣,指令碼中的所有步驟都以原子方式執行。執行指令碼時,無法執行其他Redis命令。

例如,我使用Lua指令碼改變儲存在Redis的JSON字串。我將在本文後半部分對此進行詳細描述。

3、可是我什麼都不知道

一個不認識Lua的人

別擔心,Lua並不是很難理解。如果您瞭解C語言系列中的任何語言,那麼您應該很容易上手Lua。另外,我在本文中提供了程式碼示例。

4、給我看個例子

讓我們開始透過redis-cli執行指令碼。從以下內容開始:

redis-cli

現在執行以下命令:

eval “redis.call(‘set’, KEYS[1], ARGV[1])” 1 key:name value

EVAL命令就是告訴Redis的執行下面的指令碼。該”redis.call(‘set’, KEYS[1], ARGV[1])” 字串是我們的指令碼,其功能與Redis的set命令相同。指令碼文字後面跟隨三個引數:

鍵的個數鍵名鍵值

指令碼引數分為兩類:KEYSARGV

我們用緊隨其後的數字指定指令碼需要多少個鍵。在我們的示例中,該值為1。在此編號之後,我們需要立即接這些key。它們可以作為指令碼中的KEYS表訪問。在我們的例子中,它key:name在索引1處包含一個值。

注意,Lua索引表從索引 1開始,而不是0

我們可以在鍵之後提供任意數量的引數,這些引數可以在Lua中作為ARGV表使用。在此示例中,我們提供了一個ARGV引數:string value。您已經猜到了,上面的命令將鍵設定key:name為value value。

提供指令碼使用的key作為KEYS以及提供所有其他引數作為ARGV是一種好習慣。因此,您不應該將KEYS指定為0,然後在ARGV表中提供所有key。

現在讓我們檢查指令碼是否成功完成。我們將透過執行另一個從Redis獲取金鑰的指令碼來做到這一點:

eval “return redis.call(‘get’, KEYS[1])” 1 key:name

輸出應該為”value”,這意味著先前的指令碼成功設定了鍵值 “key:name”`。

5、你能解釋一下指令碼嗎?

我們的第一個指令碼包含一個語句:redis.call函式:

redis.call('set',KEYS [1],ARGV [1])

使用redis.call它可以執行任何Redis命令。第一個引數是此命令的名稱,後跟其引數。對於set命令,這些引數是keyvalue。支援所有Redis命令。根據文件:

Redis使用相同的Lua直譯器來執行所有命令

我們的第二個指令碼不僅僅執行一個命令,它還返回一個值:

eval “return redis.call(‘get’, KEYS[1])” 1 key:name

指令碼返回的所有內容都發送到呼叫過程。在我們的情況下,此過程為redis-cli,您將在終端視窗中看到結果。

6、還有更復雜的東西嗎?

我曾經使用Lua指令碼以特定順序從雜湊對映中返回元素。順序是儲存在有序集order鍵中。

首先,透過在redis-cli中執行以下命令來設定資料:

hmset hkeys key:1 value:1 key:2 value:2 key:3 value:3 key:4 value:4 key:5 value:5 key:6 value:6zadd order 1 key:3 2 key:1 3 key:2

這條命令處建立了一個名為:hkeys的雜湊對映,filed名為:key:XXX ,order其中包含hkeys按特定順序從中選擇filed。

您可能需要檢視hmset和zadd命令參考以獲取詳細資訊。

讓我們執行以下指令碼:

eval “local order = redis.call(‘zrange’, KEYS[1], 0, -1); return redis.call(‘hmget’,KEYS[2],unpack(order));” 2 order hkeys

您應該看到以下輸出:

“value:3”“value:1”“value:2”

這意味著我們以正確的順序獲得了所需hash filed的值。

7、是否必須指定完整的指令碼文字才能執行它?

Redis允許您使用SCRIPT LOAD命令將指令碼預載入到記憶體中:

script load “return redis.call(‘get’, KEYS[1])”

您應該看到如下輸出:

“4e6d8fc8bb01276962cce5371fa795a7763657ae”

這是您需要提供給EVALSHA命令以執行指令碼的指令碼的唯一雜湊:

evalsha 4e6d8fc8bb01276962cce5371fa795a7763657ae 1 key:name

注意:您應該使用SCRIPT LOAD命令返回的實際SHA1雜湊,上面的雜湊只是一個示例。

8、更改JSON的內容

有時人們在Redis中儲存JSON物件。可以檢視我前面一篇文章的講解《Redis使用字串和hash儲存JSON,哪個更高效?》。

如果必須在此JSON物件中更改key,則需要從Redis中獲取key的value值,然後對其進行解析,更改key的value值,然後進行序列化並將其設定回Redis。這種方法存在兩個問題:

併發。另一個過程可以在我們的get和set操作之間更改此JSON。在這種情況下,更改將丟失。效能。如果您經常進行這些更改,並且json物件很大,則可能成為應用程式的瓶頸。您可以透過在Lua中實現此邏輯來提高一些效能。

讓我們在key下的Redis中新增一個測試JSON字串obj:

set obj ‘{“a”:”foo”,”b”:”bar”}’

現在執行指令碼:

EVAL ‘local obj = redis.call(“get”,KEYS[1]); local obj2 = string.gsub(obj,”(“ .. ARGV[1] .. “\”:)([^,}]+)”, “%1” .. ARGV[2]); return redis.call(“set”,KEYS[1],obj2);’ 1 obj b bar2

現在我們將在key下具有以下物件obj:

{“ a”:“ foo”,“ b”:“ bar2”}

您可以使用SCRIPT LOAD命令來載入此指令碼,然後像這樣執行它:

EVALSHA <your_script_sha> 1 obj b bar2

一些注意事項:

1、指令碼中..是Lua中字串連線運算子。2、我們使用RegEx模式來匹配鍵並替換其值。3、Lua RegEx風味與大多數其他風格的不同之處在於,我們%同時將它們用作RegEx特殊符號的回溯標記和跳脫字元。9、我應該一直使用Lua指令碼嗎?

不。我建議僅在可以證明它可以帶來更好的效能時才使用它們。首先都要做基準測試,確定性能會提高才需要使用lua指令碼。如果您只需要原子性,則應改為檢查Redis事務。

另外,您的指令碼不應太長。請記住,指令碼執行時,其他所有內容都在等待指令碼完成。如果您的指令碼需要花費一些時間,則可能會導致瓶頸,而不是提高效能。指令碼在達到超時(預設為5秒)後停止。有關Lua的更多資訊,請訪問lua.org。

11
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • docker cp 提示Stale file handle