springboot工程中限流方式

本文介绍了两种限流方法:一种是使用Guava的RateLimiter实现令牌桶算法,包括平滑突发和平滑预热限流;另一种是通过拦截器结合Redis实现注解限流。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

限流,是防止用户恶意刷新接口。常见的限流方式有阿里开源的sentinel、redis等。
1、google的guava,令牌桶算法实现限流
Guava的 RateLimiter提供了令牌桶算法实现:平滑突发限流(SmoothBursty)和平滑预热限流(SmoothWarmingUp)实现。

// RateLimiter提供了两个工厂方法,最终会调用下面两个函数,生成RateLimiter的两个子类。
static RateLimiter create(SleepingStopwatch stopwatch, double permitsPerSecond) {
 	RateLimiter rateLimiter = new SmoothBursty(stopwatch, 1.0 /* maxBurstSeconds */);
    rateLimiter.setRate(permitsPerSecond);
 	return rateLimiter;
}
static RateLimiter create(
 	SleepingStopwatch stopwatch, double permitsPerSecond, long warmupPeriod, TimeUnit unit,
 double coldFactor) {
 	RateLimiter rateLimiter = new SmoothWarmingUp(stopwatch, warmupPeriod, unit, coldFactor);
    rateLimiter.setRate(permitsPerSecond);
 	return rateLimiter;
}
    

平滑突发限流:使用 RateLimiter的静态方法创建一个限流器,设置每秒放置的令牌数为10个。返回的RateLimiter对象可以保证1秒内不会给超过10个令牌,并且以固定速率进行放置,达到平滑输出的效果。
平滑预热限流:RateLimiter的 SmoothWarmingUp是带有预热期的平滑限流,它启动后会有一段预热期,逐步将分发频率提升到配置的速率。

@RestController
public class HomeController {

    // 这里的10表示每秒允许处理的量为10个
    private RateLimiter limiter = RateLimiter.create(10);
    private RateLimiter limiter2 = RateLimiter.create(2, 1000, TimeUnit.SECONDS);
    //permitsPerSecond: 表示 每秒新增 的令牌数;warmupPeriod: 表示在从 冷启动速率 过渡到 平均速率 的时间间隔

    @GetMapping("/test/{name}")
    public String test(@PathVariable("name") String name) {
        // 请求RateLimiter, 超过permits会被阻塞
        final double acquire = limiter.acquire();
        System.out.println("acquire=" + acquire);
        //判断double是否为空或者为0
        if (acquire == 0) {
            return name;
        } else {
            return "操作太频繁";
        }
    }

    @AccessLimit(limit = 2, sec = 10)
    @GetMapping("/test2/{name}")
    public String test2(@PathVariable("name") String name) {
        return name;
    }
}

2、interceptor+redis根据注解限流

public class AccessLimitInterceptor implements HandlerInterceptor {

    @Resource
    private RedisTemplate<String, Integer> redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            if (!method.isAnnotationPresent(AccessLimit.class)) {
                return true;
            }
            AccessLimit accessLimit = method.getAnnotation(AccessLimit.class);
            if (accessLimit == null) {
                return true;
            }
            int limit = accessLimit.limit();
            int sec = accessLimit.sec();
            String key = IPUtil.getIpAddress(request) + request.getRequestURI();
            //资源唯一标识
            Integer maxLimit = redisTemplate.opsForValue().get(key);
            if (maxLimit == null) {
                //set时一定要加过期时间
                redisTemplate.opsForValue().set(key, 1, sec, TimeUnit.SECONDS);
            } else if (maxLimit < limit) {
                redisTemplate.opsForValue().set(key, maxLimit + 1, sec, TimeUnit.SECONDS);
            } else {
                output(response, "请求太频繁!");
                return false;
            }
        }
        return true;
    }

    public void output(HttpServletResponse response, String msg) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            outputStream.write(msg.getBytes("UTF-8"));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            outputStream.flush();
            outputStream.close();
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {

    @Bean
    public AccessLimitInterceptor accessLimitInterceptor() {
        return new AccessLimitInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //addPathPatterns 添加拦截规则
        registry.addInterceptor(accessLimitInterceptor()).addPathPatterns("/**");
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/");
    }
}
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashKeySerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }
}

限流方式还有很多,后续继续尝试。

<think>好的,用户想设计一个基于Spring Boot的价格查询系统,需要实现架构和设计。首先,我得理清用户的需求。价格查询系统可能涉及商品信息管理、价格数据获取、用户查询接口等模块。用户可能希望系统能够高效地处理查询请求,并且具备可扩展性和稳定性。 接下来,我需要考虑Spring Boot的常用架构模式。通常,微服务架构是一个不错的选择,尤其是当系统需要拆分成独立服务时。参考用户提供的引用内容,引用[1]提到使用API Gateway来统一管理微服务,这有助于实现松耦合和高可用性。所以,架构方面可能会采用API Gateway模式,将各个功能模块拆分为独立的服务,比如商品服务、价格服务、用户服务等。 然后,数据库设计方面,可能需要使用关系型数据库如MySQL来存储商品信息和价格数据。根据引用[2],数据库设计需要与系统模块设计结合,确保数据支持后台程序。这里可能需要设计商品表、价格表、用户表等,并考虑索引优化以提高查询效率。 技术选型方面,Spring Boot作为基础框架,整合Spring Data JPA或MyBatis进行数据持久化。同时,考虑到价格查询可能需要实时性,可以引入缓存机制,比如Redis,来缓存热点数据,减少数据库压力。此外,API Gateway可以使用Spring Cloud Gateway,服务注册与发现用Eureka或Nacos,这些都能提升系统的可伸缩性。 模块设计部分,需要分解系统功能。例如,商品管理模块负责增删改查商品信息,价格管理模块处理价格数据的更新和获取,查询接口模块处理用户请求并返回结果。每个模块作为独立的微服务,通过REST API进行通信,这样便于维护和扩展。 安全性也是需要考虑的,用户认证可以使用Spring Security或OAuth2来保护API接口,防止未授权访问。此外,日志监控和异常处理机制也不可少,确保系统稳定运行。 最后,用户可能关心如何实现这些模块的具体代码结构,比如Controller层处理请求,Service层实现业务逻辑,Repository层操作数据库。需要指导用户如何分层开发,以及如何集成缓存和分布式组件。同时,用户可能还想了解性能优化方法,比如数据库索引、缓存策略、负载均衡等,这些都需要在回答中提及。</think># 基于Spring Boot的价格查询系统架构与设计方案 ## 一、系统架构设计 本系统建议采用分层架构模式,参考微服务架构设计思想[^1],主要包含以下组件: $$系统架构 = API\ Gateway + 微服务集群 + 数据库集群 + 缓存层$$ ```mermaid graph TD A[客户端] --> B[API Gateway] B --> C[商品服务] B --> D[价格服务] B --> E[用户服务] C --> F[MySQL] D --> G[Redis] D --> F E --> F ``` ## 二、核心技术选型 1. **基础框架**:Spring Boot 3.x + Spring Cloud 2. **数据持久化**:Spring Data JPA/MyBatis + MySQL 8.0 3. **缓存层**:Redis 7.x(存储热点价格数据)[^2] 4. **服务网关**:Spring Cloud Gateway 5. **服务注册**:Nacos/Eureka 6. **监控系统**:Prometheus + Grafana ## 三、核心模块设计 ### 1. 商品管理模块 ```java // 商品实体示例 @Entity public class Product { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String skuCode; // 商品唯一编码 private String name; private String category; // 其他字段及getter/setter } ``` ### 2. 价格管理模块 ```java // 价格服务接口示例 public interface PriceService { @Cacheable(value = "prices", key = "#skuCode") BigDecimal getCurrentPrice(String skuCode); @CachePut(value = "prices", key = "#skuCode") void updatePrice(String skuCode, BigDecimal newPrice); } ``` ### 3. 查询接口模块 ```java @RestController @RequestMapping("/api/prices") public class PriceController { @Autowired private PriceService priceService; @GetMapping("/{skuCode}") public ResponseEntity<PriceResponse> getPrice( @PathVariable String skuCode, @RequestHeader("Authorization") String token) { // 身份验证逻辑 BigDecimal price = priceService.getCurrentPrice(skuCode); return ResponseEntity.ok(new PriceResponse(skuCode, price)); } } ``` ## 四、数据库设计 ### 商品表(product) | 字段名 | 类型 | 描述 | |--------|------|------| | id | BIGINT | 主键 | | sku_code | VARCHAR(32) | 商品唯一编码 | | name | VARCHAR(255) | 商品名称 | | category | VARCHAR(50) | 商品分类 | ### 价格表(price_history) | 字段名 | 类型 | 描述 | |--------|------|------| | id | BIGINT | 主键 | | sku_code | VARCHAR(32) | 关联商品编码 | | price | DECIMAL(12,2) | 当前价格 | | effective_date | DATETIME | 生效时间 | ## 五、性能优化策略 1. **缓存设计**:使用Redis缓存热点商品价格,设置TTL为5分钟 2. **数据库优化**: - 为sku_code字段建立唯一索引 - 对价格表进行水平分表(按商品类别) 3. **异步更新**:价格变更时通过消息队列(Kafka)异步更新缓存 4. **限流策略**:在API Gateway配置限流规则,防止恶意刷接口 ## 六、安全设计 1. 使用JWT进行接口鉴权 2. 敏感数据(如价格)传输使用HTTPS加密 3. 价格修改操作记录审计日志 4. 配置Spring Security进行权限控制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值