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

攔截Redis命令導(dǎo)致的Lua腳本執(zhí)行失敗的問題解決

 更新時(shí)間:2023年06月22日 10:10:04   作者:CodeFox  
本文主要介紹了攔截Redis命令導(dǎo)致的Lua腳本執(zhí)行失敗的問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

大家好,今天分享一個(gè)在使用 redis lua 腳本過程中遇到的一個(gè)問題,問題不難,但是容易踩坑。

lua 腳本使用方式

   // 定義腳本資源
   DefaultRedisScript redisScript = new DefaultRedisScript<>();
   redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource(SCRIPT_PATH + scriptName)));
   redisScript.setResultType(List.class);
   // 預(yù)加載腳本(可選)
   redisTemplate.getConnectionFactory().getClusterConnection().scriptLoad(redisScript.getScriptAsString().getBytes());
   // 執(zhí)行腳本
   stringRedisTemplate.execute(redisScript, keys, args);

redis script 相關(guān)命令說明

  • script load:將 lua 腳本加載到 redis 的腳本緩存中,返回該腳本的 sha1 校驗(yàn)和,之后通過 evalsha 命令用此校驗(yàn)和調(diào)用該腳本。
  • evalsha:根據(jù) sha1 執(zhí)行已加載入的 lua 腳本。
  • eval:執(zhí)行一段 lua 腳本代碼,執(zhí)行完后該腳本也會(huì)緩存到 redis 腳本緩存中。
  • script exists:根據(jù) sha1 檢查腳本是否已經(jīng)存在于腳本緩存中。
  • script flush:清空 redis 的腳本緩存,刪除所有已加載的 lua 腳本。
  • script kill:kill 正在執(zhí)行的 lua 腳本。

execute 方法執(zhí)行過程

reidsTemplate 里持有一個(gè) ScriptExecutor,最終的執(zhí)行都代理給 ScriptExecutor,ScriptExecutor 會(huì)通過 evalsha 命令去 redis server 端執(zhí)行腳本。

如果之前已經(jīng)通過 script load 命令預(yù)加載了 lua 腳本,則 evalsha 會(huì)正常執(zhí)行;如果沒有事先加載腳本且第一次執(zhí)行該腳本,則 evalsha 會(huì)返回 "NOSCRIPT No matching script. Please use EVAL." 異常,該異常會(huì)封裝成 RedisSystemException 拋出。

捕獲異常后,判斷如果異常類型是 NonTransientDataAccessException,且異常信息里包含 "NOSCRIPT" 關(guān)鍵詞,則再通過 eval 命令傳遞完整的腳本來執(zhí)行一次,執(zhí)行完之后會(huì)緩存腳本,以后每次調(diào)用只需通過 evalsha 命令傳遞 sha1 即可執(zhí)行。

項(xiàng)目中遇到的問題

負(fù)責(zé)的項(xiàng)目中有一段 lua 腳本用來做短信發(fā)送頻率的限流處理,服務(wù)部署到全新的一套環(huán)境后發(fā)現(xiàn)請求報(bào)錯(cuò) "NOSCRIPT No matching script. Please use EVAL.",根據(jù)上述介紹,該錯(cuò)誤表示 redis server 通過傳遞的 sha1 找不到相應(yīng)的腳本。

該服務(wù)目前做法是沒事先通過 script load 預(yù)加載腳本,是通過懶加載方式,由第一個(gè)請求去做加載操作。因?yàn)樾碌倪@套環(huán)境 redis 集群也是新搭建的,所以肯定是沒緩存此腳本的,但是按照上述分析,第一個(gè)請求 evalsha 失敗后是會(huì)執(zhí)行 eval 的。

所以可以推斷是異常類型不是 NonTransientDataAccessException,或者異常信息里沒有包含 "NOSCRIPT" 關(guān)鍵詞,導(dǎo)致異常直接拋出去了。

經(jīng)過排查發(fā)現(xiàn)是前兩周是接入了 sentinel-redis 流控功能引起的問題。

<dependency>
     <groupId>com.xxx</groupId>
     <artifactId>xxx-sentinel-spring-boot-starter-redis</artifactId>
     <version>${xxx-sentinel.version}</version>
</dependency>

該模塊會(huì)對每一個(gè) redis 命令做攔截,然后通過 sentinel 流控 api 進(jìn)行包裹。

實(shí)際命令是通過 method.invoke() 反射執(zhí)行的。如果執(zhí)行內(nèi)部有異常,會(huì)拋出 InvocationTargetException。

綜上,第一次執(zhí)行 evalsha 命令拋出的 "NOSCRIPT" RedisSystemException 被包裝成了 InvocationTargetException 異常,所以在此判斷直接返回 false,導(dǎo)致異常直接拋出了,并沒有執(zhí)行后續(xù)的 eval 命令。

怎么攔截 redis 命令

我們知道 redis 命令都是通過 RedisConnection 對象執(zhí)行的,RedisConnection 是從 RedisConnectionFactory 中 get 的。

RedisConnectionFactory 一般有 jedis、lettuce 這兩種實(shí)現(xiàn)。

通過 SpringBoot 自動(dòng)裝配裝載進(jìn) Spring 容器的就是具體的 RedisConnectionFactory 實(shí)現(xiàn)。

所以我們可以通過攔截 RedisConnectionFactory 的 getConnection 方法得到 RedisConnection,然后對 RedisConnection 在進(jìn)行一次代理,這樣所有的 redis 命令就都能走到我們自己的攔截器里了。

解決辦法

回到主題,我們要怎么解決這個(gè)問題呢?

  • 使用 lua 腳本最好在服務(wù)啟動(dòng)后通過 script load 做預(yù)加載。
  • 對 redis 命令(不限于)做攔截后,最好返回原始異常。

總結(jié)

  • 該問題還是比較坑的,不好復(fù)現(xiàn),在遷移新環(huán)境之前,一直沒出現(xiàn)過該問題,主要原因是 sentine-redis 包是最近才引入的,不管 dev、test、prod 各環(huán)境 lua 腳本其實(shí)早就已經(jīng)緩存到 redis server 了,走不到第一次加載的邏輯里去。
  • 對各種組件的執(zhí)行流程做攔截、擴(kuò)展前需仔細(xì)看下原有的執(zhí)行流程,是否對異常有特殊處理,最好返回原始異常。

到此這篇關(guān)于攔截Redis命令導(dǎo)致的Lua腳本執(zhí)行失敗的問題解決的文章就介紹到這了,更多相關(guān)redis lua執(zhí)行內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 批量導(dǎo)入txt數(shù)據(jù)到的redis過程

    批量導(dǎo)入txt數(shù)據(jù)到的redis過程

    用戶通過將Redis命令逐行寫入txt文件,利用管道模式運(yùn)行客戶端,成功執(zhí)行批量刪除以"Product*"匹配的Key操作,提高了數(shù)據(jù)清理效率
    2025-08-08
  • 一篇吃透Redis緩存穿透、雪崩、擊穿問題

    一篇吃透Redis緩存穿透、雪崩、擊穿問題

    這篇文主要介紹了Redis緩存穿透,緩存雪崩,緩存擊穿的問題解決方法,文中有詳細(xì)的圖文介紹,對大家了解Redis有一定的幫助,需要的朋友可以參考下
    2023-05-05
  • 為Redis設(shè)置密碼的三種方法

    為Redis設(shè)置密碼的三種方法

    Redis 是一個(gè)高性能的鍵值對數(shù)據(jù)庫,廣泛應(yīng)用于緩存、消息隊(duì)列等場景,為了保障 Redis 服務(wù)的安全性,設(shè)置密碼認(rèn)證是非常重要的一步,所以本文給大家介紹了為Redis設(shè)置密碼的三種方法,需要的朋友可以參考下
    2024-11-11
  • redis+lua實(shí)現(xiàn)限流的項(xiàng)目實(shí)踐

    redis+lua實(shí)現(xiàn)限流的項(xiàng)目實(shí)踐

    redis有很多限流的算法(比如:令牌桶,計(jì)數(shù)器,時(shí)間窗口)等,在分布式里面進(jìn)行限流的話,我們則可以使用redis+lua腳本進(jìn)行限流,下面就來介紹一下redis+lua實(shí)現(xiàn)限流
    2023-10-10
  • 如何使用注解方式實(shí)現(xiàn)?Redis?分布式鎖

    如何使用注解方式實(shí)現(xiàn)?Redis?分布式鎖

    這篇文章主要介紹了如何使用注解方式實(shí)現(xiàn)Redis分布式鎖,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,教大家如何優(yōu)雅的使用Redis分布式鎖,感興趣的小伙伴可以參考一下
    2022-07-07
  • 使用Redis實(shí)現(xiàn)分布式鎖的代碼演示

    使用Redis實(shí)現(xiàn)分布式鎖的代碼演示

    edis作為一個(gè)高性能的內(nèi)存數(shù)據(jù)庫,提供了多種機(jī)制來實(shí)現(xiàn)分布式鎖,本文將詳細(xì)介紹如何使用Redis實(shí)現(xiàn)分布式鎖,感興趣的朋友一起看看吧
    2025-04-04
  • Redis集群增加節(jié)點(diǎn)與刪除節(jié)點(diǎn)的方法詳解

    Redis集群增加節(jié)點(diǎn)與刪除節(jié)點(diǎn)的方法詳解

    這篇文章主要給大家介紹了關(guān)于Redis集群增加節(jié)點(diǎn)與刪除節(jié)點(diǎn)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • linux?redis-連接命令解讀

    linux?redis-連接命令解讀

    這篇文章主要介紹了linux?redis-連接命令解讀,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Redis中Hash類型相關(guān)命令介紹

    Redis中Hash類型相關(guān)命令介紹

    Redis?hash是一個(gè)String類型的field和value的映射表,hash特別適合用于存儲(chǔ)對象,這篇文章主要介紹了Redis中Hash類型相關(guān)命令的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-12-12
  • Redis避免以后AOF再次損壞的預(yù)防措施

    Redis避免以后AOF再次損壞的預(yù)防措施

    文章提供了修復(fù)和防止Redis AOF文件損壞的方法,包括臨時(shí)修復(fù)、關(guān)鍵配置設(shè)置、雙保險(xiǎn)策略、運(yùn)維規(guī)范和一鍵自救命令,重點(diǎn)介紹了安全AOF刷盤、AOF自動(dòng)碎片重寫、損壞容錯(cuò)配置、關(guān)閉混合AOF等配置,并強(qiáng)調(diào)了避免磁盤滿、定期巡檢等運(yùn)維規(guī)范,需要的朋友可以參考下
    2026-04-04

最新評論

清涧县| 大竹县| 休宁县| 桂林市| 阿合奇县| 通化县| 得荣县| 溧阳市| 榆树市| 南平市| 东明县| 梅州市| 芦山县| 什邡市| 仁布县| 吐鲁番市| 凭祥市| 太仆寺旗| 连云港市| 宣恩县| 稻城县| 双桥区| 镇远县| 惠水县| 那曲县| 股票| 房山区| 大港区| 兴义市| 桐庐县| 海晏县| 芒康县| 山东省| 宜川县| 东乡县| 武穴市| 曲周县| 迭部县| 潮安县| 新竹市| 崇州市|