时间窗口算法基于redis -zset 实现

阿里云1折优惠链接:https://www.aliyun.com/minisite/goods?userCode=8hemam4l

时间窗口算法

又名滑动时间算法,所谓的滑动时间算法指的是以当前时间为截止时间,往前取一定的时间,比如取1s的时间,在这1s时间内最大的访问数为1000。把这1秒分为1000格,每格是1毫秒。

滑动时间窗口如下图所示:

时间窗口算法基于redis -zset 实现_第1张图片

 

其中每一个小格子代表1ms,比如1s允许200次请求,那么就分成1000个小格。

如何实现?

借助Redis的有序集合ZSet来实现时间窗口算法限流,实现的过程是:

第一步:先使用ZSet的key存储限流的ID,score用来存储请求的时间。

第二步:每次有请求访问来了之后,先判断当前时间(以ms为单位如:System.currentTimeMillis())往前推1000ms的时间,获取这两个值的数量,如果超过限流值,就实行限流。

代码如下:

 

package com.bxm.warcar.cache.test.fetcher;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Protocol;

import java.util.ArrayList;
import java.util.List;


/**
 * 

* 基于redis的时间滑动窗口 *

* * @author hcmony * @since V1.0.0, 2020/08/11 22:00 */ public class Test { private final static JedisPool jedisPool = new JedisPool(new JedisPoolConfig(), "10.10.1.34", 6379, Protocol.DEFAULT_TIMEOUT, "redis_pwd123", 0); private static List list = new ArrayList<>(); /** * 设定 有1000个请求进来,但是每秒只能接受200个请求 * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { int a = 1000; int limit =200; final long l = System.currentTimeMillis(); for (int i = 0; i < a; i++) { add("LIMIT:TEST", "TEST" + i, limit); Thread.sleep(1); } System.out.println(System.currentTimeMillis()-l); System.out.println(list); } /** * * @param key 固定的 * @param value 变化的,同一个value只能存入一次 * @param limit 限流参数,可调整 */ private static void add(String key, String value, int limit) { final long timeMillis = System.currentTimeMillis(); if (get(key, timeMillis) > limit) { System.out.println(value+"超过限制了"); list.add(value); return; } Jedis jedis = null; try { jedis = jedisPool.getResource(); jedis.zadd(key, timeMillis, value); } finally { if (jedis != null) { jedis.close(); } } } /** * 获取当前 timeMillis 往前退1秒的数据 * @param key 固定的 * @param timeMillis 动态的,以毫秒为单位统计 * @return */ private static long get(String key, long timeMillis) { Jedis jedis = null; try { jedis = jedisPool.getResource(); return jedis.zcount(key, timeMillis - 1000, timeMillis); } finally { if (jedis != null) { jedis.close(); } } } }

https://www.aliyun.com/activity/daily/cloud?userCode=8hemam4l

你可能感兴趣的:(java基础,分布式服务,java,算法,redis,时间滑动窗口)