Redis两种方式实现限流
阅读原文时间:2024年06月24日阅读:1
案例-实现访问频率限制: 实现访问者 $ip 在一定的时间 $time 内只能访问 $limit 次.
  • 非脚本实现

    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;

    }

  • 以上代码有两点缺陷 


  • 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 keys = Collections.singletonList(ip);
    List 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);
    }


  • Lua 嵌入 Redis 优势: 

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章