All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.dengchen2020.ratelimiter.redis.RedisRateLimiter Maven / Gradle / Ivy

There is a newer version: 0.0.28
Show newest version
package io.github.dengchen2020.ratelimiter.redis;

import io.github.dengchen2020.ratelimiter.RateLimiter;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;

import java.time.Duration;
import java.util.Collections;

/**
 * 基于Redis实现的分布式限流实现
 * @author dengchen
 * @since 2024/8/3
 */
public class RedisRateLimiter implements RateLimiter {

    private final String seconds;

    private final StringRedisTemplate redisTemplate;

    private static final String RATE_LIMIT_PREFIX = "dc:rate_limit:";

    RedisScript rateLimitScript = new DefaultRedisScript<>(
            String.format(""" 
                    -- 限流Key
                    local rateLimitKey = "%s" .. ARGV[1]
                    local rateLimitNum = tonumber(ARGV[2])
                    local rateLimitSecond = tonumber(ARGV[3])
                    local rateLimitValue = redis.call("GET", rateLimitKey)
                    if rateLimitValue then
                        local limitNum = tonumber(rateLimitValue);
                        if limitNum > rateLimitNum then
                            return limitNum
                        else
                            return redis.call("INCR", rateLimitKey)
                        end
                    else
                        redis.call("SET", rateLimitKey, "1", "EX", rateLimitSecond)
                        return 1
                    end
                    """, RATE_LIMIT_PREFIX),
            Long.class
    );

    /**
     * 分布式限流实例化
     * @param duration 限流时间
     * @param redisTemplate {@link StringRedisTemplate}
     *
     */
    public RedisRateLimiter(Duration duration, StringRedisTemplate redisTemplate) {
        this.seconds = String.valueOf(duration.toSeconds());
        this.redisTemplate = redisTemplate;
    }

    /**
     * 是否被限制
     *
     * @param limitKey 限制标识符
     * @param limitNum 限制的次数
     * @return true:被限制 false:未被限制
     */
    @Override
    public boolean limit(String limitKey, int limitNum) {
        Long num = redisTemplate.execute(rateLimitScript, Collections.emptyList(), limitKey, String.valueOf(limitNum), seconds);
        if (num == null) return false;
        return num > limitNum;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy