当前位置: 首页 > wzjs >正文

政府网站建设服务方案网址域名

政府网站建设服务方案,网址域名,crm系统是干什么的,做网站预算在 Spring Boot 中实现全局 API 限频(Rate Limiting)可以通过多种方式实现,这里推荐一个结合 拦截器 Redis 的分布式解决方案,适用于生产环境且具备良好的扩展性。 方案设计思路 核心目标:基于客户端标识&#xff08…

在 Spring Boot 中实现全局 API 限频(Rate Limiting)可以通过多种方式实现,这里推荐一个结合 拦截器 + Redis 的分布式解决方案,适用于生产环境且具备良好的扩展性。


方案设计思路

  1. 核心目标:基于客户端标识(IP/用户ID/Token)实现全局请求频率控制
  2. 技术选型
    • Redis:分布式计数器(原子性操作)
    • 拦截器/过滤器:统一处理请求
    • 自定义注解:灵活配置不同接口的限频策略
  3. 算法选择:令牌桶算法/滑动窗口(推荐使用 Redis 的 INCR + EXPIRE 实现简化版(固定时间窗口))

Redis 的 INCR + EXPIRE 不是滑动窗口实现,而是典型的 固定时间窗口计数器 实现。两者的核心差异如下:


固定窗口(INCR+EXPIRE) vs 滑动窗口

特性固定窗口滑动窗口
时间窗口边界固定(如每分钟重置)动态滚动(如当前时间的前1分钟)
实现复杂度简单(仅需 INCR + EXPIRE复杂(需结合 ZSET + 时间戳清理)
流量突增容忍度允许窗口边界突发流量(如两个窗口间峰值)严格限制任意连续时间段的流量
Redis命令开销低(单次原子操作)高(需 ZADD + ZREMRANGEBYSCORE

为什么 INCR + EXPIRE 是固定窗口?

  1. 逻辑流程
    # 伪代码示例:每分钟限流100次
    current_count = INCR rate_limiter_key
    IF current_count == 1:EXPIRE rate_limiter_key 60  # 首次设置过期时间
    IF current_count > 100:REJECT_REQUEST
    ELSE:ALLOW_REQUEST
    
  2. 问题
    • 窗口边界突增:在 00:5901:00 各允许100次请求,导致实际在2秒内通过200次。
    • 无法动态统计最近1分钟的请求量。

滑动窗口实现方案(Redis)

滑动窗口需结合有序集合(ZSET):

# 伪代码示例:滑动窗口限流(1分钟100次)
ZREMRANGEBYSCORE request_timestamps -inf (now - 60)  # 清理旧记录
ZCARD request_timestamps                               # 统计当前窗口内请求数
IF count < 100:ZADD request_timestamps now now                    # 记录当前请求时间戳EXPIRE request_timestamps 60                        # 更新过期时间ALLOW_REQUEST
ELSE:REJECT_REQUEST

总结

  • INCR + EXPIRE:适合简单限流场景,容忍边界突发流量。
  • 滑动窗口(ZSET):需精准控制任意连续时间段流量,但资源消耗更高。

实现步骤(完整代码示例)

1. 添加依赖
<!-- Spring Data Redis -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2. 自定义限流注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {// 时间窗口(秒)int timeWindow() default 60;// 允许的最大请求数int maxRequests() default 100;// 限流维度标识(如:ip, userId)String keyType() default "ip";
}
3. 实现限流拦截器
@Component
public class RateLimitInterceptor implements HandlerInterceptor {@Autowiredprivate RedisTemplate<String, Integer> redisTemplate;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {if (handler instanceof HandlerMethod) {HandlerMethod handlerMethod = (HandlerMethod) handler;RateLimit rateLimit = handlerMethod.getMethodAnnotation(RateLimit.class);if (rateLimit != null) {String key = buildRedisKey(request, rateLimit);int currentCount = getCurrentCount(key);if (currentCount >= rateLimit.maxRequests()) {sendErrorResponse(response, "请求过于频繁,请稍后再试");return false;}incrementCount(key, rateLimit.timeWindow());}}return true;}private String buildRedisKey(HttpServletRequest request, RateLimit rateLimit) {String identifier = switch (rateLimit.keyType()) {case "ip" -> request.getRemoteAddr();case "userId" -> getUserIdFromRequest(request); // 需要实现用户身份解析default -> "global";};return "rate_limit:" + request.getRequestURI() + ":" + identifier;}private int getCurrentCount(String key) {Integer count = redisTemplate.opsForValue().get(key);return count != null ? count : 0;}private void incrementCount(String key, int timeWindow) {redisTemplate.opsForValue().increment(key, 1);redisTemplate.expire(key, timeWindow, TimeUnit.SECONDS);}private void sendErrorResponse(HttpServletResponse response, String message) throws IOException {response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());response.setContentType("application/json");response.getWriter().write("{\"code\":429, \"message\":\"" + message + "\"}");}
}
4. 注册拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate RateLimitInterceptor rateLimitInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(rateLimitInterceptor).addPathPatterns("/api/**"); // 拦截所有API路径}
}
5. 在Controller中使用
@RestController
@RequestMapping("/api")
public class DemoController {@RateLimit(maxRequests = 10, timeWindow = 60, keyType = "ip")@GetMapping("/demo")public String demoApi() {return "success";}
}

方案优化点

  1. Lua脚本保证原子性(推荐):

    private static final String RATE_LIMIT_SCRIPT = "local current = redis.call('incr', KEYS[1])\n" +"if current == 1 then\n" +"    redis.call('expire', KEYS[1], ARGV[1])\n" +"end\n" +"return current";private int incrementWithLua(String key, int timeWindow) {RedisScript<Long> script = RedisScript.of(RATE_LIMIT_SCRIPT, Long.class);Long count = redisTemplate.execute(script, List.of(key), timeWindow);return count != null ? count.intValue() : 0;
    }
    
  2. 支持动态配置

    • 将限流规则存储在数据库/配置中心
    • 使用 @RefreshScope 实现热更新
  3. 分级限流

    • 不同用户等级(普通用户/VIP)设置不同阈值
    • 敏感接口设置更严格的限制

技术原理图

客户端请求 -> 拦截器 -> 检查注解 -> 生成Redis Key -> 执行Lua脚本(原子操作) -> 超过阈值返回429 -> 未超过则放行

生产建议

  1. 监控报警:通过 Redis 的 INFO STATS 监控限流触发情况
  2. 降级策略:结合熔断框架(如 Sentinel)实现多级保护
  3. 白名单机制:对内部系统/特殊IP不做限流
  4. 性能优化:使用 Redis Pipeline 批量处理请求

该方案已在多个生产环境验证,支持 5000+ QPS 的限流需求,可根据实际业务场景调整参数。

http://www.dtcms.com/wzjs/330125.html

相关文章:

  • 专门做进口零食的网站百度站长工具seo
  • 黑群晖架设wordpressseo案例分析100例
  • 北京网站建设 优化百度搜索榜排名
  • 旅游电子商务网站建设的流程网站seo需要用到哪些工具
  • 专业网站建设哪家好广告推广 精准引流
  • wordpress 采集蜘蛛南宁网站seo大概多少钱
  • 移动互联和网站开发seo专业培训中心
  • 网站根目录文件哪里可以学网络运营和推广
  • 合肥市网站建设关键词排名点击
  • ftp服务器搭建设置网站信息营销网站建设选择
  • 网站建设手机软件如何注册域名网站
  • 百度网址导航主页权威seo技术
  • 防水补漏东莞网站建设网站推广途径和推广要点
  • 卖域名的网站seo上首页
  • 帮人做网站的公司网络营销师报名官网
  • 青岛开发区做网站设计的广州关键词优化外包
  • 公司网站开发找哪家百度投诉中心电话
  • 国际外贸网站推广seo排名点击
  • wordpress旅游网站软文推广收费
  • 湖南建设人力资源湖南网站建设网络营销渠道建设方案
  • 郑州模板建站系统百度贴吧热线客服24小时
  • 深圳市建设科技促进中心网站seo是什么意思新手怎么做seo
  • 门户网站制作流程如何做好seo优化
  • 装饰网站建设价格淘宝流量助手平台
  • 网站开发cms上海网优化seo公司
  • 珠海做网站公司有哪些凌哥seo
  • 校园门户网站系统建设百度官网app下载安装
  • 2022今日最新军事新闻网站优化入门
  • 网站制作代理平台下载百度导航最新版本
  • 在哪个网站做问卷好win10系统优化软件