五月综合激情婷婷六月,日韩欧美国产一区不卡,他扒开我内裤强吻我下面视频 ,无套内射无矿码免费看黄,天天躁,日日躁,狠狠躁

新聞動態(tài)

Redis中Lua腳本的使用和設(shè)置超時

發(fā)布日期:2022-02-02 17:23 | 文章來源:gibhub

Redis提供了Lua腳本功能來讓用戶實現(xiàn)自己的原子命令,但也存在著風(fēng)險,編寫不當(dāng)?shù)哪_本可能阻塞線程導(dǎo)致整個Redis服務(wù)不可用。

本文將介紹Redis中Lua腳本的基本用法,以及腳本超時導(dǎo)致的問題和處理方式。

EVAL命令簡介

eval格式

Redis 提供了命令EVAL來執(zhí)行Lua腳本,格式如下

EVAL script numkeys key [key …] arg [arg …]

其中 script 是將要執(zhí)行的腳本內(nèi)容,至于后面的腳本參數(shù)部分與本文無關(guān),在此不做贅述。

特性

由于Redis對數(shù)據(jù)集單線程讀寫的特性,Lua腳本執(zhí)行時會阻塞所有對數(shù)據(jù)集的讀寫操作,這給它帶來了下面兩個特性:

  • 原子性:可以通過Lua腳本實現(xiàn)對數(shù)據(jù)集的原子讀寫操作,這和Redis的事務(wù)功能MULTI / EXEC類似
  • 長時間阻塞風(fēng)險:如果Lua腳本執(zhí)行時間過長,導(dǎo)致整個Redis不可用

執(zhí)行流程

eval "return 'hello world'" 0為例,腳本執(zhí)行步驟如下

定義腳本函數(shù)

執(zhí)行過的腳本可以根據(jù)hash值找到函數(shù)重新使用

Redis會根據(jù)傳入的腳本內(nèi)容生成函數(shù),函數(shù)名由 f_ + 腳本內(nèi)容的sha1摘要組成。

function f_5332031c6b470dc5a0dd9b4bf2030dea6d65de91()
	return 'hello world'
end

函數(shù)保存到 Lua_scripts字典,便于 evalsha使用

執(zhí)行腳本函數(shù)

  • 將KEYS和ARGV兩個參數(shù)數(shù)組傳入Lua執(zhí)行環(huán)境
  • 裝載超時處理鉤子
  • 執(zhí)行腳本
  • 移除超時鉤子
  • 結(jié)果保存到客戶端輸出緩沖區(qū),等待服務(wù)器將結(jié)果返回客戶端
  • Lua環(huán)境垃圾回收

關(guān)于腳本超時

介紹完EVAL命令,下面來關(guān)注Lua腳本長時間阻塞的風(fēng)險。

Redis的配置文件中提供了如下配置項來規(guī)定最大執(zhí)行時長

  • Lua-time-limit 5000 Lua腳本最大執(zhí)行時間,默認(rèn)5秒

但這里有個坑,當(dāng)一個腳本達(dá)到最大執(zhí)行時長的時候,Redis并不會強(qiáng)制停止腳本的運行,僅僅在日志里打印個警告,告知有腳本超時。

Lua slow script detected: still in execution after 5000 milliseconds. You can try killing the script using the SCRIPT KILL command. Script SHA1 is: 2531e4edc1a1e2a9bac3c52e99466f9ccabf12c0

為什么不能直接停掉呢?

因為 Redis 必須保證腳本執(zhí)行的原子性,中途停止可能導(dǎo)致內(nèi)存的數(shù)據(jù)集上只修改了部分?jǐn)?shù)據(jù)。

(只讀的腳本應(yīng)該是可以自動停的,沒自動停的原因我猜測是:腳本超時嚴(yán)重可以肯定出現(xiàn)了編碼錯誤,作者可能希望在測試中盡早發(fā)現(xiàn)這種問題,而不是靠自動停止導(dǎo)致bug被忽略?)

如果時長達(dá)到 Lua-time-limit 規(guī)定的最大執(zhí)行時間,Redis只會做這幾件事情:

日志記錄有腳本運行超時

開始允許接受其他客戶端請求,但僅限于 SCRIPT KILLSHUTDOWN NOSAVE 兩個命令

其他請求仍返回busy錯誤

SCRIPT KILL 命令

如果Lua只是讀取數(shù)據(jù)而沒做修改的話,執(zhí)行 SCRIPT KILL 就可以直接終止腳本執(zhí)行,不用擔(dān)心數(shù)據(jù)被修改。

但是,如果腳本已經(jīng)改寫了數(shù)據(jù)內(nèi)容,SCRIPT KILL將報出以下錯誤,因為它破壞數(shù)據(jù)集的內(nèi)容。

(error) UNKILLABLE Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in a hard way using the SHUTDOWN NOSAVE command.

SHUTDOWN NOSAVE 命令

如上所述,如果腳本已經(jīng)執(zhí)行了寫命令,SCRIPT KILL將無法執(zhí)行。那我們就只剩以下兩種選擇了:

  • 繼續(xù)等待腳本執(zhí)行完成
  • 使用 SHUTDOWN NOSAVE 來直接停掉 Redis,并避免臟數(shù)據(jù)持久化到磁盤

最后,不知道你有沒有疑問,從開始執(zhí)行腳本到 SHUTDOWN 之間的寫命令會把日志寫到AOF里嗎?Lua腳本中的命令什么時候會寫AOF里?

講道理,既然 Redis 為了不破壞腳本的原子性而不讓SCRIPT KILL執(zhí)行,那么腳本中寫命令的 “提交” 也應(yīng)當(dāng)是原子執(zhí)行的,而不是執(zhí)行一句就向AOF里寫一句。

“提交”:借用數(shù)據(jù)庫中 commit 的概念,這里指寫入AOF文件中

下面就來驗證這個猜測:

先執(zhí)行 tail -f appendonly.aof 實時查看AOF文件變化

再開一個redis-cli 命令行執(zhí)行一個內(nèi)容如下的Lua腳本

redis.call('set','a','aaaa') --先執(zhí)行寫命令
local count = 1 
while( 999999999 > count ) -- 阻塞幾秒
do  
   count = count+1   
end
127.0.0.1:6379> eval "redis.call('set','a','aaaa') local count = 1 while( 999999999 > count ) do  count = count+1   end" 0
(nil)
(8.65s)

現(xiàn)象是,腳本剛開始執(zhí)行,AOF文件毫無反應(yīng),一直等到8秒后腳本完成,命令才追加寫入到AOF中。

這就驗證了Redis腳本里的寫命令是等到執(zhí)行完成后再一次性寫入AOF的。

參考

Redis設(shè)計與實現(xiàn)

到此這篇關(guān)于Redis中Lua腳本的使用和設(shè)置超時 的文章就介紹到這了,更多相關(guān)Redis Lua 超時內(nèi)容請搜索本站以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持本站!

美國服務(wù)器租用

版權(quán)聲明:本站文章來源標(biāo)注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請保持原文完整并注明來源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非maisonbaluchon.cn所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來,僅供學(xué)習(xí)參考,不代表本站立場,如有內(nèi)容涉嫌侵權(quán),請聯(lián)系alex-e#qq.com處理。

實時開通

自選配置、實時開通

免備案

全球線路精選!

全天候客戶服務(wù)

7x24全年不間斷在線

專屬顧問服務(wù)

1對1客戶咨詢顧問

在線
客服

在線客服:7*24小時在線

客服
熱線

400-630-3752
7*24小時客服服務(wù)熱線

關(guān)注
微信

關(guān)注官方微信
頂部