1. 程式人生 > >像調試java一樣來調試Redis lua

像調試java一樣來調試Redis lua

nil htm tab splay 分享圖片 ash 其他 ace lse

高並發的系統中,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, ...) 
    return
assert(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