像調試java一樣來調試Redis lua
高並發的系統中,redis的使用是非常頻繁的,而lua腳本則更是錦上添花。因為lua腳本本身執行的時候是一個事務性的操作,不會摻雜其他外部的命令,所以很多關鍵的系統節點都會用redis+lua來實現一致性的操作請求。但是在實際開發過程中,由於redis lua腳本調試難的問題,導致大量的時間耗費在了這上面。如果有什麽方案能夠讓我們像利用IDEA調試java一樣簡便去調試redis lua腳本,那該是很幸福的事兒了。
通過不斷的尋找,終於也找到了這種方式,下面就總體的來介紹一下。
1. 下載ZeroBraneStudio,解壓到本地環境,然後找到解釋器路徑,比如我本機是D:\soft\pkulchenko-ZeroBraneStudio-7a8027e\bin\lua.exe,那麽我們就可以通過如下的cmd命令,將D:\soft\pkulchenko-ZeroBraneStudio-7a8027e\bin\添加到Path環境變量中即可。cmd命令如下:
set path=%path%;D:\soft\pkulchenko-ZeroBraneStudio-7a8027e\bin\;
2. 下載luaRocks,你可以理解為它類似於python的pip包管理工具,可以利用此工具下載相應的lua包。下載地址為:http://luarocks.github.io/luarocks/releases/,註意選擇其中帶有win32字樣的包,不要選擇帶有windows字樣的包,因為win32字樣的包裏面有install.bat。下載完畢後,解壓,運行install.bat安裝即可。
3. 安裝redis及調試相關的類庫。舉一反三,既然能安裝redis相關的,那麽也能安裝nginx相關的,所以我們也可以利用此方法來搞定nginx lua開發:
luarocks install remdebug
luarocks install prtr-dump
luarocks install redis-lua
4. 打開ZeroBraneStudio,建立lua腳本,開始進行調試吧,具體步驟如下:
首先,在lua腳本中,加入下面這段代碼,以便於讓lua腳本支持調試:
local redis = require ‘redis‘ local host = "192.168.155.126" local port = 6379 client = redis.connect(host, port) redis.call = function(cmd, ...) returnassert(loadstring(‘return client:‘.. string.lower(cmd) ..‘(...)‘))(...) end
從上面可以看出,我們先進行了redis的配置操作,然後加了一個redis.call方法,以便於讓腳本實現調試操作。
然後,開始書寫我們正常的業務邏輯,整體代碼如下:
local redis = require ‘redis‘ local host = "192.168.155.126" local port = 6379 client = redis.connect(host, port) redis.call = function(cmd, ...) return assert(loadstring(‘return client:‘.. string.lower(cmd) ..‘(...)‘))(...) end -- key個數 local keysize = tonumber(3); --防重主鍵,比如orderid local pk = ‘orderid‘; --起始分值 local start_score = tonumber(1); --截止分值 local end_score = tonumber(3); --輸入值 local input = tonumber(5); --限制值 local limit = tonumber(100); --計算方式 local symbol = ‘>‘; --keys列表 local KEYS = {"pin","ip","phone"} --hashtag local hash_tag = ‘{sumhis}‘ --獲取主鍵歷史防重數據 local function get_duplicate_check_data(hash_key_appendix,field_key) local hash_key = hash_tag.."pk".. hash_key_appendix; local field_val = redis.call("HGET", hash_key , field_key); if field_val and field_val ~=nil and field_val ~= ‘‘ then return "1"; end return "0"; end --設置主鍵防重數據 local function set_duplicate_check_data(hash_key_appendix,field_key,input) local hash_key = hash_tag.."pk".. hash_key_appendix; redis.call("HSET",hash_key,field_key,input); end --獲取歷史計數數據 local function get_history_count_data(zset_key_appendix,start_score,end_score) local key = hash_tag..zset_key_appendix; local hdata = redis.call("ZRANGEBYSCORE",key,start_score,end_score); local hdatanum = #hdata; local totalNum = 0; if hdatanum > 0 then for i, buy in pairs(hdata) do --拆分字符串 local split = "_"; local valueSplit = {}; string.gsub(buy,‘[^‘..split..‘]+‘,function ( w ) table.insert(valueSplit,w) end) local orderSkuNum = valueSplit[2]; totalNum = totalNum + orderSkuNum; print("當前"..key.."購買數量為:"..orderSkuNum); end print("---->當前"..key.."購買總數為:"..totalNum); end return totalNum; end --設置歷史計數數據 local function set_history_count_data(zset_key_appendix,input,end_score,val_prefix) local key = hash_tag..zset_key_appendix; local value = val_prefix.."_"..input; redis.call(‘ZADD‘,key,end_score,value); end --根據運算符進行數學運算 local function calculate_by_symbol(left, right, symbol) if symbol == ‘+‘ then return left + right elseif symbol == ‘-‘ then return left - right elseif symbol == ‘*‘ then return left * right elseif symbol == ‘/‘ then return left / right elseif symbol == ‘>‘ then return left > right; elseif symbol == ‘<‘ then return left < right; elseif symbol == ‘>=‘ then return left >= right; elseif symbol == ‘<=‘ then return left <= right; elseif symbol == ‘==‘ then return left == right elseif symbol == ‘!=‘ then return left ~= right end end ------主邏輯流程開始------ -- 循環處理key 防重校驗,歷史計數數據比對 for i=0, keysize - 1, 1 do local key = KEYS[i+1]; --防重主鍵校驗 local checkpk = get_duplicate_check_data(key,pk); --無防重信息開始處理 if checkpk == "0" then --redis歷史數據查詢 local hdata = get_history_count_data(key,start_score,end_score); --數據比對 local calc_rst = calculate_by_symbol(input+hdata, limit, symbol); if calc_rst == true then print("---->已超限,無法繼續進行購買"); return "-1"; else print("---->未超限,可以繼續正常購買") end end end print("---->未超限,重置防重信息和歷史計數信息"); --如果無防重信息且數據未超限 for i=0, keysize - 1, 1 do local key = KEYS[i+1]; set_duplicate_check_data(key,pk,input); set_history_count_data(key,input,end_score,pk); end return "1"; ------主邏輯流程結束------
在書寫代碼的過程中,我們可以利用print方法來打印日誌,看看日誌部分是不是我們需要的值或者結果。
最後,我們運行程序,開啟調試模式,先點擊想要調試的代碼行,下斷點:
然後點擊下圖圖示的按鈕,開始進行調試:
然後程序就會啟動,開始調試,我們點擊下圖圖示的按鈕,就可以逐語句或者逐過程的進行了:
之後我們點擊按鈕幾次,就可以走到我們的方法裏面了,同時鼠標懸停到變量上面,就可以清楚的看到當前變量的值:
同時我們也可以在底部的窗口中添加監視變量來監視變量的內容:
在控制臺,我們也可以實時看到通過print打印出來的日誌:
是不是感覺和IDEA開發java一樣呢?
通過以上的方式,我們就可以非常方便的書寫redis lua,同時進行調試了。
切記,當redis lua書寫完畢,需要將如下的代碼段摘掉,然後此lua腳本就可以加載到redis服務器中了:
local redis = require ‘redis‘ local host = "192.168.155.126" local port = 6379 client = redis.connect(host, port) redis.call = function(cmd, ...) return assert(loadstring(‘return client:‘.. string.lower(cmd) ..‘(...)‘))(...) end
參考:Windows下lua+redis調試環境搭建
像調試java一樣來調試Redis lua