一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|數據庫技術|

服務器之家 - 數據庫 - Redis - redis中lua腳本使用教程

redis中lua腳本使用教程

2021-11-22 18:18huan1993 Redis

在使用redis的過程中,發現有些時候需要原子性去操作redis命令,而redis的lua腳本正好可以實現這一功能。這篇文章主要介紹了redis中lua腳本的簡單使用,需要的朋友可以參考下

一、背景

在使用redis的過程中,發現有些時候需要原子性去操作redis命令,而redis的lua腳本正好可以實現這一功能。比如: 扣減庫存操作、限流操作等等。
redis的pipelining雖然也可以一次執行一組命令,但是如果在這一組命令的執行過程中,需要根據上一步執行的結果做一些判斷,則無法實現。

二、使用lua腳本

redis中使用的是 lua 5.1 的腳本規范,同時我們編寫的腳本的時候,不需要定義 lua 函數。同時也不能使用全局變量等等。

1、lua腳本的格式和注意事項

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>

redis中lua腳本使用教程

2、注意事項

lua腳本中的redis操作的key最好都是通過 keys來傳遞,而不要寫死。否則在redis cluster的情況下可能有問題.

redis中lua腳本使用教程

1、好的寫法

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是通過keys獲取的。

2、差的寫法

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

redis命令操作的key是直接寫死的。

2、將腳本加載到redis中

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

注意:

當我們把 lua腳本加載到redis中,這個腳本并不會馬上執行,而是會緩存起來,并且返回sha1校驗和,后期我們可以通過 evalsha 來執行這個腳本。

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

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

3、執行lua腳本

1、通過eval執行

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

2、通過evalsha執行

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

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

通過 evalsha 執行的好處是可以節省帶寬。如果我們的lua腳本比較長,程序在執行的時候將lua腳本發送到redis服務器則可能耗費的帶寬多,如果發送的是hash值的話,則耗費的帶寬少。

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

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、清空服務器上的腳本緩存

注意:
我們無法清除某一個腳本的緩存,只可以清楚所有的緩存,一般情況下沒有必要清楚,因為即使有大量的腳本也不會太占用服務器內存。

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

redis中lua腳本使用教程

6、殺死正在運行的腳本

127.0.0.1:6379> script kill

注意:

  • 該命令只可以殺死正在運行的 只讀腳本
  • 對于修改了數據的腳本,無法使用此命令殺死,只能使用 shutdown nosave命令。
  • 腳本執行的默認超時時間5分鐘,可以通過redis.conf配置文件的lua-time-limit配置項修改。
  • 腳本即使到達了超時時間,也不會停止執行,因為這違反了lua腳本的原子性。

三、lua和redis數據類型轉換

lua的數據類型和redis的數據類型存在一對一的轉換關系,如果將redis類型轉換成lua類型,然后在轉換成redis類型,那么結果和初試值是一致的。

1、類型轉換

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、額外的轉換規則

  1. lua的布爾類型,lua的true會轉換成redis的1

3、3個重要規則

1. 數字類型

在lua中,只有一個number類型,整數和浮點數之間沒有區別,如果我們在lua中返回一個浮點數,實際返回的是一個整數,如果要返回浮點數,需要以字符串的方式返回。

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數組存在nil

當 redis 將 lua 數組轉換為 redis 協議時,如果遇到 nil,則轉換會停止。即 nil 后的值都不會返回。

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類型包含建和值

出現這種情況返回的redis的是一個空數組

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

四、lua腳本中輸出日志

這個一般調試我們的腳本的時候比較有用。

redis.log(loglevel,message)

loglevel的取值范圍:

  • redis.log_debug
  • redis.log_verbose
  • redis.log_notice
  • redis.log_warning

舉例:

redis中lua腳本使用教程

五、一個簡單限流的案例

1、需求

在 1s 之內,方法最大的并發只能是 5。

1s 和 5 當作參數傳遞。

2、實現步驟

1、編寫lua腳本

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
-- 輸出用戶傳遞進來的參數
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])
-- 限流的次數
local limit = tonumber(argv[1])
-- 多長時間過期
local expirems = tonumber(argv[2])
 
-- 當前已經執行的次數
local current = tonumber(redis.call('get', limitkey) or '0')
 
-- 設置一個斷點
redis.breakpoint()
 
redis.log(redis.log_notice, "limit key: " .. tostring(limitkey) .. " 在[" .. tostring(expirems) .. "]ms內已經訪問了 " .. tostring(current) .. " 次,最多可以訪問: " .. limit .. " 次")
 
-- 限流了
if (current + 1 > limit) then
    return { true }
end
 
-- 未達到訪問限制
-- 訪問次數+1
redis.call("incrby", limitkey, "1")
if (current == 0) then
    -- 設置過期時間
    redis.call("pexpire", limitkey, expirems)
end
 
return { false }

2、程序中執行lua腳本

redis中lua腳本使用教程

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

六、lua腳本的debug

當我們編寫好了lua腳本后,如果在執行的過程中發生了錯誤,那么我們如何該如何解決呢?此處我們來了解下如何debug lua 腳本。

1、lua腳本中的幾個小命令

在 腳本中打一個斷點

redis.breakpoint()

2、斷點調試

1、執行命令

?
1
2
3
4
5
6
7
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: 運行到當前行并停止 (此時當前行還未執行)
  • c:運行到下個斷點,即運行到lua腳本中存在 redis.breakpoint()方法的地方
  • list:列出當前行周圍的一些源碼
  • p:打印出所有的 local 變量的值
  • p <var>:打印具體的某個 local 變量的值
  • r:執行 redis 命令

-- eg:
r set key value
r get key

3、debug運行結果

redis中lua腳本使用教程

七、參考文檔

https://redis.io/topics/ldb

https://redis.io/commands/eval

到此這篇關于redis中lua腳本的簡單使用的文章就介紹到這了,更多相關redis中lua腳本使用內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://www.cnblogs.com/huan1993/p/15472920.html

延伸 · 閱讀

精彩推薦
  • RedisRedis如何實現數據庫讀寫分離詳解

    Redis如何實現數據庫讀寫分離詳解

    Redis的主從架構,能幫助我們實現讀多,寫少的情況,下面這篇文章主要給大家介紹了關于Redis如何實現數據庫讀寫分離的相關資料,文中通過示例代碼介紹...

    羅兵漂流記6092019-11-11
  • Redisredis中如何使用lua腳本讓你的靈活性提高5個逼格詳解

    redis中如何使用lua腳本讓你的靈活性提高5個逼格詳解

    這篇文章主要給大家介紹了關于redis中如何使用lua腳本讓你的靈活性提高5個逼格的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具...

    一線碼農5812019-11-18
  • RedisRedis的配置、啟動、操作和關閉方法

    Redis的配置、啟動、操作和關閉方法

    今天小編就為大家分享一篇Redis的配置、啟動、操作和關閉方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧 ...

    大道化簡5312019-11-14
  • Redisredis 交集、并集、差集的具體使用

    redis 交集、并集、差集的具體使用

    這篇文章主要介紹了redis 交集、并集、差集的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友...

    xiaojin21cen10152021-07-27
  • RedisRedis全量復制與部分復制示例詳解

    Redis全量復制與部分復制示例詳解

    這篇文章主要給大家介紹了關于Redis全量復制與部分復制的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Redis爬蟲具有一定的參考學習...

    豆子先生5052019-11-27
  • Redisredis實現排行榜功能

    redis實現排行榜功能

    排行榜在很多地方都能使用到,redis的zset可以很方便地用來實現排行榜功能,本文就來簡單的介紹一下如何使用,具有一定的參考價值,感興趣的小伙伴們...

    乘月歸5022021-08-05
  • Redis詳解Redis復制原理

    詳解Redis復制原理

    與大多數db一樣,Redis也提供了復制機制,以滿足故障恢復和負載均衡等需求。復制也是Redis高可用的基礎,哨兵和集群都是建立在復制基礎上實現高可用的...

    李留廣10222021-08-09
  • RedisRedis 事務知識點相關總結

    Redis 事務知識點相關總結

    這篇文章主要介紹了Redis 事務相關總結,幫助大家更好的理解和學習使用Redis,感興趣的朋友可以了解下...

    AsiaYe8232021-07-28
主站蜘蛛池模板: 国产精品特黄毛片 | 青青青国产在线观看 | 午夜AV内射一区二区三区红桃视 | 九九大香尹人视频免费 | 91亚洲精品久久91综合 | 久久免费特黄毛片 | 精品综合久久久久久97超人 | a男人天堂| 亚洲精品国产一区二区第一页 | 女人爽到喷水的视频免费 | 五月天国产精品 | 精品久久久久久久久久香蕉 | 国产在线观看福利片 | 日噜噜 | 99人中文字幕亚洲区 | 国产亚洲精品精品国产亚洲综合 | 日本视频免费在线 | 亚洲天堂激情 | 欧美精品1区 | 久久99精品国产自在自线 | 日韩手机在线视频 | 激情婷婷成人亚洲综合 | sihu国产午夜精品一区二区三区 | 免费看男女污污完整版 | 精品四虎国产在免费观看 | 91精品啪在线观看国产老湿机 | 亚洲六月丁香六月婷婷色伊人 | 国产肥臀 | 婷婷天天 | 99爱在线观看 | 国产91素人搭讪系列天堂 | 成年女人毛片免费观看97 | 2021国产麻豆剧传媒剧情动漫 | 久久青青草原精品国产软件 | 扒开大腿狠狠挺进视频 | 大好硬好深好爽想要视频 | 国产亚洲精品美女2020久久 | 粉嫩极品国产在线观看免费 | 大团圆免费阅读全文 | 美女任你模 | 亚洲精品一区制服丝袜 |