接口限流代码 - 实践
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-redis
@Component
public class RateLimitInterceptor implements HandlerInterceptor {
@Autowired
private RateLimiter rateLimiter;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
String ip = request.getRemoteAddr();
if (!rateLimiter.tryAcquire(ip)) {
response.setStatus(429);
return false;
}
return true;
}
}
public class RedisRateLimiter implements RateLimiter {
private final RedisTemplate redisTemplate;
public boolean tryAcquire(String key, int limit, int timeout) {
Long count = redisTemplate.opsForValue().increment(key, 1);
if (count == 1) {
redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
}
return count = 1) {
tokens--;
return true;
}
return false;
}
}
@Configuration
public class RateLimitConfig {
@Bean
public RateLimiter redisRateLimiter(RedisTemplate redisTemplate) {
return new RedisRateLimiter(redisTemplate);
}
@Bean
public RateLimiter tokenBucketRateLimiter() {
return new TokenBucketRateLimiter(10, 1); // 10容量,每秒1个令牌
}
}
- Redis限流:通过Redis的原子操作实现精确计数,适合分布式环境
- 令牌桶算法:单机限流方案,支持突发流量处理
- 拦截器机制:统一处理所有接口请求
- 可配置化:支持动态调整限流参数
- 响应状态码:返回429 Too Many Requests
实际部署时建议:
- 结合Nginx层限流
user nginx;
worker_processes auto;
events {
worker_connections 1024;
}
http {
# 白名单IP段定义
geo $limit {
default 1;
10.0.0.0/8 0; # 内网不限流
192.168.1.100 0; # 特定IP不限流
}
# 分层限流区域定义
limit_req_zone $binary_remote_addr zone=api_low:10m rate=100r/s;
limit_req_zone $binary_remote_addr zone=api_medium:10m rate=50r/s;
limit_req_zone $binary_remote_addr zone=api_high:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
# 自定义日志格式
log_format rate_log '$remote_addr - $http_x_forwarded_for [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'RateStatus=$limit_req_status ConnStatus=$limit_conn_status '
'ServiceTime=$request_time';
access_log /var/log/nginx/rate_limit.log rate_log;
error_log /var/log/nginx/error.log warn;
server {
listen 80;
server_name api.example.com;
# 公共静态资源不限流
location /static/ {
alias /var/www/static/;
access_log off;
}
# 健康检查接口不限流
location /health {
access_by_lua_block {
ngx.say("OK");
ngx.exit(200);
}
}
# 重要接口分层限流
location ~ ^/api/vip/ {
limit_req zone=api_high burst=20 nodelay;
limit_conn conn_limit 3;
proxy_pass http://backend_vip;
}
location ~ ^/api/business/ {
limit_req zone=api_medium burst=30 delay=10;
limit_conn conn_limit 10;
proxy_pass http://backend_biz;
}
# 普通接口限流
location /api/ {
limit_req zone=api_low burst=50;
limit_conn conn_limit 20;
proxy_pass http://backend;
}
# 白名单绕过限流
if ($limit = 0) {
set $limit_pass 1;
}
location / {
limit_req zone=api_low burst=50;
limit_conn conn_limit 20;
proxy_pass http://backend;
}
}
}
# 全局总限流(共享100r/s)
limit_req_zone $server_name zone=global_limit:10m rate=100r/s;
location /api/ {
limit_req zone=global_limit; # 所有IP共享100请求/秒
}