zoukankan      html  css  js  c++  java
  • 像调试java一样来调试Redis lua

    高并发的系统中,redis的使用是非常频繁的,而lua脚本则更是锦上添花。因为lua脚本本身执行的时候是一个事务性的操作,不会掺杂其他外部的命令,所以很多关键的系统节点都会用redis+lua来实现一致性的操作请求。但是在实际开发过程中,由于redis lua脚本调试难的问题,导致大量的时间耗费在了这上面。如果有什么方案能够让我们像利用IDEA调试java一样简便去调试redis lua脚本,那该是很幸福的事儿了。

    通过不断的寻找,终于也找到了这种方式,下面就总体的来介绍一下。

    1. 下载ZeroBraneStudio,解压到本地环境,然后找到解释器路径,比如我本机是D:softpkulchenko-ZeroBraneStudio-7a8027einlua.exe,那么我们就可以通过如下的cmd命令,将D:softpkulchenko-ZeroBraneStudio-7a8027ein添加到Path环境变量中即可。cmd命令如下:

    set path=%path%;D:softpkulchenko-ZeroBraneStudio-7a8027ein;

    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方法来打印日志,看看日志部分是不是我们需要的值或者结果。

    最后,我们运行程序,开启调试模式,先点击想要调试的代码行,下断点:

    image

    然后点击下图图示的按钮,开始进行调试:

    image

    然后程序就会启动,开始调试,我们点击下图图示的按钮,就可以逐语句或者逐过程的进行了:

    image

    之后我们点击按钮几次,就可以走到我们的方法里面了,同时鼠标悬停到变量上面,就可以清楚的看到当前变量的值:

    image

    同时我们也可以在底部的窗口中添加监视变量来监视变量的内容:

    image

    在控制台,我们也可以实时看到通过print打印出来的日志:

    image

    是不是感觉和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调试环境搭建

  • 相关阅读:
    LeetCode 83. Remove Duplicates from Sorted List (从有序链表中去除重复项)
    LeetCode 21. Merge Two Sorted Lists (合并两个有序链表)
    LeetCode 720. Longest Word in Dictionary (字典里最长的单词)
    LeetCode 690. Employee Importance (职员的重要值)
    LeetCode 645. Set Mismatch (集合不匹配)
    LeetCode 500. Keyboard Row (键盘行)
    LeetCode 463. Island Perimeter (岛的周长)
    115.Distinct Subsequences
    55.Jump Game
    124.Binary Tree Maximum Path Sum
  • 原文地址:https://www.cnblogs.com/scy251147/p/9929062.html
Copyright © 2011-2022 走看看