1. 程式人生 > >Redis指令碼Lua實現訪問控制頻率

Redis指令碼Lua實現訪問控制頻率

Redis 指令碼功能可以自定義新的命令,並且也是原子執行。
本篇和上一篇是相對應的。

一、簡單介紹下指令碼:

redis2.6推出指令碼功能,允許開發者使用 Lua語言編寫指令碼傳到Redis中執行,在Lua指令碼中可以呼叫大部分redis命令。

  • 使用指令碼優點:
    • 減少網路開銷:執行一次指令碼只需要傳送一次請求,減少網路往返時延。如果不使用指令碼,可能多個命令要傳送多個請求,還會出現競態情況。
    • 原子操作:Redis會將指令碼作為一個整體執行,中間不會被其他事務插入。編寫指令碼過程中無須考慮競態條件,也無須使用事務。事務可以完成的所有功能都可以通過指令碼實現。
    • 複用:客戶端傳送的指令碼會永久儲存在Redis 中,意味著其他客戶端可以複用這段指令碼。

二、使用指令碼實現訪問頻率限制,

  • 方案一:
Lua程式碼如下:
    -- Lua 使用 redis.call()呼叫redis命令
    local times = redis.call('incr', KEYS[1])

    if times == 1 then
        -- KEYS[1] 鍵剛剛建立,所以為其設定生存時間
        redis.call('expire', KEYS[1], ARGV[1])
    end 
    if times > tonumber(ARGV[2]) then   -- ARGV[2]為字串,需要轉為number
return 0 end return 1

執行指令碼:
$ redis-cli –eval /path/to/ratelimiting.lua rate.limiting:127.0.0.1 , 10 3

引數說明:
–eval:告訴redis-cli 讀取並執行後面的Lua指令碼。
/path/to/ratelimiting.lua : 檔案位置
rate.limiting:userId 要操作的key,在指令碼中用 KEYS[1]獲取
10 3 :兩個引數,在指令碼中用 ARGV[1]和ARGV[2] 獲取
注意:”,” 兩邊的空格不能省。

  • 方案二:
Lua程式碼如下:
    local limitLen = redis.call('llen', KEYS[1])
    if limitLen < tonumber(ARGV[2]) then
        redis.call('lpush', KEYS[1], os.time())
    else 
        local times = redis.call('lindex', KEYS[1], -1)
        if os.time() - times < ARGV[1] then
            return 0
        else 
            redis.call('lpush', KEYS[1], os.time())
            redis.call('ltrim', KEYS[1], 0, ARGV[2])
        end
    end 
    return 1

執行指令碼:
$ redis-cli –eval /path/to/ratelimiting.lua rate.limiting:127.0.0.1 , 10 3

rate.limiting:127.0.0.1 這個key 每10 秒最多訪問3次

如有錯誤,請留言指出。