redis实现限流
我们可以使用redis来实现一个简单的滑动窗口限流,滑动窗口的话我们可以使用zset的score来进行实现。value需要保证唯一性,暂且使用时间戳。
通过统计该窗口内的行为数量和限制的最大数量maxCount进行比较就可以得出当前的请求是否允许
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| public class RedisRateLimiter { @Autowired private StringRedisTemplate stringRedisTemplate;
@Test public void test() { for (int i = 0; i < 10; i++) { System.out.println(isActionAllow("user/list", "127.0.0.1", 1, 5)); try { Thread.sleep(150); } catch (InterruptedException e) { e.printStackTrace(); }
}
}
public boolean isActionAllow(String uri, String ip, int period, int maxCount) { String key = String.format("hist:%s:%s", uri, ip); long cur = System.currentTimeMillis(); List<Object> pipelined = stringRedisTemplate.executePipelined( new RedisCallback<Long>() {
@Override public Long doInRedis(RedisConnection connection) throws DataAccessException { connection.zAdd(key.getBytes(), cur, String.valueOf(cur).getBytes()); connection.zRemRangeByScore(key.getBytes(), 0, cur - period * 1000); Long count = connection.zCard(key.getBytes()); connection.expire(key.getBytes(), period + 1); return count; } } );
Object o = pipelined.get(2);
return Long.parseLong(String.valueOf(o)) <= maxCount; } }
|
如果时间窗口内允许的数量较大,会消耗大量的内存。则不适合该方式