執行Lua腳本后一直查詢不到Redis中的數據(附帶問題詳細排查過程,一波三折)

文章目錄

  • 執行Lua腳本后一直查詢不到Redis中的數據(附帶詳細問題排查過程,一波三折)
    • 問題背景
    • 問題1:Lua腳本無法切庫
    • 問題2:RedisTemlate切庫報錯
    • 問題3:序列化導致數據不一致
    • 問題4:Lua腳本中單引號無法拼接字符串
    • 總結

執行Lua腳本后一直查詢不到Redis中的數據(附帶詳細問題排查過程,一波三折)

這個問題坑慘我了,估計耗費了我兩個小時😫,中間走了不少彎路,好在我靈光一閃+GPT給我的靈感否則就栽在這上面了

問題背景

  • 問題背景

    在使用 Redis 實現接口調用次數扣減操作時,發現響應結果一直返回的是 -1,也就是查詢不到數據

    image-20230813222603833

問題1:Lua腳本無法切庫

  • 問題排查過程1

    經過一段排查,加上GPT的提示信息,我快速定位到了是可能是參數的問題,但是通過 Debug 斷點調試,我可以百分百肯定這個參數肯定沒有問題;然后我又到 redis-cli 執行原生的 Redis 指令,發現也查不到數據!(○′・д・)ノ,懵逼了,搗鼓了半天突然想起來有沒有可能是這個數據庫中壓根沒有數據,于是我使用 keys *指令查看數據庫中是否有數據,結果發現有數據,但是壓根就沒有我預熱的數據!!!這是什么原因呢?一看 REP 就恍然大悟了,我操作的數據庫1,但是由于我配置文件中使用的是數據庫 0,導致我預熱的數據 都在 數據庫1中,而 Lua腳本默認操作的數據庫0,那么問題就簡單了,直接使用 redis('select',1)這條指令切換一下數據庫不久OK了嗎(我真聰明🤭)然后我先在redis-cli上實驗,發現的確是這個的原因,嘿嘿問題成功解決了?(你不會以為這就完了吧🤣)

  • 問題原因:Lua腳本默認使用的數據庫0,我的數據在數據庫1中

  • 問題解決

    在執行Lua腳本前,先切換一下數據庫

    redis('SELECT', 1)
    

    ==結果發現在 Lua 腳本中添加了redis('SELECT', 1)之后壓根就沒有用!==┭┮﹏┭┮

    只能繼續排查問題,

  • 問題排查過程2

    在lua腳本中查詢數據前,加上redis('select',1),結果發現嘿嘿還是返回-1!這下徹底懵逼了,結果經過詢問ChartGPT,發現:Lua腳本不能切換數據庫,還是太天真了

    image-20230813223736240

    既然Lua腳本無法完成切庫,那么就需要使用 RedisTemplate 進行切庫

  • 問題解決

            RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();connection.select(1);
    

    你不會以為這么快就解決了這個問題吧!

問題2:RedisTemlate切庫報錯

  • 問題排查過程2

    redisTemplate 切庫引發的新問題:在添加了上面代碼后,結果又報錯Selecting a new database not supported due to shared connection. Use separate ConnectionFactorys to work with multiple databases.

    在此詢問GPT,發現是由于 Redis 的共享連接限制,無法直接在同一個連接上切換到不同的數據庫。如果你需要在執行 Lua 腳本之前切換 Redis 數據庫,可以嘗試使用不同的連接工廠來處理多個數據庫

  • 問題解決

    • 解決方案一:直接關閉RedisTemplate的共享連接(不推薦)

      詳情請參考這篇文章:Springboot整合redis切庫問題

      在使用 Spring Data Redis 時,默認情況下是共享連接的,因為這可以提高性能和效率。然而,如果你確實需要關閉共享連接,并為每個數據庫創建一個獨立的連接,也是可以的。但是需要注意一些潛在的問題:

      1. 性能影響:共享連接可以減少連接的開銷,而獨立連接則需要更多的資源來維護和管理。因此,關閉共享連接可能會對系統的整體性能產生一定的影響。
      2. 連接池限制:Redis 連接池有著最大連接數的限制,每個連接都占用一部分連接資源。如果為每個數據庫都創建獨立的連接,那么連接池中可用的連接數量將被均分,這可能導致每個數據庫可用連接數的減少。
      3. 連接管理復雜性:對于每個獨立的連接,你需要額外管理和維護連接的生命周期,包括創建、銷毀、異常處理等。這可能增加代碼的復雜性和維護成本。

      總之,關閉共享連接并為每個數據庫創建獨立的連接可能會帶來性能和連接管理方面的一些負面影響。因此,在進行決策時,請權衡利弊,并根據具體需求和系統規模做出選擇。

    • 解決方案二:新建一個RedisTemplate

      為了提高代碼的復用性,我就打算利用 單例模式+原型模式 對IOC容器中的RedisTemplate進行一個拷貝,然后將這個新的RedisTemplate來切庫,相對于方案一要更加方便

      下面是代碼:

      package com.ghp.admin.redis;import com.ghp.common.utils.BeanConvertorUtils;
      import org.springframework.data.redis.connection.RedisConnection;
      import org.springframework.data.redis.core.RedisTemplate;/*** @author ghp* @title* @description*/
      public class RedisUtils {private RedisTemplate redisTemplate;private static RedisUtils instance;static {instance = new RedisUtils();}public RedisUtils getInstance(RedisTemplate redisTemplate){this.redisTemplate = redisTemplate;return instance;}/*** 創建一個新的RedisTemplate,并且切換數據庫* @param databaseIndex* @return*/public RedisTemplate<String, String> createRedisTemplate(int databaseIndex) {// 進行拷貝(這里是是使用自己封裝的工具類,你可以選擇使用Spring框架自帶的拷貝工具類)RedisTemplate newRedisTemplate = BeanConvertorUtils.copyBean(redisTemplate,RedisTemplate.class);RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();connection.select(databaseIndex);return newRedisTemplate;}
      }
      

    看上去好像已經成功解決了,但是還沒完,經過測試發現執行 Lua 腳本后仍然無法從Redis中查詢到數據庫w(゚Д゚)w

    這些我又陷入了懵逼中

問題3:序列化導致數據不一致

  • 問題排查過程3

    我開始陷入懷疑當中,因為我在 redis-cli 中經過切庫后,發現執行指令是可以查詢到數據的,難道是切庫失敗了?經過檢驗發現切庫是成功的,因為我在 Lua 腳本中執行硬編碼local leftNum = redis.call('HGET', 'cache:interface:pathMethod:', '/api/name/user-POST') 是的的確確查詢到了數據的!

    我開始懷疑是不是我參數傳遞錯了,但是經過 return leftNum發現是有數據的,而且數據是真確的,這是什么原因呢?

    image-20230814104711299

    雖然返回結果是一樣的,可能不可能Lua腳本中的值不一樣呢?我繼續抱著試一試的態度,執行下面的代碼

    local key1 = KEYS[1]
    if key1 == '/api/name/user' thenreturn 1
    end
    return 2
    

    結果意料之外的居然返回了 2,也就是說我 傳入了 ’/api/name/user‘,然后從 Lua 中 返回的是 ’/api/name/user‘,但是 Lua 中兩個值竟然不相等!

    我開始懷疑難道是編碼的問題嗎?因為之前在看微信公眾號上的一篇文章,有個大佬就是因為編碼(全角和半角)的問題導致查詢不到數據,于是我抱著試一試的心態,測試了一下編碼,有看了一下編譯器使用的編碼格式,發現是全局 UTF-8

    所以可以排除編碼問題了,那會是什么原因呢,百思不得其解,突然靈光一閃會不會是序列化的問題,我全局為RedisTemplate配置了序列化轉換器,但是我還是不敢相信,因為我在Lua腳本中返回的 retrun ARGV[1]和我查詢使用的 key也就是/api/name/user是一摸一樣的

    image-20230814135211981

    發現仍然照樣沒有查詢到數據,在 Lua 腳本中返回 pathJson,發現是\"/api/name/user\",這一下又給了靈感,會不會是傳入的JSON多了有個\",于是我做出如下實驗

    local key1 = KEYS[1]
    if key1 == '\"/api/name/user\"' thenreturn 1
    end
    return 2
    

    驚奇的發現這回終于返回 1,也就是說傳入的 path 是 竟然是 \"/api/name/user\"(結果很震驚,因為之前我在Lua腳本中返回path時,結果就是/api/name/user,返回的結果根本沒有"),我猜測應該是RedisTemplate在處理Lua的返回結果時會多做一層序列化,登錄參數的傳遞過程中需要經過一層序列化!至此問題終于解決了(你不會以為這就成功解決了吧)

  • 解決方案

    在接收參數后進行預處理,也就是去掉傳入參數中多余的

    local key1 = string.gsub(KEYS[1], "\"", "") -- cache:interface:pathMethod:
    local key2 = string.gsub(KEYS[2], "\"", "") -- cache:interface:leftNum:
    -- 獲取hashKey
    local path = string.gsub(ARGV[1], "\"", "")
    local method = string.gsub(ARGV[2], "\"", "")
    local userId = string.gsub(ARGV[3], "\"", "")
    

問題4:Lua腳本中單引號無法拼接字符串

  • 問題排查4

    后面我改造了代碼,發現仍然不成功!!!😫 ┭┮﹏┭┮

    經過測試,我發現

    local key1 = path .. '-' .. method
    return key1
    

    發現只會返回 -前面的字符串 也就是 path,如果調換path和method的未知,那么只會返回method,我又陷入了沉思。

    后面我突然想起來了,是Lua中雙引號和單引號的區別,使用 .. 運算符可以用來拼接字符串。這個運算符可以連接兩個字符串(或者將其他數據類型轉換為字符串后連接)。然而,.. 運算符只能用于連接雙引號字符串。單引號字符串在 Lua 中表示字符,而不是字符串。如果你試圖使用 .. 運算符連接兩個單引號字符串,會得到一個語法錯誤。

  • 解決方法

    local key1 = tostring(path) .. "-" .. tostring(method)
    return key1
    

    成功解決了。如果你對Lua感興趣的可以參考這篇文章:Lua快速入門筆記_知識汲取者的博客-CSDN博客

總結

終于解決了這個問題,感覺好舒爽😄

總的來說,我遇到的問題是 Java 代碼使用 RedisTemplate.execute 執行 Lua腳本的時候,由于我配置了全局序列化,所以導致 傳入Lua腳本中的參數 會先被序列化,而Lua腳本的參數被傳出來時同樣會被反序列化,這個序列化和反序列化對我而言是透明的,所以導致我沒有想到居然序列化了一遍,從而導致我走了好多彎路

image-20230814141308247

這里提一嘴:前面那個Lua腳本默認使用數據庫 0不完全正確,如果我們在配置文件中配置了使用哪一個數據庫,那么在Lua腳本中就會使用哪一個數據庫,所以我們可以不用切庫,也能保障 Lua腳本能夠操作數據庫1,所以前面的 問題1 和 問題2 不需要,根本原因在于序列化和反序列化問題

參考資料

  • ChartGPT3.5
  • Springboot整合redis切庫問題

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/41691.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/41691.shtml
英文地址,請注明出處:http://en.pswp.cn/news/41691.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Etcd備份及恢復

一、Etcd數據備份 1、備份命令 [rootlocalhost ~]# export ETCDCTL_API3 [rootlocalhost ~]# /data/etcd-3.4.9/bin/etcdctl --endpoints10.2.20.108:2379 snapshot save etcd-date "%Y-%m-%d_%H-%M-%S".snapshot 2、備份完成后會在當前目錄生成備份文件 [rootlo…

vue實現打印功能

在Vue應用中調用打印機功能&#xff0c;可以使用JavaScript的window.print()方法。這個方法會打開打印對話框&#xff0c;然后讓我們選擇打印設置并打印文檔&#xff0c;但是尼這種方法依賴于瀏覽器的打印功能。 以下是一個簡單的示例&#xff0c;演示如何在Vue組件中調用打印…

Linux Tracing Technologies

目錄 1. Linux Tracing Technologies 1. Linux Tracing Technologies Linux Tracing TechnologieseBPFXDPDPDK

Flask Web開發實戰(狼書)| 筆記第1、2章

前言 2023-8-11 以前對網站開發萌生了想法&#xff0c;又有些急于求成&#xff0c;在B站照著視頻敲了一個基于flask的博客系統。但對于程序的代碼難免有些囫圇吞棗&#xff0c;存在許多模糊或不太理解的地方&#xff0c;只會照葫蘆畫瓢。 而當自己想開發一個什么網站的時&…

ubuntu部署haproxy

HAProxy是可提供高可用性、負載均衡以及基于TCP和HTTP應用的代理. 1、更新系統報 通過在終端中運行以下命令&#xff0c;確保所有系統包都是最新的 sudo apt updatesudo apt upgrade2、安裝Haproxy sudo apt install haproxy設置開機自動啟動haproxy服務 sudo systemctl en…

Lnton羚通關于如何解決nanoPC-T4 upgrade報錯問題?

nanoPC-T4 在 ??# sudo apt update 和 sudo apt upgrade??升級或安裝軟件 ??sudo apt install xxx??時遇到以下問題&#xff1a;??Failed to set up interface with /etc/hostapd/? Setting up hostapd (2:2.6-15ubuntu2.8) ... Job for hostapd.service failed be…

ssm+vue醫院住院管理系統源碼和論文PPT

ssmvue醫院住院管理系統源碼和論文PPT012 開發工具&#xff1a;idea 數據庫mysql5.7(mysql5.7最佳) 數據庫鏈接工具&#xff1a;navcat,小海豚等 開發技術&#xff1a;java ssm tomcat8.5 摘 要 隨著時代的發展&#xff0c;醫療設備愈來愈完善&#xff0c;醫院也變成人們生…

基于IMX6ULLmini的linux裸機開發系列一:匯編點亮LED

思來想去還是決定記錄一下點燈&#xff0c;畢竟萬物皆點燈嘛 編程步驟 使能GPIO時鐘 設置引腳復用為GPIO 設置引腳屬性(上下拉、速率、驅動能力) 控制GPIO引腳輸出高低電平 使能GPIO時鐘 其實和32差不多 先找到控制LED燈的引腳&#xff0c;也就是原理圖 文件名 C:/Us…

spring頭約束(全部)

文章目錄 spring-mvcspring-aopspring-txspring-contextspring-taskspring-cachespring-jdbcp命令空間spring-jeejmslangoxmutil總結 spring-mvc <beans xmlns"http://www.springframework.org/schema/beans" xmlns:xsi"http://www.w3.org/2001/XMLSchema-…

AUTOSAR NvM Block的三種類型

Native NVRAM block Native block是最基礎的NvM Block&#xff0c;可以用來存儲一個數據&#xff0c;可以配置長度、CRC等。 Redundant NVRAM block Redundant block就是在Native block的基礎上再加一個冗余塊&#xff0c;當Native block失效&#xff08;讀取失敗或CRC校驗失…

劍指offer44.數字序列中某一位的數字

最后一道題&#xff0c;我一定要自己做出來&#xff0c;想了不到一個小時想法差不多成熟了&#xff0c;但是有一個小細節出問題了&#xff0c;這個問題我在idea上debug都沒debug出來。我先講我的題解然后再講我這個小問題出在哪里吧。以下是我的代碼&#xff1a; class Soluti…

PHP手術麻醉系統源碼,自動生成麻醉和護理醫療文書

一套手術麻醉系統源碼&#xff0c;可二次開發 手術室麻醉臨床信息系統&#xff08;AIMS&#xff09;是應用于醫院手術室、麻醉科室的計算機軟件系統。該系統針對整個圍術期&#xff0c;對病人進行全程跟蹤與信息管理&#xff0c;自動集成病人HIS、LIS、RIS、PACS信息&#xff0…

【SA8295P 源碼分析】76 - Thermal 功耗 之 /dev/thermalmgr 相關調試命令匯總

【SA8295P 源碼分析】76 - Thermal 功耗 之 /dev/thermalmgr 相關調試命令匯總 1、配置文件:/mnt/etc/system/config/thermal-engine.conf2、獲取當前SOC所有溫度傳感器的溫度:cat /dev/thermalmgr3、查看所有 Thermal 默認配置和自定義配置:echo query config > /dev/th…

【Spring源碼】小白速通解析Spring源碼,從0到1,持續更新!

Spring源碼 參考資料 https://www.bilibili.com/video/BV1Tz4y1a7FM https://www.bilibili.com/video/BV1iz4y1b75q bean工廠 DefaultListableBeanFactory&#xff08;最原始&#xff09; bean的生命周期 創建&#xff08;實例化&#xff09;–>依賴注入–>-初始化…

利用vue-router跳轉的幾種方式

?1 <router-link> 2 this.$router.push 跳轉到指定路徑&#xff0c;并將跳轉頁面壓入history棧中&#xff0c;也就是添加了一個頁面記錄。3 this.$router.replace 跳轉到指定路徑&#xff0c;將history棧中的當前頁面替換為跳轉到的頁面。4 this.$router.go(n) 在his…

數據生成 | MATLAB實現WGAN生成對抗網絡數據生成

數據生成 | MATLAB實現WGAN生成對抗網絡數據生成 目錄 數據生成 | MATLAB實現WGAN生成對抗網絡數據生成生成效果基本描述程序設計參考資料 生成效果 基本描述 1.WGAN生成對抗網絡&#xff0c;數據生成&#xff0c;樣本生成程序&#xff0c;MATLAB程序&#xff1b; 2.適用于MATL…

從public static void main(String[] args)看如何構造數據

java語言中public static void main(String[] args)里面的ages有什么作用&#xff1f; 在Java語言中&#xff0c;public static void main(String[] args) 是一個特殊的方法&#xff0c;它是Java程序的入口點。當你運行一個Java程序時&#xff0c;程序會從這個方法開始執行。這…

【游戲評測】河洛群俠傳一周目玩后感

總游戲時長接近100小時&#xff0c;剛好一個月。 這兩天費了點勁做了些成就&#xff0c;刷了等級&#xff0c;把最終決戰做了。 總體感覺還是不錯的。游戲是開放世界3D游戲&#xff0c;Unity引擎&#xff0c;瑕疵很多&#xff0c;但勝在劇情扎實&#xff0c;天賦系統、秘籍功法…

kubernetes(二)

文章目錄 1. kubernetes常用資源1.1 deployment資源1.2 deployment升級和回滾1.3 tomcat連接mysql1.4 wordpress 2. kubernetes的附加組件2.1 kubernetes集群配置dns服務2.2 kubernetes的dns配置文件2.3 namespace命名空間2.4 kubernetes健康檢查2.4.1 健康檢查livenessprobo2.…

代碼隨想錄二刷day01

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 前言一、704. 二分查找二、35. 搜索插入位置三、34. 在排序數組中查找元素的第一個和最后一個位置四、69. x 的平方根五、367. 有效的完全平方數六、27. 移除元素七…