欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2021年11月24日 15:20:44   作者:hhgfy  
本文將介紹Redis中Lua腳本的基本用法,以及腳本超時(shí)導(dǎo)致的問題和處理方式。文中通過示例代碼介紹的非常詳細(xì),感興趣的小伙伴們可以參考一下

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

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

EVAL命令簡(jiǎn)介

eval格式

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

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

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

特性

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

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

執(zhí)行流程

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

定義腳本函數(shù)

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

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

function f_5332031c6b470dc5a0dd9b4bf2030dea6d65de91()
	return 'hello world'
end

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

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

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

關(guān)于腳本超時(shí)

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

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

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

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

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

為什么不能直接停掉呢?

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

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

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

日志記錄有腳本運(yùn)行超時(shí)

開始允許接受其他客戶端請(qǐng)求,但僅限于 SCRIPT KILLSHUTDOWN NOSAVE 兩個(gè)命令

其他請(qǐng)求仍返回busy錯(cuò)誤

SCRIPT KILL 命令

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

但是,如果腳本已經(jīng)改寫了數(shù)據(jù)內(nèi)容,SCRIPT KILL將報(bào)出以下錯(cuò)誤,因?yàn)樗茐臄?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 之間的寫命令會(huì)把日志寫到AOF里嗎?Lua腳本中的命令什么時(shí)候會(huì)寫AOF里?

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

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

下面就來驗(yàn)證這個(gè)猜測(cè):

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

再開一個(gè)redis-cli 命令行執(zhí)行一個(gè)內(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中。

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

參考

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

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

相關(guān)文章

  • Redis?存儲(chǔ)對(duì)象信息用?Hash?和String的區(qū)別

    Redis?存儲(chǔ)對(duì)象信息用?Hash?和String的區(qū)別

    這篇文章主要介紹了Redis存儲(chǔ)對(duì)象信息用Hash和String的區(qū)別,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-09-09
  • Redis如何實(shí)現(xiàn)分布式鎖

    Redis如何實(shí)現(xiàn)分布式鎖

    相信大家對(duì)鎖已經(jīng)不陌生了,本文主要介紹了Redis如何實(shí)現(xiàn)分布式鎖,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • 簡(jiǎn)介L(zhǎng)ua腳本與Redis數(shù)據(jù)庫的結(jié)合使用

    簡(jiǎn)介L(zhǎng)ua腳本與Redis數(shù)據(jù)庫的結(jié)合使用

    這篇文章主要介紹了簡(jiǎn)介L(zhǎng)ua腳本與Redis數(shù)據(jù)庫的結(jié)合使用,Redis是基于主存的高性能數(shù)據(jù)庫,需要的朋友可以參考下
    2015-06-06
  • Redis RDB技術(shù)底層原理詳解

    Redis RDB技術(shù)底層原理詳解

    為了使Redis在重啟之后仍能保證數(shù)據(jù)不丟失,需要將數(shù)據(jù)從內(nèi)存中以某種形式同步到硬盤中,這一過程就是持久化,本文重點(diǎn)給大家介紹Redis RDB技術(shù)底層原理實(shí)現(xiàn)方法,一起看看吧
    2021-09-09
  • AOP?Redis自定義注解實(shí)現(xiàn)細(xì)粒度接口IP訪問限制

    AOP?Redis自定義注解實(shí)現(xiàn)細(xì)粒度接口IP訪問限制

    這篇文章主要為大家介紹了AOP?Redis自定義注解實(shí)現(xiàn)細(xì)粒度接口IP訪問限制,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • redis數(shù)據(jù)一致性之延時(shí)雙刪策略詳解

    redis數(shù)據(jù)一致性之延時(shí)雙刪策略詳解

    在使用redis時(shí),需要保持redis和數(shù)據(jù)庫數(shù)據(jù)的一致性,最流行的解決方案之一就是延時(shí)雙刪策略,今天我們就來詳細(xì)刨析一下,需要的朋友可以參考下
    2023-09-09
  • 使用Redis實(shí)現(xiàn)用戶積分排行榜的教程

    使用Redis實(shí)現(xiàn)用戶積分排行榜的教程

    這篇文章主要介紹了使用Redis實(shí)現(xiàn)用戶積分排行榜的教程,包括一個(gè)用PHP腳本進(jìn)行操作的例子,需要的朋友可以參考下
    2015-04-04
  • Redis實(shí)現(xiàn)唯一計(jì)數(shù)的3種方法分享

    Redis實(shí)現(xiàn)唯一計(jì)數(shù)的3種方法分享

    這篇文章主要介紹了Redis實(shí)現(xiàn)唯一計(jì)數(shù)的3種方法分享,本文講解了基于SET、基于 bit、基于 HyperLogLog三種方法,需要的朋友可以參考下
    2015-03-03
  • 關(guān)于Redis網(wǎng)絡(luò)模型的源碼詳析

    關(guān)于Redis網(wǎng)絡(luò)模型的源碼詳析

    這篇文章主要給大家介紹了關(guān)于Redis網(wǎng)絡(luò)模型的源碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用Redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Linux、Windows下Redis的安裝即Redis的基本使用詳解

    Linux、Windows下Redis的安裝即Redis的基本使用詳解

    Redis是一個(gè)基于內(nèi)存的key-value結(jié)構(gòu)數(shù)據(jù)庫,Redis 是互聯(lián)網(wǎng)技術(shù)領(lǐng)域使用最為廣泛的存儲(chǔ)中間件,這篇文章主要介紹了Linux、Windows下Redis的安裝即Redis的基本使用詳解,需要的朋友可以參考下
    2022-09-09

最新評(píng)論