Рубрики
Uncategorized

PHP использует ограничение тока Lua + redis, режим счетчика, модель корзины токенов

Автор оригинала: David Wong.

Преимущества Lua Сокращение сетевых накладных расходов: код, который не использует Lua, должен отправлять несколько запросов в Redis, в то время как сценариям требуется только один раз, чтобы уменьшить передачу по сети; Атомарные операции: Redis выполняет весь сценарий как атом, не беспокоясь о параллелизме или транзакции. Повторное использование: Сценарий постоянно сохраняется в Redis и может использоваться другими клиентами.

Режим счетчика: Использование сценария Lua для завершения обработки за один раз для достижения атомарности, за счет увеличения числа, чтобы определить, нужно ли достигать предельного значения, чтобы вернуться к предельному значению, время истечения срока действия ключа должно быть чрезмерным диапазоном.

$lua = '
                local i = redis.call("INCR", KEYS[1]) 
                if i > 10 then
                    return "wait"
                else
                    if i == 1
                    then
                        redis.call("expire", KEYS[1], KEYS[2])
                    end
                    return redis.call("get", KEYS[3])
                end
            ';

Код запроса Laravel:

 Redis::eval($lua, 3,  sprintf(RedisKey::API_LIMIT, $key, $callService['service']), 60, $cache_key);

Режим корзины токенов Каждый запрос принимает токен в корзине и передает его, если он есть. В противном случае он возвращается и медленно помещает токен в корзину в соответствии с алгоритмом.

$lua = '
                local data = redis.call("get", KEYS[2])
                if data then
                
                    local dataJson = cjson.decode(data)
                    local newNum = math.min(KEYS[3], math.floor(((dataJson["limitVal"] - 1) + (KEYS[3]/KEYS[5]) * (KEYS[4] - dataJson["limitTime"]))))
                    
                    if newNum > 0 then
                    
                        local paramsJson = cjson.encode({limitVal=newNum,limitTime=KEYS[4]})
                        redis.call("set", KEYS[2], paramsJson)
                        return redis.call("get", KEYS[1])
                    
                    end
                     return "wait"
                end
                
                local paramsJson = cjson.encode({limitVal=KEYS[3],limitTime=KEYS[4]})
                redis.call("set", KEYS[2], paramsJson)
                return redis.call("get", KEYS[1])
            ';
            
            // 1. Lua script, 2 KEYS number, 3 lookup data key, 4 limit key, 5 bucket number, 6 timestamp, 7 expiration time
            Redis:: Eval (1,2,3,4,5,6,7 parameters);