redis可以采用什么方式實現限流

redis可以采用什么方式實現限流

目的:

  • 實現訪問頻率限制

  • 實現訪問者 $ip 在一定的時間 $time 內只能訪問 $limit 次

(學習視頻分享:redis視頻教程

非腳本實現

private?boolean?accessLimit(String?ip,?int?limit,?int?time,?Jedis?jedis)?{  ????boolean?result?=?true;?String?key?=?"rate.limit:"?+?ip;?if?(jedis.exists(key))?{?long?afterValue?=?jedis.incr(key);?if?(afterValue?>?limit)?{?result?=?false;?}?}?else?{?Transaction?transaction?=?jedis.multi();?transaction.incr(key);?transaction.expire(key,?time);?transaction.exec();?}??return?result;?}

以上代碼有兩點缺陷

可能會出現競態條件: 解決方法是用?WATCH?監控?rate.limit:$IP?的變動, 但較為麻煩;以上代碼在不使用?pipeline?的情況下最多需要向redis請求5條指令, 傳輸過多.

Lua腳本實現

Redis 允許將 Lua 腳本傳到 Redis 服務器中執行, 腳本內可以調用大部分 Redis 命令, 且 Redis 保證腳本的原子性:

首先需要準備Lua代碼: script.lua

--  --?Created?by?IntelliJ?IDEA.  --?User:?jifang  --?Date:?16/8/24  --?Time:?下午6:11?--?local?key?=?"rate.limit:"?..?KEYS[1]?local?limit?=?tonumber(ARGV[1])?local?expire_time?=?ARGV[2]?local?is_exists?=?redis.call("EXISTS",?key)?if?is_exists?==?1?then?if?redis.call("INCR",?key)?>?limit?then?return?0?else?return?1?end?else?redis.call("SET",?key,?1)?redis.call("EXPIRE",?key,?expire_time)?return?1?end

Java

private?boolean?accessLimit(String?ip,?int?limit,?int?timeout,?Jedis?connection)?throws?IOException?{?List<string>?keys?=?Collections.singletonList(ip);?List<string>?argv?=?Arrays.asList(String.valueOf(limit),?String.valueOf(timeout));?return?1?==?(long)?connection.eval(loadScriptString("script.lua"),?keys,?argv);?}?//?加載Lua代碼?private?String?loadScriptString(String?fileName)?throws?IOException?{?Reader?reader?=?new?InputStreamReader(Client.class.getClassLoader().getResourceAsStream(fileName));?return?CharStreams.toString(reader);?}</string></string>

Lua 嵌入 Redis 優勢:?

減少網絡開銷: 不使用 Lua 的代碼需要向 Redis 發送多次請求, 而腳本只需一次即可, 減少網絡傳輸;原子操作: Redis 將整個腳本作為一個原子執行, 無需擔心并發, 也就無需事務;復用: 腳本會永久保存 Redis 中, 其他客戶端可繼續使用。

相關推薦:redis視頻教程

以上就是

? 版權聲明
THE END
喜歡就支持一下吧
點贊7 分享