lua操作redis ,解php的序列化 (deal_json.lua)
local lua_list = {}
local buf, dtype, dataoffset, typeconvert, datalength, chars, readdata, i,key, value, keys, properties, otchars, otype, property,tableVIn
local _serialize_key, _read_chars, _read_until, _unknown_type,unserialize,vchars,tableTojson,vtype,stringlength,char,kchars,ktype
local EMPTY_ARRAY={}
local EMPTY_OBJECT={}
function _read_until(data, offset, stopchar)
local buf = {}
local char = string.sub(data, offset + 1, offset + 1)
local i = 2
while not (char == stopchar) do
if i + offset > string.len(data) then
error('Invalid')
end
table.insert(buf, char)
char = string.sub(data, offset + i, offset + i)
i = i + 1
end
return i - 2, table.concat(buf)
end
function _read_chars(data, offset, length)
local buf = {}, char
for i = 0, length -1 do
char = string.sub(data, offset + i, offset + i)
table.insert(buf, char)
end
return length, table.concat(buf)
end
-- php反序列化
function unserialize(data, offset)
offset = offset or 0
local buf, dtype, dataoffset, typeconvert, datalength, chars, readdata, i,key, value, keys, properties, otchars, otype, property
buf = {}
dtype = string.lower(string.sub(data, offset + 1, offset + 1))
dataoffset = offset + 2
typeconvert = function(x) return x end
datalength = 0
chars = datalength
if dtype == 'i' or dtype == 'd' then
typeconvert = function(x) return tonumber(x) end
chars, readdata = _read_until(data, dataoffset, ';')
dataoffset = dataoffset + chars + 1
elseif dtype == 'b' then
typeconvert = function(x) return tonumber(x) == 1 end
chars, readdata = _read_until(data, dataoffset, ';')
dataoffset = dataoffset + chars + 1
elseif dtype == 'n' then
readdata = nil
elseif dtype == 's' then
chars, stringlength = _read_until(data, dataoffset, ':')
dataoffset = dataoffset + chars + 2
chars, readdata = _read_chars(data, dataoffset + 1, tonumber(stringlength))
dataoffset = dataoffset + chars + 2
if not (chars == tonumber(stringlength)) then
error('String length mismatch')
end
elseif dtype == 'a' then
readdata = {}
chars, keys = _read_until(data, dataoffset, ':')
dataoffset = dataoffset + chars + 2
for i = 0, tonumber(keys) - 1 do
key, ktype, kchars = unserialize(data, dataoffset)
dataoffset = dataoffset + kchars
value, vtype, vchars = unserialize(data, dataoffset)
if vtype == 'a' then
vchars = vchars + 1
end
dataoffset = dataoffset + vchars
readdata[key] = value
end
elseif dtype == 'o' then
readdata = {}
chars, otchars = _read_until(data, dataoffset, ':')
dataoffset = dataoffset + chars + 2
otype = string.sub(data, dataoffset + 1, dataoffset + otchars)
dataoffset = dataoffset + otchars + 2
if otype == 'stdClass' then
chars, properties = _read_until(data, dataoffset, ':')
dataoffset = dataoffset + chars + 2
for i = 0, tonumber(properties) - 1 do
property, ktype, kchars = unserialize(data, dataoffset)
dataoffset = dataoffset + kchars
value, vtype, vchars = unserialize(data, dataoffset)
if vtype == 'a' then
vchars = vchars + 1
end
dataoffset = dataoffset + vchars
-- Set the list element
readdata[property] = value
end
else
_unknown_type(dtype)
end
else
_unknown_type(dtype)
end
return typeconvert(readdata), dtype, dataoffset - offset
end
-- 错误输出
function _unknown_type(type_)
error('Unknown / Unhandled data type (' .. type_ .. ')!', 2)
end
-- 表格数据判断
function tableVIn(tbl, value)
if tbl == nil then
return false
end
for k, v in pairs(tbl) do
if k == value then
return true
end
end
return false
end
local is_has,json_info,article_one
local key_nums = table.getn(KEYS)
-- return key_nums
-- 循环处理更多key
local article_list = {}
if next(KEYS) ~= nil then
for k, key in pairs(KEYS) do
local new_table = {}
local article_lua,sertab
local key_str = string.gsub(key,"article_","");
-- 获取值
article_lua = redis.call('get',key)
-- 进行序列化转换
sertab = unserialize(article_lua)
-- 判断是否创参数
if next(ARGV) ~= nil then
for k, agrv in pairs(ARGV) do
-- 进行表格判断数据
is_has = tableVIn(sertab,agrv)
if(is_has)
then
new_table[agrv] = sertab[agrv]
end
end
-- 格式转换
article_list[key_str] = new_table
article_one = new_table
else
-- 格式转换
article_list[key_str] = sertab
article_one = sertab
end
end
if(key_nums >1)
then
json_info =cjson.encode(article_list)
else
json_info =cjson.encode(article_one)
end
return json_info
else
return json_info
end
php 的代码操作逻辑,代码如下:
<?php
$redis = new Redis();
$redis_ok = $redis->pconnect('192.168.88.20', 6379, 1); //discover_tab_exposure_pv
$redis->select(0);
$data = array(''xxx"); //查询的redis key
$fields = array('_id','app_id','title');//查询redis返回的参数
$list = array_merge($data,$fields);
$nums_key = ‘xx’;查询的键参数
$script = file_get_contents(dirname(__FILE__)."/deal_json.lua");
$article_info = evalEx($redis,$script,$list,$nums_key);
/**
* eval扩展方法,结合了 eval、evalSha
*
* 优先使用 evalSha 尝试,失败则使用 eval 方法
* @param \Redis $redis
* @param string $script
* @param array $args
* @param int $num_keys
* @return mixed
*/
function evalEx($redis, $script, $args = null, $num_keys = null)
{
$result = $redis->eval($script, $args, $num_keys);
// var_dump($result);die;
// $article_info = $result ? @json_decode($result,true) : false;
// var_dump($article_info);die;
$sha1 = sha1($script);
// var_dump($sha1 );die;
$result = $redis->evalSha($sha1, $args, $num_keys);
var_dump($result);die;
if('NOSCRIPT No matching script. Please use EVAL.' === $redis->getLastError()){
var_dump($num_keys);
$result = $redis->eval($script, $args, $num_keys);
}
$article_info = $result ? @json_decode($result,true) : false;
return $article_info ? $article_info : false;
}
三 、对lua 脚本并发redis测试
redis-benchmark -h 127.0.0.1 -p 6379 -c 1000 -n 20000 EVALSHA "745694397cf9f36751f38ad3a433db72a8591321" 1 "article_5cde366a1bc8e0cf0e0000cf" "_id" "app_id" "title" "sim_content" "simhash_content" "top_video_info" "lev_1" "new_lev_1" "author" "new_app_id" "stat" "topic_info" "url" "addtime" "insert_time" "is_original"
三、以上是相关的代码,但php + lua + redis 有更好的原子性,但在性能方面不可恭维,下面是一些数据,当时为忘了截图,直接复制出来,经过测试:
1、php + lua + reidis ,处理php的序列化返回的数据
10000 requests completed in 86.22 seconds
500 parallel clients
3 bytes payload
keep alive: 1
115.98 requests per second
1、php + lua + reidis ,处理json返回的数据
10000 requests completed in 2.20 seconds
1000 parallel clients
3 bytes payload
keep alive: 1
4543.39 requests per second
1、php + reidis 返回 数据
10000 requests completed in 0.27 seconds
500 parallel clients
3 bytes payload
keep alive: 1
37453.18 requests per second
从上方的数据可看php + redis + lua 操作性能比较差,虽然可以降低流量,但无法达到高性能