Redis中使用Lua指令碼的開發思路

來源:互聯網
上載者:User

Redis中使用Lua指令碼的開發思路

Redis提供了通過eval命令來執行Lua指令碼。下面通過幾個小例子來講述如何在Redis服務端執行Lua指令碼。

1. 執行Lua指令碼的幾個命令如下:

命令格式 說明 對應Jedis用戶端Jedis對象的方法之一(有更多重載方法)
EVAL script numkeys key [key ...] arg [arg ...] 執行Lua指令碼

 

public Object eval(String script, int keyCount, String... params)

EVALSHA sha1 numkeys key [key ...] arg [arg ...] 根據給定的 sha1 校正碼,對緩衝在伺服器中的指令碼進行求值 public Object evalsha(String sha1, int keyCount, String... params)
SCRIPT LOAD script 將給定的指令碼緩衝,不執行,並返回sha1校正值 public String scriptLoad(String script)
SCRIPT EXISTS sha1 [sha1 ...] 給定一個或多個指令碼的 SHA1 校正和,返回一個包含 0 和 1 的列表,表示校正和所指定的指令碼是否已經被儲存在緩衝當中 public List<Boolean> scriptExists(String... sha1) 
SCRIPT FLUSH  清除所有 Lua 指令碼緩衝  
SCRIPT KILL 殺死當前正在啟動並執行 Lua 指令碼,若且唯若這個指令碼沒有執行過任何寫操作時,這個命令才生效(如果已經執行了寫操作,則需要通過shutdown nosave命令來處理)

2.通過redis-cli用戶端執行Lua指令碼
   
redis-cli --eval myscript.lua key1 key2 , arg1 arg2 arg3

需要注意的是用逗號來分割key和參數,這裡與在互動式模式下執行evel命令有所不同。

3.實際案例

  情境一:對一個特定請求1秒鐘只允許訪問10次,當符合請求訪問條件時,返回True,否則返回False。
  Java用戶端操作Redis服務,實現代碼如下:
   
/**
    * 存取控制
    * 
    * 1秒內最多可訪問10次
    * 
    * @param key
    * @return
    */
    public boolean isAccess(String key) {
        String rkey = "acc:" + key;
        long value = jedis.incr(rkey);
        if (value == 1) {
            jedis.expire(rkey, 1);
            return true;
        } else {
            boolean rs = value <= 10;
            return rs;
        }
    }

INCR命令作為計數器,如果rkey存在,則增加1返回最終值,否則初始化值為0,然後加1。如上程式,如果訪問rkey不存在,則表示第一次請求,這時對其rkey設定到期時間為1秒,否則比較其值是否超過制定請求數的閥值10.
 
用Lua指令碼來完成這一操作:
 
--[[
Judge status 
KEYS[1]:key
ARGV[1]:request numbers
ARGV[2]:expires times seconds
--]]
 
local key, rqn, exp  = KEYS[1], ARGV[1], ARGV[2];
local value=redis.call("incr", key);
redis.log(redis.LOG_NOTICE, "incr "..key);
if(tonumber(value) == 1)then
  redis.call("expire", key,  exp);
  redis.log(redis.LOG_NOTICE, "expire "..key.." "..exp)
  return true;
else
  return tonumber(value) <= tonumber(rqn);
end

  通過Java用戶端代碼實現該功能存在一定缺陷,比如每1秒就需要操作1個incr和expire命令,並且該命令是由用戶端通過網路發起的,而使用Lua指令碼則既可以保證操作的原子性,又能使每次操作只需要一個key即可在伺服器端完成相應的判斷操作。可以通過SCRIPT LOAD的方式將指令碼緩衝到伺服器,通過sha1校正值+參數(Key,ARG)來執行,減輕網路傳輸,也對該功能做到較好的封裝。

情境二:指定模式key大量刪除
    redis目前提供的刪除命令del僅支援刪除指定數量的key,並不能通過指定模式key來進行刪除,比如:del *user 刪除以user結尾的key。
   
  在redis中提供了keys命令,該命令可以通過指定模式key來擷取key列表,下面通過keys和del命令組合實現一個指定模式key大量刪除的命令。

--[[
Pattern delete key
KEYS[1]:pattern
--]]
 
redis.log(redis.LOG_NOTICE, "call keys "..KEYS[1]);
 
local keys=redis.call("keys", KEYS[1]);
local count = 0;
if(keys and (table.maxn(keys) > 0)) then
    for index, key in ipairs(keys) do
        redis.log(redis.LOG_NOTICE, "del "..key);
        count = count +  redis.call("del", key);
    end
end
return count;

需要注意的是情境二可以作為一種思路,通過Lua指令碼組合redis內建命令來實現特定功能的命令。而這裡的模式key大量刪除並未一個好的命令,因為如果key的數量很大時,將會有比較嚴重的效能問題。redis預設限制Lua指令碼執行時間最大為5秒,如果超過5秒將繼續接受來自用戶端的請求,並簡單的返回BUSY結果。這時候則需要SCRIPT KILL或者SHUTDOWN NOSAVE命令做相應的處理。因此應該儘力保證指令碼的執行速度極快。

情境三:產生隨機數

對於Redis而且,指令碼執行在相同資料集,相同參數下執行寫命令具有一致性的。其不依賴與隱式的資料集,指令碼執行過程中不同執行時期的狀態變化,也不依賴外部I/O裝置的輸入。

要符合Redis服務執行的指令碼條件,需要注意的地方比較多,可以參見:                        http://redis.io/commands/eval

下面是實現隨機數列表的Lua指令碼:

--[[
Random lpush a list key-value
KEYS[1]:key name
ARGV[1]:ramdom seed value
ARGV[2]:add element count
--]]
 
math.randomseed(ARGV[1]);
for i=1, ARGV[2], 1 do
    redis.call("lpush", KEYS[1], math.random());
end
redis.log(redis.LOG_NOTICE, "lpush " .. KEYS[1]);
return true;

上述指令碼通過改變randomseed函數的參數來實現隨機數,如果兩次執行上述指令碼,ARGV[1]參數值相同,則產生的隨機數是相同的。

通過執行上述指令碼,記錄每次生產的值,然後刪除對應key,再次產生。
 

對比上述結果,在執行該指令碼時,隨機數的產生由seed參數(第一個參數)決定的。
  相同隨機數種子下產生的隨機數是相同的,如果再次執行指令碼,指定產生的隨機數個數n小於已經產生的隨機數個數m,則取已經產生的前n個,如果指定產生的隨機數個數n大於已經產生的隨機數個數m,則次數再產生(n-m)個隨機數,並固定下來。

 4.Redis中使用Lua指令碼總結
    Redis內建了Lua解譯器,這為操作Redis伺服器和資料提供了巨大的靈活性。
    文中幾個情境並不見得實際,有效,但並不能掩蓋Lua與Redis結合將為Redis的使用提供了更大的想象和操作空間。
    我們可以通過Lua來實現更多特定功能的命令;用Lua來封裝複雜了Redis操作的業務;計數,統計,分析,收集資料;實現業務操作事務控制等等。更多情境,還需在實際中不斷摸索和嘗試。

Ubuntu 14.04下Redis安裝及簡單測試

Redis叢集明細文檔

Ubuntu 12.10下安裝Redis(圖文詳解)+ Jedis串連Redis

Redis系列-安裝部署維護篇

CentOS 6.3安裝Redis

Redis安裝部署學習筆記

Redis設定檔redis.conf 詳解

Redis 的詳細介紹:請點這裡
Redis 的:請點這裡

本文永久更新連結地址:

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.