最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

redis中l(wèi)ua腳本使用教程

 更新時(shí)間:2021年10月28日 09:34:49   作者:huan1993  
在使用redis的過(guò)程中,發(fā)現(xiàn)有些時(shí)候需要原子性去操作redis命令,而redis的lua腳本正好可以實(shí)現(xiàn)這一功能。這篇文章主要介紹了redis中l(wèi)ua腳本的簡(jiǎn)單使用,需要的朋友可以參考下

一、背景

在使用redis的過(guò)程中,發(fā)現(xiàn)有些時(shí)候需要原子性去操作redis命令,而redis的lua腳本正好可以實(shí)現(xiàn)這一功能。比如: 扣減庫(kù)存操作、限流操作等等。
redis的pipelining雖然也可以一次執(zhí)行一組命令,但是如果在這一組命令的執(zhí)行過(guò)程中,需要根據(jù)上一步執(zhí)行的結(jié)果做一些判斷,則無(wú)法實(shí)現(xiàn)。

二、使用lua腳本

Redis中使用的是 Lua 5.1 的腳本規(guī)范,同時(shí)我們編寫(xiě)的腳本的時(shí)候,不需要定義 Lua 函數(shù)。同時(shí)也不能使用全局變量等等。

1、lua腳本的格式和注意事項(xiàng)

1、格式

EVAL script numkeys key [key ...] arg [arg ...]

127.0.0.1:6379> eval "return {KEYS[1],ARGV[1],ARGV[2]}" 1 key1 arg1 arg2
1) "key1"
2) "arg1"
3) "arg2"
127.0.0.1:6379>

2、注意事項(xiàng)

Lua腳本中的redis操作的key最好都是通過(guò) KEYS來(lái)傳遞,而不要寫(xiě)死。否則在Redis Cluster的情況下可能有問(wèn)題.

1、好的寫(xiě)法

127.0.0.1:6379> eval "return redis.call('set',KEYS[1],'zhangsan')" 1 username
OK
127.0.0.1:6379> get username
"zhangsan"

redis命令操作的key是通過(guò)KEYS獲取的。

2、差的寫(xiě)法

127.0.0.1:6379> eval "return redis.call('set','username','zhangsan')" 0
OK
127.0.0.1:6379> get username
"zhangsan"

redis命令操作的key是直接寫(xiě)死的。

2、將腳本加載到redis中

需求: 此處定義一個(gè)lua腳本,將輸入的參數(shù)的值+1返回。

注意:

當(dāng)我們把 lua腳本加載到redis中,這個(gè)腳本并不會(huì)馬上執(zhí)行,而是會(huì)緩存起來(lái),并且返回sha1校驗(yàn)和,后期我們可以通過(guò) EVALSHA 來(lái)執(zhí)行這個(gè)腳本。

此處我們記住這個(gè)腳本加載后返回的hash值,在下一步執(zhí)行的時(shí)候需要用到。

127.0.0.1:6379> script load "return tonumber(KEYS[1])+1"
"ef424d378d47e7a8b725259cb717d90a4b12a0de"
127.0.0.1:6379>

3、執(zhí)行l(wèi)ua腳本

1、通過(guò)eval執(zhí)行

127.0.0.1:6379> eval "return tonumber(KEYS[1]) + 1" 1 100
(integer) 101
127.0.0.1:6379>

2、通過(guò)evalsha執(zhí)行

ef424d378d47e7a8b725259cb717d90a4b12a0de的值為上一步通過(guò) script load加載腳本后獲取的。

127.0.0.1:6379> evalsha ef424d378d47e7a8b725259cb717d90a4b12a0de 1 100
(integer) 101
127.0.0.1:6379>

通過(guò) evalsha 執(zhí)行的好處是可以節(jié)省帶寬。如果我們的lua腳本比較長(zhǎng),程序在執(zhí)行的時(shí)候?qū)ua腳本發(fā)送到redis服務(wù)器則可能耗費(fèi)的帶寬多,如果發(fā)送的是hash值的話(huà),則耗費(fèi)的帶寬少。

4、判斷腳本是否在redis服務(wù)器緩存中

127.0.0.1:6379> script load "return tonumber(KEYS[1])+1"
"ef424d378d47e7a8b725259cb717d90a4b12a0de"
127.0.0.1:6379> script exists ef424d378d47e7a8b725259cb717d90a4b12a0de
1) (integer) 1
127.0.0.1:6379> script exists not-exists-sha1
1) (integer) 0
127.0.0.1:6379>

5、清空服務(wù)器上的腳本緩存

注意:
我們無(wú)法清除某一個(gè)腳本的緩存,只可以清楚所有的緩存,一般情況下沒(méi)有必要清楚,因?yàn)榧词褂写罅康哪_本也不會(huì)太占用服務(wù)器內(nèi)存。

127.0.0.1:6379> script load "return tonumber(KEYS[1])+1"
"ef424d378d47e7a8b725259cb717d90a4b12a0de"
127.0.0.1:6379> script exists ef424d378d47e7a8b725259cb717d90a4b12a0de
1) (integer) 1
127.0.0.1:6379> script flush
OK
127.0.0.1:6379> script exists ef424d378d47e7a8b725259cb717d90a4b12a0de
1) (integer) 0

6、殺死正在運(yùn)行的腳本

127.0.0.1:6379> script kill

注意:

  • 該命令只可以殺死正在運(yùn)行的 只讀腳本
  • 對(duì)于修改了數(shù)據(jù)的腳本,無(wú)法使用此命令殺死,只能使用 shutdown nosave命令。
  • 腳本執(zhí)行的默認(rèn)超時(shí)時(shí)間5分鐘,可以通過(guò)redis.conf配置文件的lua-time-limit配置項(xiàng)修改。
  • 腳本即使到達(dá)了超時(shí)時(shí)間,也不會(huì)停止執(zhí)行,因?yàn)檫@違反了lua腳本的原子性。

三、lua和redis數(shù)據(jù)類(lèi)型轉(zhuǎn)換

Lua的數(shù)據(jù)類(lèi)型和Redis的數(shù)據(jù)類(lèi)型存在一對(duì)一的轉(zhuǎn)換關(guān)系,如果將Redis類(lèi)型轉(zhuǎn)換成Lua類(lèi)型,然后在轉(zhuǎn)換成Redis類(lèi)型,那么結(jié)果和初試值是一致的。

1、類(lèi)型轉(zhuǎn)換

Redis to Luaconversion table.

  • Redis integer reply -> Lua number
  • Redis bulk reply -> Lua string
  • Redis multi bulk reply -> Lua table (may have other Redis data types nested)
  • Redis status reply -> Lua table with a single ok field containing the status
  • Redis error reply -> Lua table with a single err field containing the error
  • Redis Nil bulk reply and Nil multi bulk reply -> Lua false boolean type

Lua to Redisconversion table.

  • Lua number -> Redis integer reply (the number is converted into an integer)
  • Lua string -> Redis bulk reply
  • Lua table (array) -> Redis multi bulk reply (truncated to the first nil inside the Lua array if any)
  • Lua table with a single ok field -> Redis status reply
  • Lua table with a single err field -> Redis error reply
  • Lua boolean false -> Redis Nil bulk reply.

2、額外的轉(zhuǎn)換規(guī)則

  1. Lua的布爾類(lèi)型,Lua的True會(huì)轉(zhuǎn)換成Redis的1

3、3個(gè)重要規(guī)則

1. 數(shù)字類(lèi)型

在Lua中,只有一個(gè)number類(lèi)型,整數(shù)和浮點(diǎn)數(shù)之間沒(méi)有區(qū)別,如果我們?cè)贚ua中返回一個(gè)浮點(diǎn)數(shù),實(shí)際返回的是一個(gè)整數(shù),如果要返回浮點(diǎn)數(shù),需要以字符串的方式返回。

127.0.0.1:6379> eval "return 3.98" 0
(integer) 3
127.0.0.1:6379> eval "return '3.98'" 0
"3.98"

2. lua數(shù)組存在nil

當(dāng) Redis 將 Lua 數(shù)組轉(zhuǎn)換為 Redis 協(xié)議時(shí),如果遇到 nil,則轉(zhuǎn)換會(huì)停止。即 nil 后的值都不會(huì)返回。

127.0.0.1:6379> eval "return {1,2,'data',nil,'can not return value','vv'}" 0
1) (integer) 1
2) (integer) 2
3) "data"
127.0.0.1:6379>

3. Lua的Table類(lèi)型包含建和值

出現(xiàn)這種情況返回的redis的是一個(gè)空數(shù)組

127.0.0.1:6379> eval "return {key1 ='value1',key2='value2'}" 0
(empty array)
127.0.0.1:6379>

四、lua腳本中輸出日志

這個(gè)一般調(diào)試我們的腳本的時(shí)候比較有用。

redis.log(loglevel,message)

loglevel的取值范圍:

  • redis.LOG_DEBUG
  • redis.LOG_VERBOSE
  • redis.LOG_NOTICE
  • redis.LOG_WARNING

舉例:

五、一個(gè)簡(jiǎn)單限流的案例

1、需求

在 1s 之內(nèi),方法最大的并發(fā)只能是 5。

1s 和 5 當(dāng)作參數(shù)傳遞。

2、實(shí)現(xiàn)步驟

1、編寫(xiě)lua腳本

-- 輸出用戶(hù)傳遞進(jìn)來(lái)的參數(shù)
for i, v in pairs(KEYS) do
    redis.log(redis.LOG_NOTICE, "limit: key" .. i .. " = " .. v)
end
for i, v in pairs(ARGV) do
    redis.log(redis.LOG_NOTICE, "limit: argv" .. i .. " = " .. v)
end

-- 限流的key
local limitKey = tostring(KEYS[1])
-- 限流的次數(shù)
local limit = tonumber(ARGV[1])
-- 多長(zhǎng)時(shí)間過(guò)期
local expireMs = tonumber(ARGV[2])

-- 當(dāng)前已經(jīng)執(zhí)行的次數(shù)
local current = tonumber(redis.call('get', limitKey) or '0')

-- 設(shè)置一個(gè)斷點(diǎn)
redis.breakpoint()

redis.log(redis.LOG_NOTICE, "limit key: " .. tostring(limitKey) .. " 在[" .. tostring(expireMs) .. "]ms內(nèi)已經(jīng)訪問(wèn)了 " .. tostring(current) .. " 次,最多可以訪問(wèn): " .. limit .. " 次")

-- 限流了
if (current + 1 > limit) then
    return { true }
end

-- 未達(dá)到訪問(wèn)限制
-- 訪問(wèn)次數(shù)+1
redis.call("incrby", limitKey, "1")
if (current == 0) then
    -- 設(shè)置過(guò)期時(shí)間
    redis.call("pexpire", limitKey, expireMs)
end

return { false }

2、程序中執(zhí)行l(wèi)ua腳本

完整代碼: https://gitee.com/huan1993/spring-cloud-parent/tree/master/springboot/springboot-redis-lua

六、lua腳本的debug

當(dāng)我們編寫(xiě)好了lua腳本后,如果在執(zhí)行的過(guò)程中發(fā)生了錯(cuò)誤,那么我們?nèi)绾卧撊绾谓鉀Q呢?此處我們來(lái)了解下如何debug lua 腳本。

1、lua腳本中的幾個(gè)小命令

在 腳本中打一個(gè)斷點(diǎn)

redis.breakpoint()

2、斷點(diǎn)調(diào)試

1、執(zhí)行命令

redis-cli --ldb --eval limit.lua invoked , 1 1000

limit.lua 需要debug的lua文件
invoked 為傳遞到 lua 腳本中 KEYS 的值
1 和 1000 為傳遞到 lua 腳本中 ARGV 的值

, 分割 出 KEYS 和 ARGV 的值

2、一些debug指令

  • help: 列出可用的debug指令
  • sn: 運(yùn)行到當(dāng)前行并停止 (此時(shí)當(dāng)前行還未執(zhí)行)
  • c:運(yùn)行到下個(gè)斷點(diǎn),即運(yùn)行到lua腳本中存在 redis.breakpoint()方法的地方
  • list:列出當(dāng)前行周?chē)囊恍┰创a
  • p:打印出所有的 local 變量的值
  • p <var>:打印具體的某個(gè) local 變量的值
  • r:執(zhí)行 redis 命令

-- eg:
r set key value
r get key

3、debug運(yùn)行結(jié)果

七、參考文檔

https://redis.io/topics/ldb

https://redis.io/commands/eval

到此這篇關(guān)于redis中l(wèi)ua腳本的簡(jiǎn)單使用的文章就介紹到這了,更多相關(guān)redis中l(wèi)ua腳本使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Redis Sorted Set類(lèi)型使用及應(yīng)用場(chǎng)景

    Redis Sorted Set類(lèi)型使用及應(yīng)用場(chǎng)景

    Sorted Set是Redis常用的一種是數(shù)據(jù)類(lèi)型,本文主要介紹了Redis Sorted Set類(lèi)型使用及應(yīng)用場(chǎng)景,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-06-06
  • Redis中List類(lèi)型的常用命令

    Redis中List類(lèi)型的常用命令

    本文主要介紹了Redis中List類(lèi)型的常用命令,包含12種常用命令,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-06-06
  • 通過(guò)lua實(shí)現(xiàn)redis 分布式鎖的項(xiàng)目實(shí)踐

    通過(guò)lua實(shí)現(xiàn)redis 分布式鎖的項(xiàng)目實(shí)踐

    在Redis中使用Lua腳本實(shí)現(xiàn)分布式鎖 是一種高效、原子、安全的方式,本文就來(lái)介紹一下通過(guò)lua實(shí)現(xiàn)redis分布式鎖,具有一定的參考價(jià)值,感興趣的可以了解一下
    2026-02-02
  • redis防止短信惡意調(diào)用的實(shí)現(xiàn)

    redis防止短信惡意調(diào)用的實(shí)現(xiàn)

    本文主要介紹了在場(chǎng)景登錄或注冊(cè)接口中使用短信驗(yàn)證碼時(shí)遇到的惡意調(diào)用問(wèn)題,并通過(guò)使用Redis分布式鎖來(lái)解決,具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-02-02
  • 控制Redis的hash的field中的過(guò)期時(shí)間

    控制Redis的hash的field中的過(guò)期時(shí)間

    這篇文章主要介紹了控制Redis的hash的field中的過(guò)期時(shí)間問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • Redis高并發(fā)防止秒殺超賣(mài)實(shí)戰(zhàn)源碼解決方案

    Redis高并發(fā)防止秒殺超賣(mài)實(shí)戰(zhàn)源碼解決方案

    本文主要介紹了Redis高并發(fā)防止秒殺超賣(mài)實(shí)戰(zhàn)源碼解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Redis的持久化方案詳解

    Redis的持久化方案詳解

    在本篇文章里小編給大家整理的是關(guān)于Redis的持久化方案詳解,有興趣的朋友們可以參考下。
    2020-03-03
  • redis調(diào)用二維碼時(shí)的不斷刷新排查分析

    redis調(diào)用二維碼時(shí)的不斷刷新排查分析

    這篇文章主要為大家介紹了redis調(diào)用二維碼時(shí)不斷刷新排查分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • Redis在多線(xiàn)程情況下寫(xiě)入失敗的問(wèn)題及解決

    Redis在多線(xiàn)程情況下寫(xiě)入失敗的問(wèn)題及解決

    文章描述了在JRE 7 32位環(huán)境下使用Jedis客戶(hù)端并發(fā)調(diào)用`set`方法時(shí)出現(xiàn)的問(wèn)題,懷疑是多線(xiàn)程環(huán)境下獲取連接導(dǎo)致的卡死,通過(guò)使用連接池和在JDK 8 64位環(huán)境下進(jìn)行測(cè)試,問(wèn)題得到解決
    2025-11-11
  • CentOS系統(tǒng)下Redis安裝和自啟動(dòng)配置的步驟

    CentOS系統(tǒng)下Redis安裝和自啟動(dòng)配置的步驟

    相信大家都知道Redis是一個(gè)C實(shí)現(xiàn)的基于內(nèi)存、可持久化的鍵值對(duì)數(shù)據(jù)庫(kù),在分布式服務(wù)中常作為緩存服務(wù)。所以這篇文章將詳細(xì)介紹在CentOS系統(tǒng)下如何從零開(kāi)始安裝到配置啟動(dòng)服務(wù)。有需要的可以參考借鑒。
    2016-09-09

最新評(píng)論

四川省| 鄂州市| 颍上县| 安泽县| 独山县| 文安县| 兰考县| 鹤庆县| 隆林| 镇平县| 云林县| 灵宝市| 松滋市| 昭平县| 贵定县| 漳州市| 安丘市| 宿州市| 介休市| 南宫市| 阿克| 连州市| 富蕴县| 澳门| 桐庐县| 义乌市| 大厂| 汉阴县| 嘉祥县| 平舆县| 大同市| 前郭尔| 同德县| 宿迁市| 南郑县| 杨浦区| 蕉岭县| 洪江市| 新宾| 夏津县| 富宁县|