高併發的系統中,redis的使用是很是頻繁的,而lua腳本則更是錦上添花。由於lua腳本自己執行的時候是一個事務性的操做,不會摻雜其餘外部的命令,因此不少關鍵的系統節點都會用redis+lua來實現一致性的操做請求。可是在實際開發過程當中,因爲redis lua腳本調試難的問題,致使大量的時間耗費在了這上面。若是有什麼方案可以讓咱們像利用IDEA調試java同樣簡便去調試redis lua腳本,那該是很幸福的事兒了。java
經過不斷的尋找,終於也找到了這種方式,下面就整體的來介紹一下。python
1. 下載ZeroBraneStudio,解壓到本地環境,而後找到解釋器路徑,好比我本機是D:\soft\pkulchenko-ZeroBraneStudio-7a8027e\bin\lua.exe,那麼咱們就能夠經過以下的cmd命令,將D:\soft\pkulchenko-ZeroBraneStudio-7a8027e\bin\添加到Path環境變量中便可。cmd命令以下:nginx
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安裝便可。git
3. 安裝redis及調試相關的類庫。觸類旁通,既然能安裝redis相關的,那麼也能安裝nginx相關的,因此咱們也能夠利用此方法來搞定nginx lua開發:程序員
luarocks install remdebuggithub
luarocks install prtr-dumpredis
luarocks install redis-luasql
4. 打開ZeroBraneStudio,創建lua腳本,開始進行調試吧,具體步驟以下:windows
首先,在lua腳本中,加入下面這段代碼,以便於讓lua腳本支持調試:bash
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
複製代碼
歡迎工做一到五年的Java工程師朋友們加入Java程序員開發: 854393687 羣內提供免費的Java架構學習資料(裏面有高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用本身每一分每一秒的時間來學習提高本身,不要再用"沒有時間「來掩飾本身思想上的懶惰!趁年輕,使勁拼,給將來的本身一個交代!