用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

 

 

posted @ 2014-02-20 19:53  锁千秋  阅读(3384)  评论(0编辑  收藏  举报