前言
本文接着上文应用限流进行讨论。
之前谈到的限流方案只能针对于单个 JVM 有效,也就是单机应用。而对于现在普遍的分布式应用也得有一个分布式限流的方案。
基于此尝试写了这个组件:
https://github.com/crossoverJie/distributed-redis-tool
DEMO
以下采用的是
https://github.com/crossoverJie/springboot-cloud
来做演示。
在 Order 应用提供的接口中采取了限流。首先是配置了限流工具的 Bean:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Configuration public class RedisLimitConfig {
@Value("${redis.limit}") private int limit;
@Autowired private JedisConnectionFactory jedisConnectionFactory;
@Bean public RedisLimit build() { RedisClusterConnection clusterConnection = jedisConnectionFactory.getClusterConnection(); JedisCluster jedisCluster = (JedisCluster) clusterConnection.getNativeConnection(); RedisLimit redisLimit = new RedisLimit.Builder<>(jedisCluster) .limit(limit) .build();
return redisLimit; } }
|
接着在 Controller 使用组件:
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
| @Autowired private RedisLimit redisLimit ;
@Override @CheckReqNo public BaseResponse<OrderNoResVO> getOrderNo(@RequestBody OrderNoReqVO orderNoReq) { BaseResponse<OrderNoResVO> res = new BaseResponse();
boolean limit = redisLimit.limit(); if (!limit){ res.setCode(StatusEnum.REQUEST_LIMIT.getCode()); res.setMessage(StatusEnum.REQUEST_LIMIT.getMessage()); return res ; }
res.setReqNo(orderNoReq.getReqNo()); if (null == orderNoReq.getAppId()){ throw new SBCException(StatusEnum.FAIL); } OrderNoResVO orderNoRes = new OrderNoResVO() ; orderNoRes.setOrderId(DateUtil.getLongTime()); res.setCode(StatusEnum.SUCCESS.getCode()); res.setMessage(StatusEnum.SUCCESS.getMessage()); res.setDataBody(orderNoRes); return res ; }
|
为了方便使用,也提供了注解:
1 2 3 4 5 6 7
| @Override @ControllerLimit public BaseResponse<OrderNoResVO> getOrderNoLimit(@RequestBody OrderNoReqVO orderNoReq) { BaseResponse<OrderNoResVO> res = new BaseResponse(); return res ; }
|
该注解拦截了 http 请求,会再请求达到阈值时直接返回。
普通方法也可使用:
1 2
| @CommonLimit public void doSomething(){}
|
会在调用达到阈值时抛出异常。
为了模拟并发,在 User 应用中开启了 10 个线程调用 Order(限流次数为5) 接口(也可使用专业的并发测试工具 JMeter 等)。