朝阳博客

  • Article
  • Project
  • HTML+CSS
  • Bootstrap
  • JavaScript
  • jQuery
  • PHP
  • Java
  • Linux
  • MySQL
朝阳博客
一款专注于博客的响应式网站
  1. 首页
  2. Linux
  3. 正文

Redis 实现滑动窗口

2023年3月28日 321点热度 0人点赞 0条评论

1、前言

一般我们做在指定时间内只允许做 n 次都用,一个 key 设置过期时间 t 秒,然后在 key 过期时间内只需要做 n 次。然而这个思路有问题,最明显的就是跨时间段的问题。所以这个问题很显然用滑动窗口来做。

指定时间T内,只允许发生N次。我们可以将这个指定时间T,看成一个滑动时间窗口(定宽)。我们采用Redis的zset基本数据类型的score来圈出这个滑动时间窗口。在实际操作zset的过程中,我们只需要保留在这个滑动时间窗口以内的数据,其他的数据不处理即可。

  • 每个用户的行为采用一个zset存储,score为毫秒时间戳,value也使用毫秒时间戳(比UUID更加节省内存)
  • 只保留滑动窗口时间内的行为记录,如果zset为空,则移除zset,不再占用内存(节省内存)

2、代码

package com.example.demo.redis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Response;

import java.io.IOException;

/**
 * 
 *     通过zset实现滑动窗口算法限流
 * 
 *
 */
public class SimpleSlidingWindowByZSet {

    private Jedis jedis;

    public SimpleSlidingWindowByZSet(Jedis jedis) {
        this.jedis = jedis;
    }

    /**
     * 判断行为是否被允许
     *
     * @param userId        用户id
     * @param actionKey     行为key
     * @param period        限流周期
     * @param maxCount      最大请求次数(滑动窗口大小)
     * @return
     */
    public boolean isActionAllowed(String userId, String actionKey, int period, int maxCount) throws IOException {
        String key = this.key(userId, actionKey);
        long ts = System.currentTimeMillis();
        Pipeline pipe = jedis.pipelined();
        pipe.multi();

        // 每个用户一个 zset,这里是 user + key 组合
        pipe.zadd(key, ts, String.valueOf(ts));
        // 移除滑动窗口之外的数据
        pipe.zremrangeByScore(key, 0, ts - (period * 1000));
        // 获取窗口内的数量
        Response count = pipe.zcard(key);
        // 设置行为的过期时间,如果数据为冷数据,zset将会删除以此节省内存空间(不是必须,算是优化)
        pipe.expire(key, period);
        pipe.exec();
        pipe.close();
        return count.get() 
public class FirstTool {

    static JedisPool pool = null;

    static {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxIdle(8);
        config.setMaxTotal(18);
        pool = new JedisPool(config, "127.0.0.1", 6379, 2000);
    }

    public static void main(String[] args) throws Exception {
        Jedis jedis = pool.getResource();

        SimpleSlidingWindowByZSet slidingWindow = new SimpleSlidingWindowByZSet(jedis);
        for (int i = 1; i 
标签: 暂无
最后更新:2023年3月28日

aiyao

你要加油,你喜欢的人还没结婚。

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

COPYRIGHT © 2021 zhaoyangweb.com. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

冀ICP备2021020018号-1