【限流保护】Springboot接口限流
公众号上线啦!
搜一搜【国服冰】
使命:尽自己所能给自学后端开发的小伙伴提供一个少有弯路的平台
回复:国服冰,即可领取我为大家准备的资料,里面包含整体的Java学习路线,电子书,以及史上最全的面试题!
高并发保护常用方案
- 缓存:缓存的目的是提升系统访问速度和增大系统处理容量
- 降级:降级是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行
- 限流:限流的目的是通过对并发访问/请求进行限速,或者对一个时间窗口内的请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务、排队或等待、降级等处理
为什么需要限流
在一个高并发系统中对流量的把控是非常重要的,当巨大的流量直接请求到我们的服务器上没多久就可能造成接口不可用,不处理的话甚至会造成整个应用不可用。
常用限流算法
- 计数器法
- 滑动窗口
- 漏桶算法
- 令牌桶算法
计数器法
方案一:第一个请求过来时,采用requestURI
+userID
为key
,value = 1
,当第二个请求过来时incr
自增,当缓存中的value
达到请求最大数时直接拒绝访问该URI
,弹出请求频繁提示。
方案二:第一种方案可用度很低,当存在多个接口需要限流而且每个接口承载的流量不一致时可用度不高,而且我们需要在访问接口前进行一个拦截处理,这里我们创建一个Interceptor
(拦截器)并声明一个限流注解,既然这里使用了拦截器,我们可以在注解中判断是否需要用户登录,当方法上不存在限流注解时则返回true
放行,然后进行计数器法进行限流。
限流注解
@Retention(RetentionPolicy.RUNTIME)
@Target(value = ElementType.METHOD)
public @interface AccessLimit {int second();int maxCount() default 5;boolean needLogin();
}
Interceptor
@Service
public class AccessInterceptor implements HandlerInterceptor {@Autowiredprivate UserService userService;@Autowiredprivate RedisService redisService;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {if(handler instanceof HandlerMethod) {User user = getMiaoshaUser(request);UserContext.setUser(user);HandlerMethod handlerMethod = (HandlerMethod) handler;AccessLimit methodAnnotation = handlerMethod.getMethodAnnotation(AccessLimit.class);if (methodAnnotation == null) {return true;}int second = methodAnnotation.second();int maxCount = methodAnnotation.maxCount();boolean needLogin = methodAnnotation.needLogin();if (needLogin) {if (user == null) {render(response, CodeMsg.SESSION_ERROR);return false;}}/*** 根据注解填的参数进行限流,接口的uri+"_"+userID为Key,最大请求数maxCount为Value**/String requestURI = request.getRequestURI();String key = requestURI + "_" + user.getId();AccessLimitKey accessLimitKey = AccessLimitKey.withExpire(second);Integer rMaxCount = redisService.get(accessLimitKey, key, Integer.class);if (rMaxCount == null) {redisService.set(accessLimitKey, key, 1);} else if (rMaxCount < maxCount) {redisService.incr(accessLimitKey, key);} else {System.out.println(CodeMsg.MIAOSHA_FREQUENTLY);render(response, CodeMsg.MIAOSHA_FREQUENTLY);return false;}}return true;}public void render(HttpServletResponse response, CodeMsg msg) throws IOException {response.setContentType("application/json;charset=UTF-8");String s = JSON.toJSONString(Result.error(msg));OutputStream os = response.getOutputStream();os.write(s.getBytes("UTF-8"));os.flush();os.close();}public User getMiaoshaUser(HttpServletRequest request){Cookie[] cookies = request.getCookies();if(cookies == null || cookies.length <=0){return null;}String token = null;for(Cookie cookie : cookies){if(cookie.getName().equals(LoginController.COOKIE_NAME)){//拿到tokentoken = cookie.getValue();break;}}User user = userService.getUserByToken(token);return user;}
}
WebMvcConfigurer中注册拦截器
@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(accessInterceptor);}
在拦截器中保存用户时使用的了ThreadLoal
:每个 Thread
内有自己的实例副本,且该副本只能由当前 Thread
使用,因为拦截器会在参数解析器前先执行,所以在拦截器中获取到用户后可以在参数解析器中获取到User
public class UserContext {public static ThreadLocal<User> threadLocal = new ThreadLocal();public static void setUser(User user){threadLocal.set(user);}public static User getUser(){return threadLocal.get();}
}
这种方法有个最致命的弱点就是限制不精确:
如果某个接口限制的是一分钟最大请求为100
,此时有一位狂徒张三在第0:59
的情况下利用不正当工具请求的我们接口100
次,然后在第1
分钟的时候又请求了我们接口100
次,这时就有了200/s
的请求速,我们原则上是只承载1.6/s
的请求速,整整大了125
倍,通过在时间窗口的重置节点处突发请求,可以瞬间超过我们的速率限制。狂徒张三有可能通过算法的这个漏洞,瞬间压垮我们的应用,当然有其他算法可以避免这个漏洞,这里就不赘述。
下面我们来测试一下这个接口
@AccessLimit(second = 5,maxCount = 5,needLogin = true)@RequestMapping(value = "/togoodslist",produces = "text/html")
当超过5
个请求后拦截器直接拦截返回提示页面,避免频繁请求
【限流保护】Springboot接口限流相关推荐
- 亿级流量场景下如何为HTTP接口限流?看完我懂了!!
这里,我们实现Web接口限流,具体方式为:使用自定义注解封装基于令牌桶限流算法实现接口限流. 不使用注解实现接口限流 搭建项目 这里,我们使用SpringBoot项目来搭建Http接口限流项目,Spr ...
- 轻松两步,我在 SpringBoot 服务上实现了接口限流
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! Sentinel是阿里巴巴开源的限流器熔断器,并且带有可视 ...
- Springboot 整合 Current-Limiting 实现接口限流
该篇文章内容: 1.实现标题中提到的接口限流 2.使用压测工具jmeter给大家展现验证效果 第一部分,代码的实现 首先是导入依赖包: <dependency><groupId> ...
- 后端技术:阿里开源的接口限流神器Sentinel介绍
Sentinel是阿里巴巴开源的限流器熔断器,并且带有可视化操作界面. 在日常开发中,限流功能时常被使用,用于对某些接口进行限流熔断,譬如限制单位时间内接口访问次数:或者按照某种规则进行限流,如限制i ...
- 接口限流算法:漏桶算法令牌桶算法
工作中对外提供的API 接口设计都要考虑限流,如果不考虑限流,会成系统的连锁反应,轻者响应缓慢,重者系统宕机,整个业务线崩溃,如何应对这种情况呢,我们可以对请求进行引流或者直接拒绝等操作,保持系统的可 ...
- 微服务接口限流的设计与思考(附GitHub框架源码)
http://www.infoq.com/cn/articles/microservice-interface-rate-limit?useSponsorshipSuggestions=true&am ...
- 接口限流算法:漏桶算法amp;令牌桶算法
转载自 接口限流算法:漏桶算法&令牌桶算法 背景 每一个对外提供的API接口都是需要做流量控制的,不然会导致系统直接崩溃.很简单的例子,和保险丝的原理一样,如果用电符合超载就会烧断保险丝断掉电 ...
- 接口限流算法及解决方案
参考: 接口限流算法:漏桶算法&令牌桶算法 文章目录 一.限流算法 1. 漏桶算法 2. 令牌桶算法 二.令牌桶算法VS漏桶算法 三.解决方案 1. 使用Guava的RateLimiter进行 ...
- 接口限流算法:漏桶算法令牌桶算法。
背景 每一个对外提供的API接口都是需要做流量控制的,不然会导致系统直接崩溃.很简单的例子,和保险丝的原理一样,如果用电符合超载就会烧断保险丝断掉电源以达到保护的作用.API限流的意义也是如此,如果A ...
最新文章
- DeepMind又出大招!新算法MuZero登顶Nature,AI离人类规划又近了一步
- java 100以内冒泡算法_Java俩种形式实现冒泡排序
- leetcode算法题--重排链表★
- Windows7中启动Mysql服务时提示:拒绝访问的一种解决方式
- 关于spring cloud的几个核心组件
- 年末阿里百度等大厂技术面试题汇总,不可思议!
- 【求助】测试XCode v8.0的正向反向功能
- python_知识点_字符串+数字+列表
- 操作系统,语言分类,变量
- 如何实现一个HTML5 RPG游戏引擎——第二章,实现烟雨和雪飞效果
- 佳能G1810G2810G1800G2800G3800 废墨 手动清零方法
- web-----简单小游戏项目
- Origin软件绘制柱形图
- 云平台、面向服务的体系结构和云编程
- 《人月神话》经典摘录
- MATLAB 棋盘格图片校准
- MySQL的启动与简单命令_002
- 未能检测服务器连接失败,被控链接失败处理检查方法
- 通常所说的微型计算机主机是指,通常所说的微型主机是指
- java是几位的unicode,下列说法错误的是()。A.Java的字符类型采用的是Unicode编码,每个Unicode码占16位比特B.Java的各种...