其他分享
首页 > 其他分享> > 双剑合璧 .Net 结合JSP实现流量安全控制细节处理详解

双剑合璧 .Net 结合JSP实现流量安全控制细节处理详解

作者:互联网

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来保障微服务的稳定性。

 

Sentinel 具有以下特征:

 

「Sentinel 主要特征」

 

 

「Sentinel 开源生态」

 

Sentinel 目前已经针对 Servlet、Dubbo、Spring Boot/Spring Cloud、gRPC 等进行了适配,用户只需引入相应依赖并进行简单配置即可非常方便地享受 Sentinel 的高可用流量防护能力。Sentinel 还为 Service Mesh 提供了集群流量防护的能力。未来 Sentinel 还会对更多常用框架进行适配。

 

Sentinel 分为两个部分:

 

2|0Sentinel 的历史

 

 

3|0Sentinel 核心

 

Sentinel 的使用可以分为两个部分:

 

4|0Sentinel 控制台

 

Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。

官网文档:https://github.com/alibaba/Sentinel/wiki/控制台

 

4|1获取控制台

 

您可以从 release 页面 下载最新版本的控制台 jar 包。

您也可以从最新版本的源码自行构建 Sentinel 控制台:

 

4|2启动控制台

 

启动命令如下,本文使用的是目前最新 1.7.2 版本:

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.2.jar

「注意」:启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本。

其中 -Dserver.port=8080 用于指定 Sentinel 控制台端口为 8080

从 Sentinel 1.6.0 起,Sentinel 控制台引入基本的「登录」功能,默认用户名和密码都是 sentinel。可以参考 鉴权模块文档 配置用户名和密码。

注:若您的应用为 Spring Boot 或 Spring Cloud 应用,您可以通过 Spring 配置文件来指定配置,详情请参考 Spring Cloud Alibaba Sentinel 文档

 

为了方便启动,可以编写一个启动脚本 run.bat

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.2.jar pause

 

4|3访问

 

访问:http://localhost:8080/

 

输入默认用户名和密码 sentinel 点击登录。至此控制台就安装完成了。

 

5|0环境准备

 

sentinel-demo 聚合工程。SpringBoot 2.3.0.RELEASESpring Cloud Hoxton.SR4

 

 

6|0客户端接入控制台

 

控制台启动后,客户端需要按照以下步骤接入到控制台:

 

先把可能需要保护的资源定义好,之后再配置规则。也可以理解为,只要有了资源,我们就可以在任何时候灵活地定义各种流量控制规则。在编码的时候,只需要考虑这个代码是否需要保护,如果需要保护,就将之定义为一个资源。

 

由于我们的项目是 Spring Cloud 项目,所以可以借助官方文档来进行学习。

Spring 官网文档:https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html

Github 文档:https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel

 

6|1添加依赖

 

父工程需要添加如下依赖:

<dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.1.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>

子工程需要添加如下依赖:

<!-- spring cloud alibaba sentinel 依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>

 

配置文件

 

客户端需要启动 Transport 模块来与 Sentinel 控制台进行通信。

order-service-rest 的 application.yml

spring: cloud: # 配置 Sentinel sentinel: transport: port: 8719 dashboard: localhost:8080

这里的 spring.cloud.sentinel.transport.port 端口配置会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了一个限流规则,会把规则数据 push 给这个 Http Server 接收,Http Server 再将规则注册到 Sentinel 中。

 

初始化客户端

 

「确保客户端有访问量」,Sentinel 会在「客户端首次调用的时候」进行初始化,开始向控制台发送心跳包。

简单的理解就是:访问一次客户端,Sentinel 即可完成客户端初始化操作,并持续向控制台发送心跳包。

 

访问

 

多次访问:http://localhost:9090/order/1 然后查看控制台实时监控结果如下:

 

6|2定义资源

 

「资源」 是 Sentinel 中的核心概念之一。我们说的资源,可以是任何东西,服务,服务里的方法,甚至是一段代码。最常用的资源是我们代码中的 Java 方法。Sentinel 提供了 @SentinelResource 注解用于定义资源,并提供了 AspectJ 的扩展用于自动定义资源、处理 BlockException 等。

只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。

官网文档:https://github.com/alibaba/Sentinel/wiki/如何使用#定义资源

 

注解支持

 

官网文档:https://github.com/alibaba/Sentinel/wiki/注解支持

OrderServiceImpl.java

package com.example.service.impl; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.example.pojo.Order; import com.example.service.OrderService; import com.example.service.ProductService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Arrays; @Service public class OrderServiceImpl implements OrderService { @Autowired private ProductService productService; /** * 根据主键和订单编号查询订单 * * @param id * @param orderNo * @return */ @Override @SentinelResource(value = "selectOrderByIdAndOrderNo", blockHandler = "selectOrderByIdAndOrderNoBlockHandler", fallback = "selectOrderByIdAndOrderNoFallback") public Order selectOrderByIdAndOrderNo(Integer id, String orderNo) { return new Order(id, orderNo, "中国", 2666D, Arrays.asList(productService.selectProductById(1))); } // 服务流量控制处理,参数最后多一个 BlockException,其余与原函数一致。 public Order selectOrderByIdAndOrderNoBlockHandler(Integer id, String orderNo, BlockException ex) { // Do some log here. ex.printStackTrace(); return new Order(id, "服务流量控制处理-托底数据", "中国", 2666D, Arrays.asList(productService.selectProductById(1))); } // 服务熔断降级处理,函数签名与原函数一致或加一个 Throwable 类型的参数 public Order selectOrderByIdAndOrderNoFallback(Integer id, String orderNo, Throwable throwable) { System.out.println("order-service 服务的 selectOrderById 方法出现异常,异常信息如下:" + throwable); return new Order(id, "服务熔断降级处理-托底数据", "中国", 2666D, Arrays.asList(productService.selectProductById(1))); } }

 

ProductServiceImpl.java

package com.example.service.impl; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.example.pojo.Product; import com.example.service.ProductService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; /** * 商品管理 */ @Service public class ProductServiceImpl implements ProductService { @Autowired private RestTemplate restTemplate; /** * 根据主键查询商品 * * @param id * @return */ @SentinelResource(value = "selectProductById", blockHandler = "selectProductByIdBlockHandler", fallback = "selectProductByIdFallback") @Override public Product selectProductById(Integer id) { return restTemplate.getForObject("http://product-service/product/" + id, Product.class); } // 服务流量控制处理,参数最后多一个 BlockException,其余与原函数一致。 public Product selectProductByIdBlockHandler(Integer id, BlockException ex) { // Do some log here. ex.printStackTrace(); return new Product(id, "服务流量控制处理-托底数据", 1, 2666D); } // 服务熔断降级处理,函数签名与原函数一致或加一个 Throwable 类型的参数 public Product selectProductByIdFallback(Integer id, Throwable throwable) { System.out.println("product-service 服务的 selectProductById 方法出现异常,异常信息如下:" + throwable); return new Product(id, "服务熔断降级处理-托底数据", 1, 2666D); } }

注意:注解方式埋点不支持 private 方法。

 

@SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项。 @SentinelResource 注解包含以下属性:

注:1.6.0 之前的版本 fallback 函数只针对降级异常(DegradeException)进行处理,「不能针对业务异常进行处理」

特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。若未配置 blockHandlerfallback 和 defaultFallback,则被限流降级时会将 BlockException 「直接抛出」(若方法本身未定义 throws BlockException 则会被 JVM 包装一层 UndeclaredThrowableException)。

从 1.4.0 版本开始,注解方式定义资源支持自动统计业务异常,无需手动调用 Tracer.trace(ex) 来记录业务异常。Sentinel 1.4.0 以前的版本需要自行调用 Tracer.trace(ex) 来记录业务异常。

 

6|3定义规则

 

Sentinel 的所有规则都可以在「内存态中动态地查询及修改,修改之后立即生效」。同时 Sentinel 也提供相关 API,供您来定制自己的规则策略。

Sentinel 支持以下几种规则:「流量控制规则」「熔断降级规则」「热点参数规则」「系统保护规则」「来源访问控制规则」

官网文档:https://github.com/alibaba/Sentinel/wiki/如何使用#规则的种类

 

流量控制规则

 

添加流量控制规则

 

选择 簇点链路 找到定义好的资源 selectProductById 并点击对应的规则按钮进行设置。

 

比如我们设置一个流量控制规则,定义资源访问的 QPS 为 1(每秒能处理查询数目)。

 

测试

 

快速刷新页面多次访问:http://localhost:9090/order/idAndOrderNo?id=1&orderNo=order-001 结果如下:

 

熔断降级规则

 

模拟服务出错

 

修改 order-service-rest 项目中的核心代码,模拟服务出错。

package com.example.service.impl; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.example.pojo.Product; import com.example.service.ProductService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; /** * 商品管理 */ @Service public class ProductServiceImpl implements ProductService { @Autowired private RestTemplate restTemplate; /** * 根据主键查询商品 * * @param id * @return */ @SentinelResource(value = "selectProductById", blockHandler = "selectProductByIdBlockHandler", fallback = "selectProductByIdFallback") @Override public Product selectProductById(Integer id, String productName) { // 模拟查询主键为 1 的商品信息会导致异常 if (1 == id) throw new RuntimeException("查询主键为 1 的商品信息导致异常"); return restTemplate.getForObject("http://product-service/product/" + id, Product.class); } // 服务流量控制处理,参数最后多一个 BlockException,其余与原函数一致。 public Product selectProductByIdBlockHandler(Integer id, BlockException ex) { // Do some log here. ex.printStackTrace(); return new Product(id, "服务流量控制处理-托底数据", 1, 2666D); } // 服务熔断降级处理,函数签名与原函数一致或加一个 Throwable 类型的参数 public Product selectProductByIdFallback(Integer id, Throwable throwable) { System.out.println("product-service 服务的 selectProductById 方法出现异常,异常信息如下:" + throwable); return new Product(id, "服务熔断降级处理-托底数据", 1, 2666D); } }

 

添加熔断降级规则

 

熔断降级规则支持相应时间、异常比例、异常数三种方式。

 

测试

 

访问:http://localhost:9090/order/idAndOrderNo?id=1&orderNo=order-001 结果如下:

 

热点参数规则

 

热点参数规则是一种更细粒度的流控规则,它允许将规则具体到参数上。比如 selectOrderByIdAndOrderNo 方法有两个参数,我们对第一个参数进行限流,对第二个参数不限流。

 

添加热点参数规则

 

选择 簇点链路 找到定义好的资源 selectOrderByIdAndOrderNo 并点击对应的规则按钮进行设置。

 

设置热点参数规则,定义对资源的第一个参数的 QPS 为 1(每秒能处理查询数目)。

 

测试

 

分别用两个参数访问,会发现只对第一个参数限流了。

快速刷新页面多次访问:http://localhost:9090/order/idAndOrderNo?id=1 被限流。

快速刷新页面多次访问:http://localhost:9090/order/idAndOrderNo?orderNo=order-001 正常访问。

 

授权规则

 

很多时候,我们需要根据调用来源来判断该次请求是否被允许,这时候可以使用 Sentinel 的来源访问控制的功能。来源访问控制根据资源的请求来源(origin)限制资源是否通过。

Sentinel 提供了 RequestOriginParser 接口来处理来源。一旦 Sentinel 保护的接口资源被访问,Sentinel 就会调用 RequestOriginParser 的实现类去解析访问来源。

 

自定义来源处理规则

 

package com.example.sentinel; import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; /** * 自定义来源处理规则 */ @Component public class MyRequestOriginParser implements RequestOriginParser { @Override public String parseOrigin(HttpServletRequest request) { return request.getParameter("userName"); } }

 

新增授权规则

 

下图配置的意思是资源 selectOrderByIdAndOrderNo 只有 userName=zhangsan 的用户无法访问(黑名单)

 

测试

 

快速刷新页面多次访问:http://localhost:9090/order/idAndOrderNo?id=1&userName=zhangsan 被限流。

快速刷新页面多次访问:http://localhost:9090/order/idAndOrderNo?id=1&userName=lisi 正常访问。

 

系统保护规则

 

系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体 LOAD、RT、线程数、入口 QPS 和 CPU 使用率五个维度监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量(进入应用的流量)生效。

 

动态规则扩展

 

官网文档:

 

SentinelProperties 内部提供了 TreeMap 类型的 datasource 属性用于配置数据源信息。支持:

 

文件配置规则

 

Sentinel 支持通过本地文件加载规则配置,使用方式如下(限流规则作为演示):

spring: cloud: # 配置 Sentinel sentinel: datasource: ds1: file: file: classpath:flowRule.json data-type: json rule-type: flow

 

flowRule.json 对应 com.alibaba.csp.sentinel.slots.block.RuleConstant 各属性。

[ { "resource": "selectProductList", "count": 1, "grade": 1, "limitApp": "default", "strategy": 0, "controlBehavior": 0 } ]

 

重要属性:

Field说明默认值
resource 资源名,资源名是限流规则的作用对象  
count 限流阈值  
grade 限流阈值类型,QPS 模式(1)或并发线程数模式(0) QPS 模式
limitApp 流控针对的调用来源 default,代表不区分调用来源
strategy 调用关系限流策略:直接、链路、关联 根据资源本身(直接)
controlBehavior 流控效果(直接拒绝 / 排队等待 / 慢启动模式),不支持按调用关系限流 直接拒绝
clusterMode 是否集群限流

 

访问客户端以后,刷新控制台,查看流控规则如下:

 

7|0RestTemplate 支持

 

Spring Cloud Alibaba Sentinel 支持对 RestTemplate 调用的服务进行服务保护。需要在构造 RestTemplate Bean 时添加 @SentinelRestTemplate 注解。

 

7|1启动类

 

OrderServiceRestApplication.java

package com.example; import com.alibaba.cloud.sentinel.annotation.SentinelRestTemplate; import com.example.exception.ExceptionUtil; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication public class OrderServiceRestApplication { @Bean @LoadBalanced @SentinelRestTemplate(blockHandler = "handleException", blockHandlerClass = ExceptionUtil.class, fallback = "fallback", fallbackClass = ExceptionUtil.class) public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(OrderServiceRestApplication.class, args); } }

 

7|2服务熔断处理类

 

ExceptionUtil.java 必须使用静态方法。

package com.example.exception; import com.alibaba.cloud.sentinel.rest.SentinelClientHttpResponse; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.fastjson.JSON; import com.example.pojo.Product; import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpResponse; public class ExceptionUtil { // 服务流量控制处理 public static ClientHttpResponse handleException(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException exception) { exception.printStackTrace(); return new SentinelClientHttpResponse( JSON.toJSONString(new Product(1, "服务流量控制处理-托底数据", 1, 2666D))); } // 服务熔断降级处理 public static ClientHttpResponse fallback(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException exception) { exception.printStackTrace(); return new SentinelClientHttpResponse( JSON.toJSONString(new Product(1, "服务熔断降级处理-托底数据", 1, 2666D))); } }

 

7|3访问

 

控制台设置流量控制规则,定义资源访问的 QPS 为 1(每秒能处理查询数目)。

快速刷新页面多次访问:http://localhost:9090/order/1 结果如下:

 

8|0OpenFeign 支持

 

8|1添加依赖

 

<!-- spring cloud alibaba sentinel 依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <!-- spring cloud openfeign 依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>

 

8|2开启 Sentinel

 

server: port: 9091 # 端口 spring: application: name: order-service-feign # 应用名称 cloud: # 配置 Nacos 注册中心 nacos: discovery: enabled: true # 如果不想使用 Nacos 进行服务注册和发现,设置为 false 即可 server-addr: 127.0.0.1:8848 # Nacos 服务器地址 # 配置 Sentinel sentinel: transport: port: 8719 dashboard: localhost:8080 # feign 开启 sentinel 支持 feign: sentinel: enabled: true

 

8|3熔断降级

 

ProductServiceFallback.java

package com.example.fallback; import com.example.pojo.Product; import com.example.service.ProductService; import feign.hystrix.FallbackFactory; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; /** * 服务熔断降级处理可以捕获异常 */ @Slf4j @Component public class ProductServiceFallbackFactory implements FallbackFactory<ProductService> { @Override public ProductService create(Throwable throwable) { return new ProductService() { @Override public Product selectProductById(Integer id) { // 获取日志,在需要捕获异常的方法中进行处理 log.error("product-service 服务的 selectProductById 方法出现异常,异常信息如下:" + throwable); return new Product(id, "托底数据", 1, 2666D); } }; } }

 

8|4消费服务

 

ProductService.java

package com.example.service; import com.example.fallback.ProductServiceFallbackFactory; import com.example.pojo.Product; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; // 声明需要调用的服务 @FeignClient(value = "product-service", fallbackFactory = ProductServiceFallbackFactory.class) public interface ProductService { /** * 根据主键查询商品 * * @param id * @return */ @GetMapping("/product/{id}") Product selectProductById(@PathVariable("id") Integer id); }

 

OrderServiceImpl.java

package com.example.service.impl; import com.example.pojo.Order; import com.example.service.OrderService; import com.example.service.ProductService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Arrays; @Service public class OrderServiceImpl implements OrderService { @Autowired private ProductService productService; /** * 根据主键查询订单 * * @param id * @return */ @Override public Order selectOrderById(Integer id) { return new Order(id, "order-001", "中国", 2666D, Arrays.asList(productService.selectProductById(1))); } }

 

8|5控制层

 

package com.example.controller; import com.example.pojo.Order; import com.example.service.OrderService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/order") public class OrderController { @Autowired private OrderService orderService; /** * 根据主键查询订单 * * @param id * @return */ @GetMapping("/{id}") public Order selectOrderById(@PathVariable("id") Integer id) { return orderService.selectOrderById(id); } }

 

8|6启动类

 

package com.example; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; // 开启 FeignClients 注解 @EnableFeignClients // 开启 @EnableDiscoveryClient 注解,当前版本默认会开启该注解 //@EnableDiscoveryClient @SpringBootApplication public class OrderServiceFeignApplication { public static void main(String[] args) { SpringApplication.run(OrderServiceFeignApplication.class, args); } }

 

8|7测试

 

控制台信息如下:

 

添加流量控制规则,定义资源访问的 QPS 为 1(每秒能处理查询数目)。

 

快速刷新页面多次访问:http://localhost:9091/order/1 结果如下:

 

或者关闭服务提供者,访问:http://localhost:9091/order/1 结果如下:

 

9|0Gateway 支持

 

Sentinel 支持对 Spring Cloud Gateway、Netflix Zuul 等主流的 API Gateway 进行限流。

官网文档:

 

9|1创建项目

 

创建 gateway-server-sentinel 项目。

 

9|2添加依赖

 

单独使用添加 sentinel-spring-cloud-gateway-adapter 依赖即可。

若想跟 Sentinel Starter 配合使用,需要加上 spring-cloud-alibaba-sentinel-gateway 依赖来让 spring-cloud-alibaba-sentinel-gateway 模块里的 Spring Cloud Gateway 自动化配置类生效。

同时请将 spring.cloud.sentinel.filter.enabled 配置项置为 false(若在网关流控控制台上看到了 URL 资源,就是此配置项没有置为 false)。

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <!-- 继承父依赖 --> <parent> <artifactId>gateway-demo</artifactId> <groupId>com.example</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>gateway-server-sentinel</artifactId> <!-- 项目依赖 --> <dependencies> <!-- spring cloud gateway 依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!-- spring cloud alibaba nacos discovery 依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- 单独使用 --> <!-- sentinel gateway adapter 依赖 --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId> </dependency> <!-- 和 Sentinel Starter 配合使用 --> <!-- <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId> </dependency> --> </dependencies> </project>

 

9|3配置文件

 

server: port: 9001 # 端口 spring: application: name: gateway-server-sentinel # 应用名称 cloud: sentinel: filter: enabled: false gateway: discovery: locator: # 是否与服务发现组件进行结合,通过 serviceId 转发到具体服务实例。 enabled: true # 是否开启基于服务发现的路由规则 lower-case-service-id: true # 是否将服务名称转小写 # 路由规则 routes: - id: order-service # 路由 ID,唯一 uri: lb://order-service # 目标 URI,lb:// 根据服务名称从注册中心获取服务请求地址 predicates: # 断言(判断条件) # 匹配对应 URI 的请求,将匹配到的请求追加在目标 URI 之后 - Path=/order/**

 

9|4限流规则配置类

 

使用时只需注入对应的 SentinelGatewayFilter 实例以及 SentinelGatewayBlockExceptionHandler 实例即可。

GatewayConfiguration.java

package com.example.config; import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule; import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager; import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter; import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler; import org.springframework.beans.factory.ObjectProvider; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.web.reactive.result.view.ViewResolver; import javax.annotation.PostConstruct; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; /** * 限流规则配置类 */ @Configuration public class GatewayConfiguration { private final List<ViewResolver> viewResolvers; private final ServerCodecConfigurer serverCodecConfigurer; /** * 构造器 * * @param viewResolversProvider * @param serverCodecConfigurer */ public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer) { this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList); this.serverCodecConfigurer = serverCodecConfigurer; } /** * 限流异常处理器 * * @return */ @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() { // Register the block exception handler for Spring Cloud Gateway. return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer); } /** * 限流过滤器 * * @return */ @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public GlobalFilter sentinelGatewayFilter() { return new SentinelGatewayFilter(); } /** * Spring 容器初始化的时候执行该方法 */ @PostConstruct public void doInit() { // 加载网关限流规则 initGatewayRules(); } /** * 网关限流规则 */ private void initGatewayRules() { Set<GatewayFlowRule> rules = new HashSet<>(); /* resource:资源名称,可以是网关中的 route 名称或者用户自定义的 API 分组名称 count:限流阈值 intervalSec:统计时间窗口,单位是秒,默认是 1 秒 */ rules.add(new GatewayFlowRule("order-service") .setCount(3) // 限流阈值 .setIntervalSec(60)); // 统计时间窗口,单位是秒,默认是 1 秒 // 加载网关限流规则 GatewayRuleManager.loadRules(rules); } }

 

9|5启动类

 

GatewayServerSentinelApplication.java

package com.example; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; // 开启 EurekaClient 注解,目前版本如果配置了 Eureka 注册中心,默认会开启该注解 //@EnableEurekaClient @SpringBootApplication public class GatewayServerSentinelApplication { public static void main(String[] args) { SpringApplication.run(GatewayServerSentinelApplication.class, args); } }

 

9|6访问

 

多次访问:http://localhost:9001/order/1 结果如下:

接口 BlockRequestHandler 的默认实现为 DefaultBlockRequestHandler,当触发限流时会返回默认的错误信息:Blocked by Sentinel: FlowException。我们可以通过 GatewayCallbackManager 定制异常提示信息。

标签:alibaba,sentinel,双剑合,import,Sentinel,JSP,Net,com,id
来源: https://www.cnblogs.com/yiluba/p/13099432.html