環境已經搭建完畢 傳送門
- 計數方案
就目前來看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);
