Redis Functions 介紹之二

首先,讓我們先回顧一下上一篇講的在Redis Functions中關(guān)于將key的名字作為參數(shù)和非key名字作為參數(shù)的區(qū)別陶珠,先看下面的例子挟裂。
首先,我們先在一個Lua腳本文件mylib.lua中定義如下的庫和函數(shù)揍诽。

//--------------------mylib.lua 文件開始 ----------- //
#!lua name= mylib

local function my_hset(keys, args)
    local hash = keys[1]
    local time = redis.call('TIME')[1]     //這一行的目的是執(zhí)行TIME命令得到當(dāng)前的服務(wù)器時間
    return redis.call('HSET', hash, '_last_modified_', time, unpack(args))
end

redis.register_function('my_hset', my_hset)
//--------------------mylib.lua 文件結(jié)束 ----------- //

然后我們在命令行中運(yùn)行如下命令:

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

當(dāng)我們再運(yùn)行如下FCALL命令時候诀蓉,我們會得到如下的結(jié)果:

redis> FCALL my_hset 1 myhash_key first_field "first value" second_field "second value"(integer) 3

上面命令的my_hset是函數(shù)名,1代表第一個參數(shù)myhash_key是key名暑脆,后面的first_field "first value" second_field "second value" 都是這個key: myhash_key的field:value對
我們通過在Redis客戶端運(yùn)行 HGETALL myhash_key可以查看到相對應(yīng)的結(jié)果:

redis> HGETALL myhash_key
1) "_last_modified_"
2) "1659536487"
3) "first_field"
4) "first value"
5) "second_field"
6) "second value"

好了渠啤,在復(fù)習(xí)完了上一篇Redis Functions的內(nèi)容之后,我們可以看到上面的例子中mylib庫中只包含了一個函數(shù)my_hset, 事實(shí)上在一個庫中可以包括多個函數(shù)添吗,在下面的例子中我們要添加另外2個function:my_hgetall 與 my_hlastmodified.
其中沥曹,函數(shù)my_hgetall相當(dāng)于在redis 客戶端執(zhí)行hgetall命令,而my_hlastmodified函數(shù)返回的是傳入的key中_last_modified這一個field的值碟联。
首先妓美,讓我們在mylib.lua中添加這兩個function

local function my_hgetall(keys, args)
    local hash = keys[1]
    local res = redis.call('HGETALL', hash)
    return res
end

local function my_hlastmodified(keys, args)
    local hash = keys[1]
    return redis.call('HGET', keys[1], '_last_modified_')
end

然后,在mylib中注冊這兩個函數(shù)鲤孵。

redis.register_function('my_hgetall', my_hgetall)
redis.register_function('my_hlastmodified', my_hlastmodified)

因?yàn)槲覀円趍ylib庫中新增兩個函數(shù)壶栋,所以我們需要運(yùn)行如下的命令:

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

接下來我們運(yùn)行my_hgetall函數(shù)與my_hlastmodified


redis> FCALL my_hgetall 1 myhash_key
1) "_last_modified_"
2) "1659536487"
3) "first_field"
4) "first value"
5) "second_field"
6) "second value"

redis> FCALL my_hlastmodified 1 myhash_key
"1659536487"

最后我們可以通過FUNCTION LIST命令來查看當(dāng)前所有的Redis Function的庫及其包含的函數(shù)信息。下面我們來查看一下當(dāng)前庫mylib中包括的3個function的信息普监。

127.0.0.1:6381> FUNCTION list
1) 1) "library_name"
   2) "mylib"
   3) "engine"
   4) "LUA"
   5) "functions"
   6) 1) 1) "name"
         2) "my_hset"
         3) "description"
         4) (nil)
         5) "flags"
         6) (empty array)
      2) 1) "name"
         2) "my_hlastmodified"
         3) "description"
         4) (nil)
         5) "flags"
         6) (empty array)
      3) 1) "name"
         2) "my_hgetall"
         3) "description"
         4) (nil)
         5) "flags"
         6) (empty array)

在Redis的官方文檔中贵试,我們發(fā)現(xiàn)我們可以在庫中定義一個function供庫中的其他函數(shù)使用,在官方的使用說明凯正,它給出了一個例子用于錯誤檢測毙玻。我們下面來看看這個例子。
定義一個check_keys的函數(shù)廊散,用來檢測客戶端調(diào)用的redis function的函數(shù)輸入的key是否存在并且只有一個淆珊。

local function check_keys(keys)
    local error = nil
    local nkeys = table.getn(keys)
    if nkeys == 0 then
        error = 'Hash key name not provided'
    elseif nkeys > 1 then
        error = 'Only one key name is allowed'
    end

    if error ~= nil then
        redis.log(redis.LOG_WARNING, error);
        return redis.error_reply(error)
     end
     return nil
end

相應(yīng)的,我們也需要修改已經(jīng)有的3個函數(shù)奸汇,讓他們?nèi)フ{(diào)用新增的check_keys函數(shù)施符。

local function my_hset(keys, args)
    local error = check_keys(keys)
    if error ~= nil then
        return error
    end

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

local function my_hgetall(keys, args)
    local error = check_keys(keys)
    if error ~= nil then
        return error
    end

    local hash = keys[1]
    local res = redis.call('HGETALL', hash)
    return res
end

local function my_hlastmodified(keys, args)
     local error = check_keys(keys)
     if error ~= nil then
         return error
     end

     local hash = keys[1]
     return redis.call('HGET', keys[1], '_last_modified_')
end

這里要注意一點(diǎn)往声,在上面的例子中,如果我們運(yùn)行FCALL:

redis> FCALL my_hgetall 1 myhash_key
1) "_last_modified_"
2) "1659536487"
3) "first_field"
4) "first value"
5) "second_field"
6) "second value"

我們可以看到運(yùn)行是正常的戳吝,但是如果我們運(yùn)行FCALL_RO:

redis> FCALL_RO my_hgetall 1 myhash_key
(error) ERR Can not execute a script with write flag using *_ro command.

我們會收到一個錯誤浩销。這是為什么呢?
事實(shí)上听哭,函數(shù)my_hgetall的目的只是從數(shù)據(jù)中讀取數(shù)據(jù)慢洋,并沒有寫操作。但是當(dāng)我們定義它的時候陆盘,并沒有標(biāo)注它是只讀屬性普筹。

local function my_hgetall(keys, args)
    local hash = keys[1]
    local res = redis.call('HGETALL', hash)
    return res
end

所以這個時候,當(dāng)我們用命令FCALL_RO就會返回一個錯誤:Can not execute a script with write flag using *_ro command

所以為了可以讓FCALL_RO執(zhí)行一個只讀屬性的函數(shù)隘马,我們需要對my_hgetall的注冊方式進(jìn)行一下修改:

redis.register_function{
    function_name='my_hgetall',
    callback=my_hgetall,
    flags={ 'no-writes' }
}

這個時候太防,我們再運(yùn)行FCALL_RO命令時候,我們就會得到正確的結(jié)果了

redis> FCALL_RO my_hgetall 1 myhash_key
1) "_last_modified_"
2) "1659536487"
3) "first_field"
4) "first value"
5) "second_field"
6) "second value

Redis functions是如何在集群中運(yùn)行
在非集群狀態(tài)時候酸员,如果有主從節(jié)點(diǎn)蜒车,那么主節(jié)點(diǎn)上的function會自動地被復(fù)制到從節(jié)點(diǎn),這與function創(chuàng)建的初衷也是一致的:Redis認(rèn)為Functions是數(shù)據(jù)庫的一部分幔嗦,是可以持久化的酿愧,并且也是可以復(fù)制的。
但是邀泉,如果function是存在于集群的節(jié)點(diǎn)中嬉挡,那么就有一些不一樣的特性了。Redis function無法被自動地加載到集群中的所有節(jié)點(diǎn)汇恤,而需要被管理員手動地將function加載到集群中的每個節(jié)點(diǎn)中棘伴。要加載Redis function在集群中的節(jié)點(diǎn),可以運(yùn)行如下的命令:

redis-cli --cluster-only-masters --cluster call host:port FUNCTION LOAD [REPLACE] function-code

如果運(yùn)行命令:

redis-cli --cluster add-node

那么這個時候集群中已經(jīng)存在的節(jié)點(diǎn)會將已經(jīng)加載的function自動地傳播到新加入集訓(xùn)的節(jié)點(diǎn)屁置。
使用Redis Function的其他的注意事項(xiàng)
如果一個已經(jīng)加載Redis Function的節(jié)點(diǎn)需要重啟焊夸,那么在重啟之前建議先運(yùn)行命令:

redis-cli --functions-rdb

這樣會將已經(jīng)存在于節(jié)點(diǎn)上的Redis function存到一個RDB文件中,當(dāng)這個節(jié)點(diǎn)重啟之后可以直接加載這個rdb文件蓝角,就不需要再手工加載每一個function了阱穗,大大地節(jié)省了時間和減少錯誤機(jī)率。
本篇文章引用了部分Redis官方文檔的例子使鹅, 大家可以從鏈接去查看和運(yùn)行一下揪阶。
https://redis.io/docs/manual/programmability/functions-intro/
下一篇,我們開始分析Redis function的源碼患朱,讓我們深入探討一下這個Redis新特性內(nèi)部是如何執(zhí)行鲁僚,歡迎繼續(xù)關(guān)注Redis Functions系列文章。
最后,感謝Redis社區(qū)的所有貢獻(xiàn)者的努力工作冰沙,及所有對Redis感興趣的開發(fā)者的支持侨艾。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市拓挥,隨后出現(xiàn)的幾起案子唠梨,更是在濱河造成了極大的恐慌,老刑警劉巖侥啤,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件当叭,死亡現(xiàn)場離奇詭異,居然都是意外死亡盖灸,警方通過查閱死者的電腦和手機(jī)蚁鳖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赁炎,“玉大人醉箕,你說我怎么就攤上這事「恃” “怎么了琅攘?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵垮庐,是天一觀的道長松邪。 經(jīng)常有香客問我,道長哨查,這世上最難降的妖魔是什么逗抑? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮寒亥,結(jié)果婚禮上邮府,老公的妹妹穿的比我還像新娘。我一直安慰自己溉奕,他們只是感情好褂傀,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著加勤,像睡著了一般仙辟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鳄梅,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天叠国,我揣著相機(jī)與錄音,去河邊找鬼戴尸。 笑死粟焊,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播项棠,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼悲雳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了沾乘?” 一聲冷哼從身側(cè)響起怜奖,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎翅阵,沒想到半個月后歪玲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掷匠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年滥崩,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片讹语。...
    茶點(diǎn)故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡钙皮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出顽决,到底是詐尸還是另有隱情短条,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布才菠,位于F島的核電站茸时,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏赋访。R本人自食惡果不足惜可都,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蚓耽。 院中可真熱鬧渠牲,春花似錦、人聲如沸步悠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鼎兽。三九已至答姥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間接奈,已是汗流浹背踢涌。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留序宦,地道東北人睁壁。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親潘明。 傳聞我的和親對象是個殘疾皇子行剂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容