令牌桶
Redisson可以实现很多东西,在Redis的基础上,Redisson做了超多的封装,不仅可以用来实现分布式锁,还可以帮助我们实现令牌桶限流。
Ratelimter主要作用就是可以限制调用接口的次数。主要原理就是调用接口之前,需要拥有指定个令牌,限流器每秒会产生X个令牌放入令牌桶,调用接口需要去令牌桶里面拿令牌。如果令牌被其它请求拿完了,那么自然而然,当前请求就调用不到指定的接口。
RateLimter实现限流
java
@RestController
@RequestMapping("/redisTest")
public class RedisTestController {
@Autowired
private Redisson redisson;
@GetMapping("/Token")
public String testTokenBucket() {
RRateLimiter rateLimiter = redisson.getRateLimiter("myRatelimiter");
//最大流速 =每10秒钟产生1个令牌
rateLimiter.trySetRate(RateType.OVERALL, 1, 10, RateIntervalUnit.SECONDS);
//需要1个令牌
if (rateLimiter.tryAcquire(1)) {
return "令牌桶里面有可使用的令牌";
}
return "不好意思,请过十秒钟再来~~~~~~~";
}
}
RedisTemplate实现方式:
话不多说直接上代码,如下:
java
package com.shop.cyshop.commons.service;
/**
* 限流器
*
* @date 2024年04月28日 15:02
*/
import com.shop.cyshop.commons.locker.LockService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
@Slf4j
public class RequestLimitService {
private static final String REQUEST_LIMIT_KEY = "request_limit";
private static final int WINDOW_SIZE_SECONDS = 6; //每六秒一次请求限制
private static final int MAX_REQUESTS = 1;
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private LockService lockService;
public boolean isAllowed() {
return lockService.lock(REQUEST_LIMIT_KEY + "::glock", "sys", () -> {
long currentTime = System.currentTimeMillis() / 1000; //10
long windowStart = currentTime - WINDOW_SIZE_SECONDS;//4
// 删除过期的记录
redisTemplate.opsForZSet().removeRangeByScore(REQUEST_LIMIT_KEY, 0, windowStart);
// 获取当前窗口内的请求数量
Long currentRequests = redisTemplate.opsForZSet().count(REQUEST_LIMIT_KEY, windowStart, currentTime);
if (currentRequests != null && currentRequests < MAX_REQUESTS) {
// 增加请求记录
redisTemplate.opsForZSet().add(REQUEST_LIMIT_KEY, String.valueOf(currentTime), currentTime);
// 设置过期时间
redisTemplate.expire(REQUEST_LIMIT_KEY, WINDOW_SIZE_SECONDS, TimeUnit.SECONDS);
return true;
}
return false;
});
}
}