热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SpringCloud微服务接口限流的两种方式

背景我想,大家平时接触最多的app就是淘宝、京东了吧!这些大的电商网站,每天处理的访问量都是亿级的。如果,不对系统中的各个接

背景

我想,大家平时接触最多的app就是淘宝、京东了吧!这些大的电商网站,每天处理的访问量都是亿级的。如果,不对系统中的各个接口进行保护,当并发访问量大时,系统就会发生故障。

所以,保护好系统,就会用到缓存、降级和限流这三把利器。前面讲过了断路器Hystrix的熔断与降级;缓存可以使用内存里面的缓存队列、消息中间件、分布式缓存;限流可以使用Zuul来实现。通过限流,可以很好地控制系统的qps。

每秒查询率QPS是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。

服务限流

方法一:Zuul+RateLimiter

RateLimiter是Guava提供的基于令牌桶算法的实现类,可以非常简单的完成限流特技,并且根据系统的实际情况来调整生成token的速率。

至于令牌桶算法的基本流程,大家可以通过查询相关资料进行学习。给大家推荐一个讲解令牌桶算法的视频,个人觉得易于理解。https://www.bilibili.com/video/av26168532/ ,接下来,就用代码的方式来实现Zuul的限流。

要用RateLimiter,需要导入相应的约束,所以,就对上篇博文中的网关服务(api-gateway)进行改造,pom中增加约束。

com.marcosbarbero.cloudspring-cloud-zuul-ratelimit2.1.0.RELEASE


org.springframework.bootspring-boot-starter-data-redis

注意,这里需要用到Redis,所以也需要把Redis的约束导入。然后在yml中添加相应的配置。公众 号Java精选,回复java面试,获取面试资料,支持在线刷题。

ratelimit:enabled: truedefault-policy:limit: 10quota: 4refresh-interval: 5type: #可选 限流方式- url

  • ratelimit.enabled=true表示开启限流策略。

  • ratelimit.default-policy.limit=10 表示请求控制在10次以内。

  • ratelimit.default-policy.quota=4 请求时间不得超过4秒。

  • ratelimit.default-policy.refresh-interval=5 刷新间隔是5秒。

综上所述:所有服务在5秒内只能有10次请求,并且请求的时间总和不得超过4秒。

配置完成,接下来,启动服务,进行测试。

d13f550697f54dedff77f8d388c31e6b.png

可以看到,在启动网关服务的时候,出现了异常。上面指出zuul.ratelimit.repository这个配置,不能为空。相信大家对repository这个词并不陌生。我们原来在学Mybatis、JPA、Hibernate的时候经常看到。

所以,这个错误就是提示我们,需要某种仓库存储限流数据。通过点击配置文件,查看源码。

/** Copyright 2012-2018 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.properties;public enum RateLimitRepository {/*** Uses Redis as data storage*/REDIS,/*** Uses Consul as data storage*/CONSUL,/*** Uses SQL database as data storage*/JPA,/*** Uses Bucket4j JCache as data storage*/BUCKET4J_JCACHE,/*** Uses Bucket4j Hazelcast as data storage*/BUCKET4J_HAZELCAST,/*** Uses Bucket4j Ignite as data storage*/BUCKET4J_IGNITE,/*** Uses Bucket4j Infinispan as data storage*/BUCKET4J_INFINISPAN,
}

可以看到这是一个枚举类。其中,较为熟悉的就是REDIS、CONSUL、JPA。这里,就选择REDIS作为限流数据的存储。这就是pom文件中导入REDIS的原因。重新修改配置文件

ratelimit:enabled: truerepository: REDIS  #对应存储类型(用来存储统计信息)behind-proxy: true  #代理之后default-policy: #可选 - 针对所有的路由配置的策略,除非特别配置了policieslimit: 10 #可选 - 每个刷新时间窗口对应的请求数量限制quota: 4 #可选-  每个刷新时间窗口对应的请求时间限制(秒)refresh-interval: 5 # 刷新时间窗口的时间,默认值 (秒)type: #可选 限流方式- url

服务正常启动,接下来进行测试。

上面限制5秒之内只能发送10次请求,那就发送11次请求试一试。使用postman工具进行请求的发送。同时,教大家如何使用postman批量发送请求。

861a02da35afa7daae6c78aea39e602e.png

首先,在地址栏填写接口地址,然后,可以点击send,测试当前地址是否正确。如果一切正常,点击旁边的save按钮。

0548da0cd3b76a830be2b3624a4d2f22.png

出现上面的浮层,按照箭头的标注,进行操作,点击save按钮后,在左边就能看到已经保存的请求了。

cdc7699424ba14980321c83ca8c68276.png

然后点击图示的run按钮,进入下面的界面。

48df995b97e45d9a40253cf1fe7c08a8.png

按照文中给出的注释,进行设定,这里我就改一下请求的次数,设置为11次。然后点击run按钮发起请求,看测试结果。

9540a64e6d4764b46588009ea9558bd8.png

可以看到,配置文件中规定请求次数为10次,测试前10次请求都是正常的响应。而第11次请求就被限流策略阻止了。证明了配置生效,接口限流成功。

方法二:过滤器限流

Zuul的过滤器功能,不仅可以做权限验证,也可以拿来做限流。所以,新建一个过滤器,让其继承ZuulFilter

package com.root.project.apigateway.filter;import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;/*** @ClassName: InterfaceLimitFilter* @Author: 清风一阵吹我心* @Description: TODO* @Version 1.0**/
@Component
public class InterfaceLimitFilter extends ZuulFilter {//每秒产生10个令牌private static final RateLimiter RATE_LIMITER = RateLimiter.create(10);@Overridepublic String filterType() {return PRE_TYPE;}@Overridepublic int filterOrder() {return -10;}@Overridepublic boolean shouldFilter() {RequestContext context = RequestContext.getCurrentContext();HttpServletRequest request = context.getRequest();//只对管理员服务限流String admin = "/api/admin/v1.0/admin";return admin.equalsIgnoreCase(request.getRequestURI());}/*** 限流逻辑* RATE_LIMITER.tryAcquire()尝试获取令牌* @return* @throws ZuulException*/@Overridepublic Object run() throws ZuulException {RequestContext context = RequestContext.getCurrentContext();//每调用一次tryAcquire()方法,令牌数量减1if (!RATE_LIMITER.tryAcquire()) {context.setSendZuulResponse(false);context.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());HttpServletResponse response = context.getResponse();try {response.setContentType("text/html;charset=UTF-8");response.getWriter().write("访问上限,限流啦");} catch (IOException e) {e.printStackTrace();}}return null;}
}

因为Guava是基于令牌桶算法的实现类,所以RateLimiter.create(10)可以理解为:每秒往桶里放入10个令牌。RATE_LIMITER.tryAcquire()方法尝试获取桶里的令牌,如果有,则返回true,并且,总的令牌数减1。没有则返回false。后面的逻辑和权限验证相似。设置Htpp状态码,然后返回信息到前台展示。

注意:在类上还要加入@Component注解,将其注入到IOC容器中。

启动服务,进行测试。使用postman发送20个请求。

932fffa59a296487f17e5183c58baf80.png

奇怪的事情发生了,可以看到第十八个请求被限流了,但是第十九个请求又成功了。其实这也不难理解,当第十八个请求到达网关时,木桶里已经没有令牌可以获取了。所以,直接被限流策略限制。

其实,除了网关层的限流,还能在Nginx层上做限流。感兴趣的朋友,可以去看一下Nginx方面的知识。一个高性能的HTTP和反向代理服务器,作为一名开发人员,了解和使用它,也是必不可少的。

作者:星光不问赶路人º

https://blog.csdn.net/qq_32101993/article/details/87375917

公众号“Java精选”所发表内容注明来源的,版权归原出处所有(无法查证版权的或者未注明出处的均来自网络,系转载,转载的目的在于传递更多信息,版权属于原作者。如有侵权,请联系,笔者会第一时间删除处理!
最近有很多人问,有没有读者交流群!加入方式很简单,公众号Java精选,回复“加群”,即可入群!Java精选面试题(微信小程序):3000+道面试题,包含Java基础、并发、JVM、线程、MQ系列、Redis、Spring系列、Elasticsearch、Docker、K8s、Flink、Spark、架构设计等,在线随时刷题!
------ 特别推荐 ------
特别推荐:专注分享最前沿的技术与资讯,为弯道超车做好准备及各种开源项目与高效率软件的公众号,「大咖笔记」,专注挖掘好东西,非常值得大家关注。点击下方公众号卡片关注。点击“阅读原文”,了解更多精彩内容!文章有帮助的话,点在看,转发吧!


推荐阅读
  • 本文探讨了如何通过Service Locator模式来简化和优化在B/S架构中的服务命名访问,特别是对于需要频繁访问的服务,如JNDI和XMLNS。该模式通过缓存机制减少了重复查找的成本,并提供了对多种服务的统一访问接口。 ... [详细]
  • 本文详细介绍了如何利用 Bootstrap Table 实现数据展示与操作,包括数据加载、表格配置及前后端交互等关键步骤。 ... [详细]
  • 本文详细介绍了`android.os.Binder.getCallingPid()`方法的功能和应用场景,并提供了多个实际的代码示例。通过这些示例,开发者可以更好地理解如何在不同的开发场景中使用该方法。 ... [详细]
  • 秒建一个后台管理系统?用这5个开源免费的Java项目就够了
    秒建一个后台管理系统?用这5个开源免费的Java项目就够了 ... [详细]
  • 本文详细介绍了 InfluxDB、collectd 和 Grafana 的安装与配置流程。首先,按照启动顺序依次安装并配置 InfluxDB、collectd 和 Grafana。InfluxDB 作为时序数据库,用于存储时间序列数据;collectd 负责数据的采集与传输;Grafana 则用于数据的可视化展示。文中提供了 collectd 的官方文档链接,便于用户参考和进一步了解其配置选项。通过本指南,读者可以轻松搭建一个高效的数据监控系统。 ... [详细]
  • 本文探讨了如何在PHP与MySQL环境中实现高效的分页查询,包括基本的分页实现、性能优化技巧以及高级的分页策略。 ... [详细]
  • 我的读书清单(持续更新)201705311.《一千零一夜》2006(四五年级)2.《中华上下五千年》2008(初一)3.《鲁滨孙漂流记》2008(初二)4.《钢铁是怎样炼成的》20 ... [详细]
  • 本文总结了一次针对大厂Java研发岗位的面试经历,探讨了面试中常见的问题及其背后的原因,并分享了一些实用的面试准备资料。 ... [详细]
  • 深入理解:AJAX学习指南
    本文详细探讨了AJAX的基本概念、工作原理及其在现代Web开发中的应用,旨在为初学者提供全面的学习资料。 ... [详细]
  • 在尝试通过自定义端口部署Spring Cloud Eureka时遇到了连接失败的问题。本文详细描述了问题的现象,并提供了有效的解决方案,以帮助遇到类似情况的开发者。 ... [详细]
  • Java中的引用类型详解
    本文详细介绍了Java中的引用类型,包括强引用、软引用、弱引用和虚引用的特点和应用场景。 ... [详细]
  • 本文通过基准测试(Benchmark)对.NET Core环境下Thrift和HTTP客户端的微服务通信性能进行对比分析。基准测试是一种评估系统或组件性能的方法,通过运行一系列标准化的测试来衡量其表现。 ... [详细]
  • 本文详细介绍了Java代码分层的基本概念和常见分层模式,特别是MVC模式。同时探讨了不同项目需求下的分层策略,帮助读者更好地理解和应用Java分层思想。 ... [详细]
  • 阿里巴巴终面技术挑战:如何利用 UDP 实现 TCP 功能?
    在阿里巴巴的技术面试中,技术总监曾提出一道关于如何利用 UDP 实现 TCP 功能的问题。当时回答得不够理想,因此事后进行了详细总结。通过与总监的进一步交流,了解到这是一道常见的阿里面试题。面试官的主要目的是考察应聘者对 UDP 和 TCP 在原理上的差异的理解,以及如何通过 UDP 实现类似 TCP 的可靠传输机制。 ... [详细]
  • 本文介绍了如何利用Shell脚本高效地部署MHA(MySQL High Availability)高可用集群。通过详细的脚本编写和配置示例,展示了自动化部署过程中的关键步骤和注意事项。该方法不仅简化了集群的部署流程,还提高了系统的稳定性和可用性。 ... [详细]
author-avatar
天涯s1_278
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有