• 用lua+redis实现一个简单的计数器功能 (二)


    环境已经搭建完毕 传送门

    • 计数方案

      就目前来看nginx是最快的服务

      我在设计方案时选择信任redis作为存储库,不做穿透处理,由于目前redis集群方案还不成熟,只在这里做了主备方案。想做集群方案的人可以考虑使用twemproxy

      --如采用twemproxy 集群方案 不要选择信任redis集群,最好有穿透机制 一旦某机器当机,恢复会很麻烦  

    • 程序部分

    为方便管理lua文件,修改nginx.conf并重启

    lua_package_path '/var/www/lib/?.lua'; 
    lua_package_cpath '/usr/local/nginx/so/?.so'; #加载动态库
    init_by_lua_file '/usr/local/nginx/lua/init.lua';#将配置文件加载到nginx内存中
    lua_shared_dict config 45m;//配置内存大小
    include site/*.conf;

    新建site/lua.conf

    server {
            listen       80;
            server_name  count.xxxxxx.com;
    
            location ^~/user_group_praise/ {
                            access_log off;
                            lua_code_cache off;
                            content_by_lua_file /usr/local/nginx/lua/count.lua;
            }
    }

    init.lua代码让配置文件常驻内存

    local cjson = require "cjson";
    
    local config = ngx.shared.config;
    
    local file = io.open("/usr/local/nginx/lua/count.cjson", "r");
    local content = cjson.decode(file:read("*all"));
    file:close();
    
    for name, value in pairs(content) do
        config:set(name, cjson.encode(value));
    end

     count.cjson

    {
        "user_group_praise": {
            "redis_host": "127.0.0.1",
            "redis_port": 6379,
            "cv_key": "user_praise",
            "key": [
                "uid"
            ],
            "count_name": "用户直通赞数"
        }
    }

    count.lua代码

    ngx.header.content_type = "text/plain;charset=utf-8"
    
    local request_method = ngx.var.request_method
    local args = nil
    if "GET" == request_method then
            args = ngx.req.get_uri_args()
    elseif "POST" == request_method then
            ngx.req.read_body()
            args = ngx.req.get_post_args()
    end
    
    
    
    local uri = ngx.var.uri;
    uri = string.sub(uri,2,#uri);
    local uripos = string.find(uri , '/');
    if(uripos == null) then
            ngx.say('{"errorCode":500,"errorMsg":"'..conf_tab['count_name']..' 参数错误}');
            ngx.exit(200);
    
    end
    local type = string.sub(uri , 1 ,uripos-1);
    local functionname = string.sub(uri , uripos+1 ,#uri);
    
    
    local cjson = require "cjson";
    local config = ngx.shared.config;
    
    local conf_tab = config:get(type);
    if(conf_tab == null) then
            ngx.say('{"errorCode":500,"errorMsg":"'..conf_tab['count_name']..' 无此计数类型}');
            ngx.exit(200);
    end
    conf_tab = cjson.decode(conf_tab);
    
    local param_key_all = '';
    --检测参数
    if(functionname  ~= 'get') then
    
        param_key_all = param_key_all..conf_tab['cv_key'];
    
        for key, val in pairs(conf_tab['key']) do
            if(args[val] == null) then
                ngx.say('{"errorCode":500,"errorMsg":"'..conf_tab['count_name']..' 参数错误}');
                ngx.exit(200);
            end
            param_key_all = param_key_all..':'..args[val];
        end
    
    else
        if(args['json'] == null) then
            ngx.say('{"errorCode":500,"errorMsg":"'..conf_tab['count_name']..' 参数错误}');
            ngx.exit(200);
        end
        local param_tab = cjson.decode(args['json']);
        if(param_tab == null) then
            ngx.say('{"errorCode":500,"errorMsg":"'..conf_tab['count_name']..' 参数错误}');
            ngx.exit(200);
        end
    
        for key, val in pairs(param_tab) do
            param_key_all = param_key_all..','.."'"..conf_tab['cv_key'];
    
            for i=1,#conf_tab['key'],1 do
                if(val[conf_tab['key'][i]] == null) then
                    ngx.say('{"errorCode":500,"errorMsg":"'..conf_tab['count_name']..' 参数错误}');
                    ngx.exit(200);
                end
                param_key_all = param_key_all..':'..val[conf_tab['key'][i]];
            end
            param_key_all = param_key_all.."'";
        end
        param_key_all = string.sub(param_key_all,2,#param_key_all);
    
    end
    local redis = require("resty.redis");
    local red = redis:new();
    red:set_timeout(1000); -- 1 sec
    local ok, err = red:connect(conf_tab['redis_host'] , conf_tab['redis_port'] );
    if not ok then
        ngx.say('{"errorCode":500,"errorMsg":"'..conf_tab['count_name']..' REDIS服务器连接错误}')
        ngx.exit(200);
    end
    
    if(functionname == 'get') then
      local cvval = red:eval("return redis.call('mget',"..param_key_all..")",0);
      local results = {};
      results['data'] = cvval;
      results['errorCode'] = 0;
      results['errorMsg'] = 'ok';
    
      ngx.say(cjson.encode(results));
    elseif(functionname == 'inc') then
      cnum=red:incrby(param_key_all,1)
      ngx.say('{"errorCode":0,"errorMsg":"ok","data":'..cnum..'}')
    elseif(functionname == 'dec') then
      cnum=red:incrby(param_key_all,-1);
      ngx.say('{"errorCode":0,"errorMsg":"ok","data":'..cnum..'}')
    elseif(functionname == 'clear') then
      cnum=red:set(param_key_all,0);
      ngx.say('{"errorCode":0,"errorMsg":"ok","data":0}')
    else
       ngx.say('参数错误');
    
    end
    red:set_keepalive(0, 100);
    View Code
  • 相关阅读:
    Java接口自动化测试实战001----get、post方法实现与封装
    临近年关,两个磁盘占满引起的服务下线
    Abp小试牛刀之 图片上传
    Abp vNext异常处理的缺陷/改造方案
    Oh my God, Swagger API文档竟然可以这样写?
    【C#】DockPanelSuite 中 DockState.Document 状态下子窗体控件不显示的解决方案
    环境系列——cygwin启动flink
    环境系列——window10环境下编译Flink源码编译
    弱肉强食——《哆啦A梦:大雄的新恐龙》观后感
    bilibili插件推荐
  • 原文地址:https://www.cnblogs.com/turnswing/p/3554313.html
Copyright © 2020-2023  润新知