Redis Functions 介紹之一

Redis提供了編程接口(programming interface)可以讓你在Redis服務器端執行客戶的腳本。

一個重大的變化就是從Redis 7開始,你可以選擇使用Redis Functions去管理和運行你的腳本,而在此之前你只能使用EVAL命令執行Lua腳本。

通過EVAL命令執行的腳本是有缺陷的。如果在Redis服務器端執行了命令SCRIPT FLUSH, 或者服務器重啓,或者主節點執行了一個主備切換,那麼存在於服務器端的腳本將會丟失,於是客戶端的應用程序需要重新將整個的腳本再次發送到服務器。這個缺陷實際上說明,客戶要執行的腳本需要客戶端的應用程序去維護而不是Redis服務器端維護。所以,爲了解決腳本的一系列問題,Redis在最新發布的7.0版本中提出了Functions這個概念。

Redis Functions最重要的2點是可以持久化的,並且也是可以複製的。Redis Functions提供了和腳本一樣的核心功能,但是Redis認爲Functions是數據庫的一部分,因此,客戶端的應用程序在運行時候不需要再load它們,也不用擔心在執行事務的操作時候會有中斷的危險。在使用Functions之前僅需要先聲明它們(declare before use),這樣,客戶端應用程序僅僅需要調用Functions的API即可,而不需要再關注那些在腳本中的程序邏輯了。Functions提供的這些豐富的API可以包括很多Redis的核心命令,這一點非常 類似於Redis的Modules, 並且,Redis的Functions可以達到開發一次,使用多次的目的,同一個Functions可以在多個客戶端應用程序中重複使用。

每個Function都有一個唯一的名字,並且每個Function都屬於一個唯一的庫(library),在一個庫中可以包含多個Function. 要注意一點的是,這個庫的內容是不可以改變的,不可以選擇性地改變或者更新它所包含的Function,而是必須將整個庫作爲一個操作將所有的庫一起更新。這個特性使得可以在一個庫中的多個Function可以互相調用,或者共享代碼。

另外要注意的一點,Function的執行是原子化的。當一個Function在執行它的代碼時候,它會阻塞Redis Server執行其他命令,因此,Functions的代碼應執行的非常快,儘量避免在Functions中出現運行時間比較長的代碼段。

下面我們以實例說明如何使用Redis Functions

我們前面已經說過,每一個Function都屬於一個唯一的庫(library)。加載(Loading)一個庫進Redis數據庫需要通過FUNCTION LOAD命令。這個命令將庫的payload作爲輸入,這個輸入的格式如下:

#!<engine name> name=<library name>

讓我們看一個例子:

下面的例子是創建了一個library名字是mylib, 並且這個庫有一個函數名字爲myfunc, 這個函數的目的是返回它的第一個參數

例子1:

redis> FUNCTION LOAD "#!lua name=mylib 
                        redis.register_function('myfunc', function(keys, args) 
                                                 return args[1] end)"
mylib ---- 命令返回值

這個命令的返回值是加載的庫的名字,這裏就是mylib 我們可以通過FCALL命令調用在庫mylib中註冊的函數myfuncredis> FCALL myfunc 0 hello"hello" 你們可以看到,返回值就是hello

例子2:此外還有2個與FUNCTION LOAD相關的命令,FUNCTION LIST 與 FUNCTION DELETE

redis> function list
1) 1) "library_name"
   2) "mylib"
   3) "engine"
   4) "LUA"
   5) "functions"
   6) 1) 1) "name"
         2) "myfunc"
         3) "description"
         4) (nil)
         5) "flags"
         6) (empty array

例子3:

redis> FUNCTION DELETE mylib
OK
redis> FCALL myfunc 0
(error) ERR Function not found

以上3個命令的詳細信息與如何具體的使用可以查看下面的鏈接:

https://redis.io/commands/function-load/

https://redis.io/commands/function-list/

https://redis.io/commands/function-delete/ 

你們可能已經注意到了,上面調用庫中函數的命令是:redis> FCALL myfunc 0 hello"hello" 在其中包括myfunc函數名和一個數字0. 這個數字表示後面的鍵的數目(the number of key names that follow it),在這個例子中,不包括任何的key,所以這裏寫做了0我們下面要講解一個關於在Redis Functions中關於將key的名字作爲參數和非key名字作爲參數的區別 爲了讓Redis Functions能夠正確的執行,在function中所有的要訪問的key的名字都必須明確地(explicitly)將這些key的名字作爲輸入參數;任何不是key名字的參數都將被視爲普通的輸入參數下面我們將會舉一個例子進行說明:一個HSET的數據類型,我們想爲每個這種數據類型的key存貯如下信息:

HGETALL myhashkey
1) "_last_modified_"
2) "1654705366"
3) "orange"
4) "good"
5) "apple"
6) "perfect"
7) "banada"
8) "very good

除了3—8的貨品信息,還包括一個1-2的最新的修改信息 我們可以先在一個Lua腳本文件mylib.lua中定義如下的庫和函數

#!lua name=mylib

local function my_hset(keys, args)
  local hash = keys[1]
  local time = redis.call('TIME')[1]
  return redis.call('HSET', hash, '_last_modified_', time, unpack(args))
end

redis.register_function('my_hset', my_hset)

然後我們在命令行中運行如下命令:

$ cat mylib.lua | redis-cli -x FUNCTION LOAD REPLACE
"mylib"

然後當我們再運行如下FCALL命令時候,我們會得到如下的結果:

redis> FCALL my_hset 1 myhash orange "good" apple "perfect" banada "very good"
(integer) 3

上面命令的my_hset是函數名,1代表第一個參數myhash是key名,後面的orange "good" apple "perfect" banada "very good" 都是這個key:myhash的field:value對 

好了,這篇文章就先介紹到這裏,下次我們將接續介紹Redis Functions的其他高級特點。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章