php +redis +lua 的原子性操作,同時lua解php的 序列化操作

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 操作性能比較差,雖然可以降低流量,但無法達到高性能

發佈了46 篇原創文章 · 獲贊 23 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章