Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >使用Sentinel对Spring MVC接口进行限流

使用Sentinel对Spring MVC接口进行限流

作者头像
码农小胖哥
发布于 2020-10-10 02:28:43
发布于 2020-10-10 02:28:43
2.1K00
代码可运行
举报
运行总次数:0
代码可运行

1.前言

Spring Cloud Alibaba提供了中间件Sentinel,它以流量为切入点,提供了流量控制、熔断降级、系统负载保护等多个功能来保护服务的稳定性。今天就来尝试一下。

本文是在 Spring Boot 2.3.4.RELEASE 的基础之上构建的

2.依赖引入

和其它教程通过Spring Cloud Starter引入的不同,这里使用更加底层一些的依赖引入来让我们深入的了解一些Sentinel,这里引入的是1.8.0版本。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!--Sentinel 核心包-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>${sentinel.version}</version>
</dependency>
<!--@SentinelResource注解AOP切面支持-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-annotation-aspectj</artifactId>
    <version>${sentinel.version}</version>
</dependency>
<!--针对Spring MVC的适配器 Spring Webflux 可引入对应的适配器-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-spring-webmvc-adapter</artifactId>
    <version>${sentinel.version}</version>
</dependency>
<!--负责同 dashboard 进行通信  如果你没有使用 sentinel dashboard 它是可选的-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-transport-simple-http</artifactId>
    <version>${sentinel.version}</version>
</dependency>

这里引入了SentinelSpring MVC的相关适配器和注解支持。

3. 使用

Sentinel的限流首先要制定限流规则,然后针对规则进行资源的标记。通过监控标记资源流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。

流控规则

规则被封装到FlowRule对象中,需要声明的属性说明如下:

属性

说明

默认值

resource

资源名,资源名是限流规则的作用对象,不建议使用默认值

count

限流阈值,可以是 QPS 阈值,也可以是并发线程数阈值

grade

限流阈值类型,QPS 模式(1)或并发线程数模式(0)

QPS 模式

limitApp

可针对性的对特定客户端的请求进行流控

default,代表不区分调用来源

strategy

调用关系限流策略:直接、链路、关联

根据资源本身(直接)

controlBehavior

流控效果(直接拒绝/WarmUp/匀速+排队等待),不支持按调用关系限流

直接拒绝

clusterMode

是否集群限流

下面定义了一个规则并加载到内存中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 规则对应的类为FlowRule,用List保存,可以有多个规则
List<FlowRule> rules = new ArrayList<>();
FlowRule flowRule = new FlowRule();
// 设置资源名称
flowRule.setResource("bar");
// QPS为2
flowRule.setCount(2);
// 需要在限流过滤器中设置对应的解析策略来获取
// flowRule.setLimitApp(appName);
//限流的类型
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
flowRule.setControlBehavior(CONTROL_BEHAVIOR_DEFAULT);
rules.add(flowRule);
FlowRuleManager.loadRules(rules);

上面这种硬编码方式 一般仅用于测试和演示,生产上一般通过动态规则源的方式来动态管理规则。详细参考官方文档中关于动态流控规则的描述[1]

标记限流资源

传统情况下使用SphU 包含了 try-catch 风格的 API 进行限流操作。当资源发生了限流之后会抛出 BlockException。这个时候可以捕捉异常,进行限流之后的逻辑处理。基本范式如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 1.5.0 版本开始可以利用 try-with-resources 特性(使用有限制)
// 资源名可使用任意有业务语义的字符串,比如方法名、接口名或其它可唯一标识的字符串。
try (Entry entry = SphU.entry("resourceName")) {
  // 被保护的业务逻辑
  // do something here...
} catch (BlockException ex) {
  // 资源访问阻止,被限流或被降级
  // 在此处进行相应的处理操作
}

这种样板代码并不是非常优雅,所以Sentinel提供了@SentinelResource注解来简化开发,需要依赖sentinel-annotation-aspectj模块并显式的启用AOP切面类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
    return new SentinelResourceAspect();
}

然后我们可以在Spring MVC接口上进行如下标记即可:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@SentinelResource(value = "bar", entryType = EntryType.IN)
@GetMapping("/bar")
public String bar() {
    return "bar";
}

无论异常处理还是注解都只建议在学习中使用,实际生产中配合sentinel-dashboard可以更加方便地、集中地进行标记配置限流资源。详情参考控制台文档[2]

全局配置

我们还可以通过SentinelWebInterceptor或者SentinelWebTotalInterceptor来配置一些全局特性。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.felord.sentinel.configuration;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.SentinelWebInterceptor;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.config.SentinelWebMvcConfig;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class GlobalSentinelWebMvcConfiguration implements WebMvcConfigurer {


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        SentinelWebMvcConfig sentinelWebMvcConfig = new SentinelWebMvcConfig();
        //指定 请求方法 POST  GET 等等
        sentinelWebMvcConfig.setHttpMethodSpecify(true);
        //默认使用统一Web上下文   如果希望支持链路关系的流控策略则应该设置为false
        sentinelWebMvcConfig.setWebContextUnify(true);
        // 统一的 BlockException 处理  FlowException(BlockException) 会被 JVM 的 UndeclaredThrowableException 包裹一层  某种原因并不能捕获到异常
//        sentinelWebMvcConfig.setBlockExceptionHandler(new DefaultBlockExceptionHandler());
        // 用来标识来源 可针对性的对特定客户端的请求进行流控   limitApp
//        sentinelWebMvcConfig.setOriginParser(request -> request.getHeader("X-Client"));
 //       sentinelWebMvcConfig.setOriginParser(request -> request.getParameter("app"));

        //对原始的URL进行处理,比如去掉锚点之类的    /foo/bar?a=3#title  ->   /foo/bar?a=3
//        sentinelWebMvcConfig.setUrlCleaner( );
        registry.addInterceptor(new SentinelWebInterceptor(sentinelWebMvcConfig)).addPathPatterns("/**");
    }
}

流控规则中提到的limitApp就是通过setOriginParser 来配置获取策略的。

异常处理

虽然在全局配置中可以进行异常处理,但是经过胖哥测试提供的异常处理还是有些问题的,有时候无法捕捉到BlockException。我们可以通过控制器通知来切面捕获到它:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 捕获BlockException异常.
 */
@Slf4j
@ControllerAdvice
@Order(0)
public class SentinelControllerAdvice {
    /**
     * 异常处理.
     *
     * @param request the request
     * @param e       the e
     * @return the object
     */
    @ExceptionHandler(BlockException.class)
    @ResponseBody
    public ResponseEntity<?> sentinelBlockHandler(HttpServletRequest request, BlockException e) {
        log.warn("Blocked by Sentinel: {}", e.getRule());
        // Return the customized result.
        HashMap<String, Object> map = new HashMap<>();
        map.put("path", request.getServletPath());
        map.put("msg", "limited by sentinel");
        return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body(map);
    }
}

控制台

其实到这里限流功能已经可以使用了。不过配合控制台使用还是很简单的,先下载或者打包控制台的jar文件,通过下面的命令启动:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
java  -Dserver.port=8088     -jar .\sentinel-dashboard-1.8.0.jar

客户端这时就可以移除注解相关的配置和样板代码了,但是拦截器GlobalSentinelWebMvcConfiguration配置务必保留。

客户端 ,例如sentinel-spring-boot.jar注册时,执行命令:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
java -Dcsp.sentinel.dashboard.server=localhost:8088  -Dproject.name=sentinel-app -jar .\sentinel-spring-boot.jar

localhost:8088服务器地址,sentinel-app为客户端名称。

注册完毕后,控制台依旧是白板。务必确保客户端有访问量Sentinel 会在客户端首次调用的时候进行初始化,开始向控制台发送心跳包。你可以访问客户端的接口几次,然后刷新控制台,出现下面的

sentinel dashboard控制台

然后点击 +流控对接口GET:/foo/bar新增流控规则。以下是属性对照图:

FlowRule 属性对照

添加完毕针对GET:/foo/bar的限流就生效了。

控制台的实时流量监控数据只在内存保留 5 分钟,如果需要查历史流量甚至对接 Grafana 平台,就必须将监控数据持久化,网上有很多方案,有需要的可以自行搜索资料。

4.总结

今天对Sentinel的流控功能进行了简单的学习,其实它还可以实现很多有用的功能,熔断降级、热点参数限流、系统自适应限流、黑白名单控制等等。中文文档也算比较完备,有兴趣可以了解。好了今天就到这里,多多关注:码农小胖哥 获取更多的编程干货。

本文DEMO可通过关注公众号:码农小胖哥 回复 sentinel 获取。

参考资料

[1]

关于动态流控规则的描述: https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95

[2]

详情参考控制台文档: https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-09-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农小胖哥 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Android获取经纬度
通常情况下到这里我们已经通过Android自带的API获取到了经纬度,但是有的时候会获取不到,或者我们需要获取连续的点位信息,下面我就来写一下如何获取连续的点位信息,同时我们可以通过这种方式来避免获取点位失败的问题。
longzeqiu
2019/08/14
3.1K0
android中几种定位方式详解
目前,移动端大致通过三种方式来进行设备定位:GPS、基站、wifi。本文就详细的讲解一下这几种定位方式和实现方法。
BennuCTech
2021/12/10
7.7K0
android中几种定位方式详解
Android Osmdroid + 天地图 (二)
  上一篇中我们显示了地图,但是还不够,不满足基本的使用情况,本篇中继续进行功能使用上的完善。
晨曦_LLW
2024/11/28
2750
Android Osmdroid + 天地图 (二)
项目需求讨论 - 定位功能小结
我们知道我们的APP有可能需要获取一些地理位置信息。比如定位用户当前的位置,自动选定城市或者区域等。所以这次做个关于定位的一些总结。
青蛙要fly
2018/08/29
9840
项目需求讨论 - 定位功能小结
Android Geocoder(位置解析)
Android中提供GPS定位服务,同时开发者可以对获得的位置信息进行解析,可以获得位置的详细信息。 1.gps定位 在Eclipse中建立android应用程序。android sdk中提供了locationmanager来获得系统提供的定位服务,可以通过gps、network等定位。通过下面的代码能够获取location对象,而通过location可以获得经纬度信息。 1 LocationManager loactionmanager=(LocationManager) getSystemServic
水击三千
2018/02/27
3.2K0
Android GB28181接入端实时位置订阅和上报之-如何获取当前经纬度
我们在做Android平台GB28181的时候,其中实时位置(MobilePosition)订阅和上报这块,涉及到实时经纬度的获取,特别是执法记录、车载系统的那个等场景,几乎就是标配。
音视频牛哥
2022/09/21
7790
LocationManager的简单使用
当在真机上运行时,弹出定位错误信息,则可能是因为没有打开定位权限,需要自己手动打开,运行成功弹出你所在的城市的位置。
全栈程序员站长
2022/07/22
1K0
LocationManager的简单使用
Google Map
上一章介绍了如何使用Android的GPS来获取设备的定位信息,但这种方式得到的定位信息只不过是一些数字的经度、纬度值,如果这些经度、纬度值不能以更加形象、直观的方式显示出来,对于大部分普通用户而言,这些数据几乎没有任何价值。要想让这些经纬度值“派上”用场,就需要用到本章中介绍到的Google Map服务。在本章中我们首先对Google Map进行简单的介绍,然后介绍Android中进行Google Map开发需要的准备工作,最后通过一系列的案例讲解了在Android中进行Google Map开发的方法及技巧。
张哥编程
2024/12/17
2660
Google Map
Android经典实战之如何获取图片的经纬度以及如何根据经纬度获取对应的地点名称
在Android中,可以通过以下步骤获取图片的经纬度信息以及根据这些经纬度信息获取对应的地点名称。这里主要涉及两部分:从图片中提取地理位置信息(经纬度)和通过地理位置信息获取地点名称。
AntDream
2024/08/09
3150
Android经典实战之如何获取图片的经纬度以及如何根据经纬度获取对应的地点名称
Android Google Maps
  在国内你选择的SDK可以是高德、百度、腾讯等,但在国外,你首选肯定是谷歌,因此要进行Google地图的开发你首先要解决下面三个问题
晨曦_LLW
2024/11/28
2460
Android Google Maps
Kotlin入门(32)网络接口访问
手机上的资源毕竟有限,为了获取更丰富的信息,就得到辽阔的互联网大海上冲浪。对于App自身,也要经常与服务器交互,以便获取最新的数据显示到界面上。这个客户端与服务端之间的信息交互,基本使用HTTP协议进行通信,即App访问服务器的HTTP接口来传输数据。HTTP接口调用在Java代码中可不是一个轻松的活,开发者若用最基础的HttpURLConnection来编码的话,至少要考虑以下场景的处理: 1、HTTP的请求方式是什么,是GET还是POST还是PUT还是DELETE? 2、HTTP的连接超时时间是
aqi00
2019/01/18
1.8K0
校园跑腿小程序通过位置获取当前学校
图片底部中,最下面是当前地址,当前地址可以根据逆地址解析获取,上面的是附近学校(通过城市码和地区码对比),在搜索到其他关联的店铺数据
德宏大魔王
2023/08/08
3460
校园跑腿小程序通过位置获取当前学校
腾讯位置服务开发应用-使用教程,案例分享,知识总结
作为一名在职岗位为【前端开发工程师】的程序员,我开发的应用程序经常需要获取用户位置信息,需要再某些场合下使用展示地图以及地图商的某些地点,需要获取行政区划列表(省市区)以及地址详情信息,需要在地图上规划一条(动态)路线,轨迹回放,小车移动,需要创建信息窗口,用于地点的摘要性信息的展示。
达达前端
2020/12/28
6.5K0
腾讯位置服务开发应用-使用教程,案例分享,知识总结
Arcgis API for Android之GPS定位
先说说写这篇文章的原因吧,在群内讨论的过程中,有人提到了定位的问题,刚好,自己以前在做相关工作的时候做过相关的东西,所以就总结一下,给大家共享出来,由于本人水平有限,bug是在所难免,还望有更高的高人批评指正。废话不多说,直接进入主题。
牛老师讲GIS
2018/10/23
9550
《移动互联网技术》第九章 感知与多媒体: 了解质感设计的基本原则和设计方法
《移动互联网技术》课程是软件工程、电子信息等专业的专业课,主要介绍移动互联网系统及应用开发技术。课程内容主要包括移动互联网概述、无线网络技术、无线定位技术、Android应用开发和移动应用项目实践等五个部分。移动互联网概述主要介绍移动互联网的概况和发展,以及移动计算的特点。无线网络技术部分主要介绍移动通信网络(包括2G/3G/4G/5G技术)、无线传感器网络、Ad hoc网络、各种移动通信协议,以及移动IP技术。无线定位技术部分主要介绍无线定位的基本原理、定位方法、定位业务、数据采集等相关技术。Android应用开发部分主要介绍移动应用的开发环境、应用开发框架和各种功能组件以及常用的开发工具。移动应用项目实践部分主要介绍移动应用开发过程、移动应用客户端开发、以及应用开发实例。 课程的教学培养目标如下: 1.培养学生综合运用多门课程知识以解决工程领域问题的能力,能够理解各种移动通信方法,完成移动定位算法的设计。 2.培养学生移动应用编程能力,能够编写Andorid应用的主要功能模块,并掌握移动应用的开发流程。 3. 培养工程实践能力和创新能力。  通过本课程的学习应达到以下目的: 1.掌握移动互联网的基本概念和原理; 2.掌握移动应用系统的设计原则; 3.掌握Android应用软件的基本编程方法; 4.能正确使用常用的移动应用开发工具和测试工具。
猫头虎
2024/04/08
1550
腾讯位置服务开发应用-使用教程,案例分享,知识总结
作为一名在职岗位为【前端开发工程师】的程序员,我开发的应用程序经常需要获取用户位置信息,需要再某些场合下使用展示地图以及地图商的某些地点,需要获取行政区划列表(省市区)以及地址详情信息,需要在地图上规划一条(动态)路线,轨迹回放,小车移动,需要创建信息窗口,用于地点的摘要性信息的展示。
腾讯位置服务
2021/07/29
3.1K0
腾讯位置服务开发应用-使用教程,案例分享,知识总结
微信小程序获取位置信息
在用户首次进入某页面(需要地理位置授权)时候,在页面进行onLoad,onShow时候,进行调用wx.getLocation要求用户进行授权;以后每次进入该页面时,通过wx.getSetting接口,返回用户授权具体信息。
程思扬
2022/01/10
2.7K0
微信小程序获取位置信息
腾讯位置服务实现路径规划功能demo
这个腾讯位置服务产品初体验小demo能够实现的基本功能有:实现输入(定位)当前位置及终点位置,在地图上规划出两点之间路线,并显示路线所需的距离及路费,确认行程后通过动画模拟车辆在路线上行驶。
腾讯位置服务
2021/08/04
1.2K0
腾讯位置服务实现路径规划功能demo
微信小程序类快递自动填写收发货地址功能
获取当前位置信息或者某地的行政区划信息或者街道信息,实现类似电商平台填写收货地址功能。
腾讯位置服务
2021/03/26
1.7K0
Android6.0蓝牙开发中获取附近低功耗蓝牙设备结果权限问题分析
问题描述: fang_fang_story 近期做一个扫描附近低功耗蓝牙设备获取到rssi并进行一系列的相对的定位的功能。在开发前期一直使用低版本(Android6.0以下)的手机进行测试,没有任何问题。在运行到Android6.0的手机上后,出了一个问题。 每当扫描到附近ble设备并进行回调时都会报错,根本获取不了扫描的结果,报错如下: D/BluetoothLeScanner: onClientRegistered() - status=0 clientIf=5 W/Binder: Caught a
fanfan
2018/01/24
1.7K0
推荐阅读
相关推荐
Android获取经纬度
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档