Redis+Lua實現限流

分布式限流最關鍵的是要將限流服務做成原子化楞捂,而解決方案可以使使用redis+lua或者nginx+lua技術進行實現僵蛛,通過這兩種技術可以實現的高并發(fā)和高性能荞驴。
首先我們來使用redis+lua實現時間窗內某個接口的請求數限流琐谤,實現了該功能后可以改造為限流總并發(fā)/請求數和限制總資源數檐蚜。Lua本身就是一種編程語言魄懂,也可以使用它實現復雜的令牌桶或漏桶算法。
如下操作因是在一個lua腳本中(相當于原子操作)闯第,又因Redis是單線程模型市栗,因此是線程安全的。

相比Redis事務來說咳短,Lua腳本有以下優(yōu)點
減少網絡開銷: 不使用 Lua 的代碼需要向 Redis 發(fā)送多次請求, 而腳本只需一次即可, 減少網絡傳輸;
原子操作: Redis 將整個腳本作為一個原子執(zhí)行, 無需擔心并發(fā), 也就無需事務;
復用: 腳本會永久保存 Redis 中, 其他客戶端可繼續(xù)使用.

Lua腳本

local key = KEYS[1] --限流KEY(一秒一個)
local limit = tonumber(ARGV[1]) --限流大小
local current = tonumber(redis.call('get', key) or "0")
if current + 1 > limit then --如果超出限流大小
    return 0
else --請求數+1填帽,并設置2秒過期
    redis.call("INCRBY", key,"1")
    redis.call("expire", key,"2")
end
return 1

java代碼

import org.apache.commons.io.FileUtils;

import redis.clients.jedis.Jedis;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class RedisLimitRateWithLUA {

    public static void main(String[] args) {
        final CountDownLatch latch = new CountDownLatch(1);

        for (int i = 0; i < 7; i++) {
            new Thread(new Runnable() {
                public void run() {
                    try {
                        latch.await();
                        System.out.println("請求是否被執(zhí)行:"+accquire());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();

        }

        latch.countDown();
    }

    public static boolean accquire() throws IOException, URISyntaxException {
        Jedis jedis = new Jedis("127.0.0.1");
        File luaFile = new File(RedisLimitRateWithLUA.class.getResource("/").toURI().getPath() + "limit.lua");
        String luaScript = FileUtils.readFileToString(luaFile);

        String key = "ip:" + System.currentTimeMillis()/1000; // 當前秒
        String limit = "5"; // 最大限制
        List<String> keys = new ArrayList<String>();
        keys.add(key);
        List<String> args = new ArrayList<String>();
        args.add(limit);
        Long result = (Long)(jedis.eval(luaScript, keys, args)); // 執(zhí)行l(wèi)ua腳本,傳入參數
        return result == 1;
    }
}

運行結果

請求是否被執(zhí)行:true
請求是否被執(zhí)行:true
請求是否被執(zhí)行:false
請求是否被執(zhí)行:true
請求是否被執(zhí)行:true
請求是否被執(zhí)行:true
請求是否被執(zhí)行:false

從結果可看出只有5個請求成功執(zhí)行

IP限流Lua腳本

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

參考文章:http://jinnianshilongnian.iteye.com/blog/2305117

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末咙好,一起剝皮案震驚了整個濱河市篡腌,隨后出現的幾起案子,更是在濱河造成了極大的恐慌勾效,老刑警劉巖嘹悼,帶你破解...
    沈念sama閱讀 221,406評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異层宫,居然都是意外死亡杨伙,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 94,395評論 3 398
  • 文/潘曉璐 我一進店門萌腿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來限匣,“玉大人,你說我怎么就攤上這事毁菱∶姿溃” “怎么了?”我有些...
    開封第一講書人閱讀 167,815評論 0 360
  • 文/不壞的土叔 我叫張陵鼎俘,是天一觀的道長哲身。 經常有香客問我,道長贸伐,這世上最難降的妖魔是什么勘天? 我笑而不...
    開封第一講書人閱讀 59,537評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮捉邢,結果婚禮上脯丝,老公的妹妹穿的比我還像新娘。我一直安慰自己伏伐,他們只是感情好宠进,可當我...
    茶點故事閱讀 68,536評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著藐翎,像睡著了一般材蹬。 火紅的嫁衣襯著肌膚如雪实幕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,184評論 1 308
  • 那天堤器,我揣著相機與錄音昆庇,去河邊找鬼。 笑死闸溃,一個胖子當著我的面吹牛整吆,可吹牛的內容都是我干的。 我是一名探鬼主播辉川,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼表蝙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了乓旗?” 一聲冷哼從身側響起府蛇,我...
    開封第一講書人閱讀 39,668評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎寸齐,沒想到半個月后欲诺,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 46,212評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡渺鹦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,299評論 3 340
  • 正文 我和宋清朗相戀三年扰法,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片毅厚。...
    茶點故事閱讀 40,438評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡塞颁,死狀恐怖,靈堂內的尸體忽然破棺而出吸耿,到底是詐尸還是另有隱情祠锣,我是刑警寧澤,帶...
    沈念sama閱讀 36,128評論 5 349
  • 正文 年R本政府宣布咽安,位于F島的核電站伴网,受9級特大地震影響,放射性物質發(fā)生泄漏妆棒。R本人自食惡果不足惜澡腾,卻給世界環(huán)境...
    茶點故事閱讀 41,807評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望糕珊。 院中可真熱鬧动分,春花似錦、人聲如沸红选。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽喇肋。三九已至坟乾,卻和暖如春迹辐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背甚侣。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評論 1 272
  • 我被黑心中介騙來泰國打工右核, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人渺绒。 一個月前我還...
    沈念sama閱讀 48,827評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像菱鸥,于是被迫代替她去往敵國和親宗兼。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,446評論 2 359

推薦閱讀更多精彩內容