国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

lua腳本實(shí)現(xiàn)Redis令牌桶限流

這篇具有很好參考價(jià)值的文章主要介紹了lua腳本實(shí)現(xiàn)Redis令牌桶限流。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

背景

令牌桶限流是一種常見的流量控制算法,用于控制系統(tǒng)的請求處理速率,防止系統(tǒng)過載。在令牌桶限流算法中,可以將請求看作是令牌,而令牌桶則表示系統(tǒng)的處理能力。系統(tǒng)在處理請求時(shí),首先需要從令牌桶中獲取令牌,如果令牌桶中沒有足夠的令牌,就需要等待一定時(shí)間,直到令牌桶中有足夠的令牌。
具體來說,令牌桶限流算法可以通過以下方式實(shí)現(xiàn):
1.系統(tǒng)維護(hù)一個(gè)固定容量的令牌桶,每秒鐘會(huì)向桶中添加一定數(shù)量的令牌,直到桶的容量達(dá)到上限。
2.每次請求來臨時(shí),需要先從令牌桶中獲取令牌,如果桶中有足夠的令牌,則請求被允許通過,并從桶中移除一個(gè)令牌;如果桶中的令牌數(shù)量不足,則請求被拒絕。具體來說,令牌桶算法會(huì)維護(hù)一個(gè)令牌桶,其中包含一定數(shù)量的令牌,每個(gè)令牌代表一個(gè)可以執(zhí)行操作的許可。在每個(gè)時(shí)間段內(nèi),如果有令牌可用,就可以執(zhí)行一個(gè)操作,并將令牌桶中的令牌數(shù)量減少一。如果沒有令牌可用,就不能執(zhí)行操作,需要等待一定時(shí)間,直到令牌桶中有足夠的令牌。
3.由于令牌桶的容量是有限的,因此當(dāng)桶中的令牌數(shù)量達(dá)到上限時(shí),新的令牌會(huì)被丟棄,從而限制了請求的處理速率。
令牌桶限流算法可以在多種場景中進(jìn)行流量控制,例如 Web 應(yīng)用程序、消息隊(duì)列、數(shù)據(jù)庫等。在 Web 應(yīng)用程序中,可以通過令牌桶限流算法控制 API 的訪問速率,防止 API 被惡意攻擊或者過載。在消息隊(duì)列中,可以通過令牌桶限流算法控制消息的生產(chǎn)和消費(fèi)速率,防止消息堆積和系統(tǒng)崩潰。在數(shù)據(jù)庫中,可以通過令牌桶限流算法控制查詢和寫入操作的速率,防止數(shù)據(jù)庫過載和響應(yīng)時(shí)間過長。

lua腳本實(shí)現(xiàn)令牌桶算法

Lua 腳本可以用來實(shí)現(xiàn) Redis 的令牌桶限流:
1.定義 Redis 數(shù)據(jù)結(jié)構(gòu)
使用 Redis 的 Hash 數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)當(dāng)前令牌桶的狀態(tài)。在 Hash 中,rate 表示速率(每秒生成的令牌數(shù)),capacity 表示桶的容量(最多可以同時(shí)存儲(chǔ)的令牌數(shù)),tokens 表示當(dāng)前桶中的令牌數(shù)量,timestamp 表示上次更新令牌數(shù)量的時(shí)間戳。示例代碼:

HSET rdb:token_bucket rate 10 capacity 100 tokens 100 timestamp 0

2.編寫 Lua 腳本
編寫 Lua 腳本來實(shí)現(xiàn)限流邏輯。在腳本中,首先讀取當(dāng)前時(shí)間戳和桶的狀態(tài),計(jì)算出從上次更新時(shí)間戳到當(dāng)前時(shí)間應(yīng)該生成的令牌數(shù)量。然后,將當(dāng)前桶中的令牌數(shù)量和應(yīng)該生成的令牌數(shù)量相加,得到當(dāng)前桶中的令牌數(shù)量。如果當(dāng)前桶中的令牌數(shù)量超過了桶的容量,將其限制為桶的容量。
然后,判斷當(dāng)前桶中的令牌數(shù)量是否足夠執(zhí)行操作。如果令牌數(shù)量足夠,將當(dāng)前桶中的令牌數(shù)量減去操作所需的令牌數(shù)量,并更新桶的狀態(tài)。如果令牌數(shù)量不足,則返回限流的錯(cuò)誤信息。
示例代碼:

-- 讀取桶的狀態(tài)
local rate = tonumber(redis.call('HGET', KEYS[1], 'rate'))
local capacity = tonumber(redis.call('HGET', KEYS[1], 'capacity'))
local tokens = tonumber(redis.call('HGET', KEYS[1], 'tokens'))
local timestamp = tonumber(redis.call('HGET', KEYS[1], 'timestamp'))

-- 計(jì)算應(yīng)該生成的令牌數(shù)量
local now = redis.call('TIME')
local elapsed = now[1] - timestamp
local generated = math.floor(elapsed * rate)

-- 更新令牌數(shù)量并限制桶的容量
tokens = math.min(capacity, tokens + generated)

-- 執(zhí)行操作
local required = tonumber(ARGV[1])
if tokens >= required then
    tokens = tokens - required
    redis.call('HSET', KEYS[1], 'tokens', tokens)
    redis.call('HSET', KEYS[1], 'timestamp', now[1])
    return 1
else
    return 0
end

3.在應(yīng)用程序中調(diào)用 Lua 腳本
在應(yīng)用程序中,使用 Redis 的 EVAL 命令來調(diào)用 Lua 腳本。示例代碼:

@Component
public class TokenBucketLimiter {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    public boolean tryAcquire(String key, int tokens) {
        List<String> keys = Arrays.asList(key);
        List<String> args = Arrays.asList(Integer.toString(tokens));
        Long result = redisTemplate.execute(new DefaultRedisScript<>(
                "local rate = tonumber(redis.call('HGET', KEYS[1], 'rate')) " +
                        "local capacity = tonumber(redis.call('HGET', KEYS[1], 'capacity')) " +
                        "local tokens = tonumber(redis.call('HGET', KEYS[1], 'tokens')) " +
                        "local timestamp = tonumber(redis.call('HGET', KEYS[1], 'timestamp')) " +
                        "local now = redis.call('TIME') " +
                        "local elapsed = now[1] - timestamp " +
                        "local generated = math.floor(elapsed * rate) " +
                        "tokens = math.min(capacity, tokens + generated) " +
                        "if tokens >= tonumber(ARGV[1]) then " +
                        "    tokens = tokens - tonumber(ARGV[1]) " +
                        "    redis.call('HSET', KEYS[1], 'tokens', tokens) " +
                        "    redis.call('HSET', KEYS[1], 'timestamp', now[1]) " +
                        "    return 1 " +
                        "else " +
                        "    return 0 " +
                        "end",
                Long.class), keys, args);
        return result != null && result == 1L;
    }
}

或者如下腳本:文章來源地址http://www.zghlxwxcb.cn/news/detail-621465.html

-- 返回碼 1:通過限流 0:不通過
-- rate ARGV[1] 每秒填充速率
-- now  ARGV[2] 當(dāng)前時(shí)間
-- capacity ARGV[3] 令牌桶最大數(shù)量
-- request ARGV[4] 需要令牌數(shù)量
local SUCCESS = "1"
local FAIL = "0"
local rate = tonumber(ARGV[1]) -- replenishRate 令令牌桶填充平均速率
local capacity = tonumber(ARGV[2]) -- burstCapacity 令牌桶上限
local now = tonumber(ARGV[3]) -- 機(jī)器傳入的當(dāng)前時(shí)間 秒
local requested = tonumber(ARGV[4]) -- 消耗令牌數(shù)量,默認(rèn)取1

local fill_time = capacity/rate   -- 計(jì)算令牌桶填充滿令牌需要多久時(shí)間
local ttl = math.floor(fill_time*2) -- *2 保證時(shí)間充足

local result = SUCCESS;




-- ttl 防止小于0
if ttl < 1 then
    ttl = 10
end


-- 1、獲取桶內(nèi)令牌剩余數(shù)量
local last_tokens = tonumber(redis.call("get", KEYS[1]))
-- 獲得令牌桶剩余令牌數(shù)
if last_tokens == nil then -- 第一次時(shí),沒有數(shù)值,所以桶時(shí)滿的
    last_tokens = capacity
end

-- 2、獲取上次更新時(shí)間
local last_refreshed = tonumber(redis.call("get", KEYS[2]))
-- 令牌桶最后填充令牌時(shí)間
if last_refreshed == nil then
    last_refreshed = 0
end

-- 3、本次驗(yàn)證和上次更新時(shí)間的間隔
local delta = math.max(0, now-last_refreshed)
-- 填充令牌,計(jì)算新的令牌桶剩余令牌數(shù) 填充不超過令牌桶令牌上限。
local filled_tokens = math.min(capacity, last_tokens+(delta*rate))

-- 4、判斷令牌數(shù)量是否足夠
local allowed = filled_tokens >= requested
local new_tokens = filled_tokens
local allowed_num = "0"
if allowed then
    -- 若成功,令牌桶剩余令牌數(shù)(new_tokens) 減消耗令牌數(shù)( requested ),并設(shè)置獲取成功( allowed_num = 1 ) 。
    new_tokens = filled_tokens - requested
    allowed_num = SUCCESS
end

-- 5、設(shè)置令牌桶剩余令牌數(shù)( new_tokens ) ,令牌桶最后填充令牌時(shí)間(now) ttl是超時(shí)時(shí)間
redis.call("setex", KEYS[1], ttl, new_tokens)
redis.call("setex", KEYS[2], ttl, now)

if not allowed then
    return FAIL
end

return SUCCESS




到了這里,關(guān)于lua腳本實(shí)現(xiàn)Redis令牌桶限流的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 68. redis計(jì)數(shù)與限流中incr+expire的坑以及解決辦法(Lua+TTL)

    68. redis計(jì)數(shù)與限流中incr+expire的坑以及解決辦法(Lua+TTL)

    在日常工作中,經(jīng)常會(huì)遇到對某種操作進(jìn)行頻次控制或者統(tǒng)計(jì)次數(shù)的需求,此時(shí)常用的做法是采用 redis 的 incr 來遞增,記錄訪問次數(shù), 以及 expire 來設(shè)置失效時(shí)間。本文將以一個(gè)實(shí)際的例子來說明 incr 存在的一個(gè)\\\"坑\\\",以及給出解決方案。 如: 26.redis實(shí)現(xiàn)日限流、周限流(含黑

    2024年01月21日
    瀏覽(15)
  • 【實(shí)戰(zhàn)】使用Lua腳本怎么清理redis中的數(shù)據(jù)【實(shí)戰(zhàn)】使用Lua腳本怎么清理redis中的數(shù)據(jù)

    首先我們通過hiredis 向redis 中寫入了數(shù)據(jù),這里我們主要以測試為目的,所以,Key 值設(shè)定為毫秒級(jí)時(shí)間戳。 但是當(dāng)我們測試完成之后,需要驗(yàn)證實(shí)際情況,這里我們直接使用redis-cli 登錄數(shù)據(jù)庫看看。 本次測試完成,接下來要結(jié)合業(yè)務(wù)開始測試,需要清理數(shù)據(jù)庫,但是一條一

    2024年02月13日
    瀏覽(20)
  • Redis之Lua腳本

    Redis之Lua腳本

    目錄 Lua腳本 編寫Lua腳本 ?springboot整合redis使用lua Lua腳本 ? ? ? ?Redis在2.6推出了腳本功能,允許開發(fā)者使用Lua語言編寫腳本傳到Redis中執(zhí)行。使用腳本的好處如下: 1. 減少網(wǎng)絡(luò)開銷:本來5次網(wǎng)絡(luò)請求的操作,可以用一個(gè)請求完成,原先5次請求的邏輯放在redis服務(wù)器上完成。使

    2024年01月23日
    瀏覽(21)
  • Redis入門 - Lua腳本

    原文首更地址,閱讀效果更佳! Redis入門 - Lua腳本 | CoderMast編程桅桿 https://www.codermast.com/database/redis/redis-scription.html Redis 腳本使用 Lua 解釋器來執(zhí)行腳本。 Redis 2.6 版本通過內(nèi)嵌支持 Lua 環(huán)境。執(zhí)行腳本的常用命令為 EVAL。 Eval 命令的基本語法如下: EVAL script numkeys key [key ...]

    2024年02月09日
    瀏覽(27)
  • 使用lua腳本操作redis

    使用lua腳本操作redis

    redis中實(shí)現(xiàn)事務(wù)有兩種方法: 1.WATCH監(jiān)視鍵的變動(dòng),然后MULTI開始事務(wù),EXEC提交事務(wù) WATCH key [key…]:監(jiān)視一個(gè)或多個(gè)鍵,如果在事務(wù)執(zhí)行之前被修改,則事務(wù)被打斷。 MULTI:標(biāo)記一個(gè)事務(wù)的開始。 EXEC:執(zhí)行事務(wù)中的所有命令。 DISCARD:取消一個(gè)事務(wù),放棄執(zhí)行事務(wù)中的所有命

    2024年02月16日
    瀏覽(15)
  • Redis之Lua腳本講解

    當(dāng)涉及 Lua 編程時(shí),以下是對前述12個(gè)關(guān)鍵概念的詳細(xì)說明,附帶Lua代碼示例以幫助更深入了解這門編程語言 1.1.1 注釋 注釋在 Lua 中用于添加說明和注解。單行注釋以 -- 開始,多行注釋則使用 --[[ ... ]] 。 1.1.2 變量 變量在 Lua 中無需顯式聲明類型。使用 local 創(chuàng)建局部變

    2024年02月08日
    瀏覽(21)
  • 【Redis】Redis 的學(xué)習(xí)教程(十二)之在 Redis使用 lua 腳本

    lua 菜鳥教程:https://www.runoob.com/lua/lua-tutorial.html 在 Redis 使用 lua 腳本的好處: 減少網(wǎng)絡(luò)開銷 ??梢詫⒍鄠€(gè)請求通過腳本的形式一次發(fā)送,減少網(wǎng)絡(luò)時(shí)延及開銷 原子性操作 。Redis會(huì)將整個(gè)腳本作為一個(gè)整體執(zhí)行,中間不會(huì)被其他請求插入。因此在腳本運(yùn)行過程中無需擔(dān)心會(huì)出

    2024年02月07日
    瀏覽(23)
  • Springboot+Redis執(zhí)行l(wèi)ua腳本

    ????????隨著Redis數(shù)據(jù)庫的廣泛應(yīng)用,它在服務(wù)器端應(yīng)用程序中的作用越來越重要。Redis具有快速讀寫、數(shù)據(jù)持久化、發(fā)布訂閱、事務(wù)處理等諸多特性,而這些特性使得它在處理高并發(fā)、實(shí)時(shí)數(shù)據(jù)操作等方面表現(xiàn)出色。然而,單純使用Redis還不足以滿足一些復(fù)雜業(yè)務(wù)邏輯的需

    2024年02月09日
    瀏覽(23)
  • Redis命令行使用Lua腳本

    Lua腳本在Redis中的使用非常有用,它允許你在Redis服務(wù)器上執(zhí)行自定義腳本,可以用于復(fù)雜的數(shù)據(jù)處理、原子性操作和執(zhí)行多個(gè)Redis命令。以下是Lua腳本在Redis中的基本使用詳細(xì)講解: 運(yùn)行Lua腳本: 在Redis中,你可以使用 EVAL 或 EVALSHA 命令來運(yùn)行Lua腳本。 EVAL 用于執(zhí)行未經(jīng)緩存

    2024年02月07日
    瀏覽(15)
  • 【Redis】5、Redis 的分布式鎖、Lua 腳本保證 Redis 命令的原子性

    【Redis】5、Redis 的分布式鎖、Lua 腳本保證 Redis 命令的原子性

    ?? 分布式鎖:滿足分布式系統(tǒng)或集群模式下 多進(jìn)程可見 并且 互斥的 鎖 ?? 分布式鎖的核心是實(shí)現(xiàn)多進(jìn)程之間鎖的互斥 ,而滿足這一點(diǎn)的方式有很多,常見的有三種: ??鎖獲取了,還沒有來得及設(shè)置過期時(shí)間服務(wù)器就宕機(jī)了 ??保證 setnx(獲取鎖)和 expire 設(shè)置過期時(shí)間兩

    2024年02月15日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包