◆Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助您保障微服务的稳定性
◆资源:可以是Java应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码
◆规则:围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则;且所有规则可以动态实时调整
◆顾名思义,限流就是限制流量,控制系统的QPS,从而达到保护系统的目的
◆为什么 需要限流( 搞清楚这些,再去决定你的系统需不需要限流)
1.平台用户增长过快
2.热点事件、热点接口、热点Key
3.恶意请求
这种算法就是指定规定时间内允许接收多少请求,但是这种算法有两个漏洞:
第一,假设每分钟允许100个请求,请求全部集中在第一个一分钟最后和第二个一分钟的开始,就会有瞬间两百个请求。
第一,所有的请求都发生在一瞬间。
往桶中以任意速率流入水,以一定速率流出水,当水超过桶流量则丢弃,因为桶容量是不变的,保证了整体的速率;
是对漏桶算法的改进,漏桶算法能够限制请求调用的速率,而令牌桶算法能够在限制调用的平均速率的同时还允许一定程度的突发调用
1.所有的请求在处理之前都需要拿到一个可用的令牌才会被处理
2.根据限流大小,设置按照一定的速率往桶里添加令牌
3.桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝
4.请求到达后需要获取令牌桶中令牌
5.令牌桶保持有最低限额,保证足够的限流
◆Sentinel 提供一个轻量级 的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能
1.下载控制台Jar包: Releases · alibaba/Sentinel · GitHub
2. java -Dserver.port=7777 -Dcsp.sentinel.dashboard.server=localhost:7777 -Dproject.name=shuai-sentinel-dashboard -jar sentinel-dashboard-1.8.3.jar
3.从Sentinel 1 .6.0起,Sentinel Dashboard引入了基本的登录功能,默认的用户名密码都是sentinel
◆查看机器列表以及健康情况:收集Sentinel 客户端发送的心跳包,用于判断机器是否在线
◆监控(单机和集群聚合):通过Sentinel客户端暴露的监控API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控
◆规则管理和推送:统一管理推送规则
SpringCloud Alibaba Sentinel的限流功能
◆服务端需要根据系统的处理能力对流量进行控制,Sentinel作为一个调配器,可以根据需要把随机的请求调整成合适的形状
◆资源的调用关系,例如资源的调用链路,资源和资源之间的关系
◆运行指标, 例如QPS、线程池、系统负载等
◆控制的效果,例如直接限流、冷启动、排队等
创建Sentinel的微服务
首先引入依赖
e-commerce-springcloud
com.taluohui.ecommerce
1.0-SNAPSHOT
4.0.0
e-commerce-sentinel-client
1.0-SNAPSHOT
jar
8
8
e-commerce-sentinel-client
Sentinel Client
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
com.taluohui.ecommerce
e-commerce-mvc-config
1.0-SNAPSHOT
${artifactId}
org.springframework.boot
spring-boot-maven-plugin
repackage
配置文件
server:
port: 8100
servlet:
context-path: /ecommerce-sentinel-client
spring:
application:
name: e-commerce-sentinel-client # 应用名称也是构成 Nacos 配置管理 dataId 字段的一部分 (当 config.prefix 为空时)
cloud:
nacos:
# 服务注册发现
discovery:
enabled: true # 如果不想使用 Nacos 进行服务注册和发现, 设置为 false 即可
server-addr: 1.15.247.9:8848
# server-addr: 127.0.0.1:8848,127.0.0.1:8849,127.0.0.1:8850 # Nacos 服务器地址
namespace: 22d40198-8462-499d-a7fe-dbb2da958648
metadata:
management:
context-path: ${server.servlet.context-path}/actuator
sentinel:
# 配置 sentinel dashboard 地址
transport:
dashboard: 1.15.247.9:7777
port: 8719 # 会在应用对应的机器上启动一个 Http Server, 该 Server 会与 Sentinel 控制台做交互
# 服务启动直接建立心跳连接
eager: true
# 暴露端点
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: always
创建入口文件
/**
* Sentinel 集成到 SpringCloud 工程中
* */
@EnableDiscoveryClient
@SpringBootApplication
public class SentinelClientApplication {
public static void main(String[] args) {
SpringApplication.run(SentinelClientApplication.class, args);
}
}
后面会将流控规则写在配置文件中
/**
* 流控规则硬编码的 Controller
* */
@Slf4j
@RestController
@RequestMapping("/code")
public class FlowRuleCodeController {
/**
* 初始化流控规则
* */
@PostConstruct
public void init() {
// 流控规则集合
List flowRules = new ArrayList<>();
// 创建流控规则
FlowRule flowRule = new FlowRule();
// 设置流控规则 QPS, 限流阈值类型 (QPS, 并发线程数)
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 流量控制手段
flowRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
// 设置受保护的资源
flowRule.setResource("flowRuleCode");
// 设置受保护的资源的阈值
flowRule.setCount(1);
flowRules.add(flowRule);
// 加载配置好的规则
FlowRuleManager.loadRules(flowRules);
}
/**
* 采用硬编码限流规则的 Controller 方法
* */
@GetMapping("/flow-rule")
@SentinelResource(value = "flowRuleCode")
public CommonResponse flowRuleCode() {
log.info("request flowRuleCode");
return new CommonResponse<>(0, "", "shuai-ecommerce");
}
/**
* 采用硬编码限流规则的 Controller 方法
* */
@GetMapping("/flow-rule")
// @SentinelResource(value = "flowRuleCode")
@SentinelResource(value = "flowRuleCode", blockHandler = "handleException")
public CommonResponse flowRuleCode() {
log.info("request flowRuleCode");
return new CommonResponse<>(0, "", "shuai-ecommerce");
}
/**
* 当限流异常抛出时, 指定调用的方法
* 是一个兜底策略
* */
public CommonResponse handleException(BlockException exception) {
log.error("has block exception: [{}]", JSON.toJSONString(exception.getRule()));
return new CommonResponse<>(
-1,
"flow rule exception",
exception.getClass().getCanonicalName()
);
}
/**
* 自定义通用的限流处理逻辑
* */
@Slf4j
public class QinyiBlockHandler {
/**
* 通用限流处理方法
* 这个方法必须是 static 的
* */
public static CommonResponse qinyiHandleBlockException(BlockException exception) {
log.error("trigger qinyi block handler: [{}], [{}]",
JSON.toJSONString(exception.getRule()), exception.getRuleLimitApp());
return new CommonResponse<>(
-1,
"flow rule trigger block exception",
null
);
}
}
同时接口方法上的注解也需要改变
/**
* 采用硬编码限流规则的 Controller 方法
* */
@GetMapping("/flow-rule")
// @SentinelResource(value = "flowRuleCode")
// @SentinelResource(value = "flowRuleCode", blockHandler = "handleException")
@SentinelResource(
value = "flowRuleCode", blockHandler = "qinyiHandleBlockException",
blockHandlerClass = QinyiBlockHandler.class
)
public CommonResponse flowRuleCode() {
log.info("request flowRuleCode");
return new CommonResponse<>(0, "", "imooc-qinyi-ecommerce");
}
/**
* 基于 Sentinel 控制台配置流控规则
* Sentinel 是懒加载的, 先去访问一下, 就可以在 Sentinel Dashboard 看到了
* */
@Slf4j
@RestController
@RequestMapping("/dashboard")
public class RateLimitController {
/**
* 在 dashboard 中 "流控规则" 中按照资源名称新增流控规则
* */
@GetMapping("/by-resource")
@SentinelResource(
value = "byResource",
blockHandler = "qinyiHandleBlockException",
blockHandlerClass = QinyiBlockHandler.class
)
public CommonResponse byResource() {
log.info("coming in rate limit controller by resource");
return new CommonResponse<>(0, "", "byResource");
}
/**
* 在 "簇点链路" 中给 url 添加流控规则
* */
@GetMapping("/by-url")
@SentinelResource(value = "byUrl")
public CommonResponse byUrl() {
log.info("coming in rate limit controller by url");
return new CommonResponse<>(0, "", "byUrl");
}
}
在 dashboard 中 "流控规则" 中按照资源名称新增流控规则
在 "簇点链路" 中给 url 添加流控规则
◆Sentinel 支持对RestTemplate服务调用进行保护,实现流控降级和异常降级
在配置文件中开启对@SentinelRestTemplate的支持
# 开启或关闭 @SentinelRestTemplate 注解
resttemplate:
sentinel:
enabled: true
对RestTemplate 做一些包装
/**
* 开启服务间的调用保护, 需要给 RestTemplate 做一些包装
* */
@Slf4j
@Configuration
public class SentinelConfig {
/**
* 包装 RestTemplate
* */
@Bean
@SentinelRestTemplate(
fallback = "handleFallback", fallbackClass = RestTemplateExceptionUtil.class,
blockHandler = "handleBlock", blockHandlerClass = RestTemplateExceptionUtil.class
)
public RestTemplate restTemplate() {
return new RestTemplate(); // 可以对其做一些业务相关的配置
}
}
RestTemplate 在限流或异常时的兜底方法
/**
* RestTemplate 在限流或异常时的兜底方法
* */
@Slf4j
public class RestTemplateExceptionUtil {
/**
* 限流后的处理方法
* */
public static SentinelClientHttpResponse handleBlock(HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution,
BlockException ex) {
log.error("Handle RestTemplate Block Exception: [{}], [{}]",
request.getURI().getPath(), ex.getClass().getCanonicalName());
return new SentinelClientHttpResponse(
JSON.toJSONString(new JwtToken("shuai-block"))
);
}
/**
* 异常降级之后的处理方法
* */
public static SentinelClientHttpResponse handleFallback(HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution,
BlockException ex) {
log.error("Handle RestTemplate Fallback Exception: [{}], [{}]",
request.getURI().getPath(), ex.getClass().getCanonicalName());
return new SentinelClientHttpResponse(
JSON.toJSONString(new JwtToken("qinyi-imooc-block"))
);
}
}
使用 Sentinel 保护 RestTemplate 服务间调用
/**
* 使用 Sentinel 保护 RestTemplate 服务间调用
* */
@Slf4j
@RestController
@RequestMapping("/sentinel-rest-template")
public class SentinelRestTemplateController {
private final RestTemplate restTemplate;
public SentinelRestTemplateController(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
/**
* 从授权服务中获取 JwtToken
* 1. 流控降级:
* 是针对于簇点链路中的 http://127.0.0.1:7000/ecommerce-authority-center/authority/token
* 2. 容错降级: 对于服务不可用时不能生效
* */
@PostMapping("/get-token")
public JwtToken getTokenFromAuthorityService(
@RequestBody UsernameAndPassword usernameAndPassword) {
String requestUrl =
"http://127.0.0.1:7000/ecommerce-authority-center/authority/token";
log.info("RestTemplate request url and body: [{}], [{}]",
requestUrl, JSON.toJSONString(usernameAndPassword));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return restTemplate.postForObject(
requestUrl,
new HttpEntity<>(JSON.toJSONString(usernameAndPassword), headers),
JwtToken.class
);
}
}
首先将上面的RestTemplate的@SentinelRestTemplate注解注释掉
提供熔断降级策略
/**
* Sentinel 回退降级的兜底策略
* 都需要是静态方法
* */
@Slf4j
public class QinyiFallbackHandler {
/**
* getTokenFromAuthorityService 方法的 fallback
* */
public static JwtToken getTokenFromAuthorityServiceFallback(
UsernameAndPassword usernameAndPassword
) {
log.error("get token from authority service fallback: [{}]",
JSON.toJSONString(usernameAndPassword));
return new JwtToken("imooc-qinyi-fallback");
}
/**
* ignoreException 方法的 fallback
* */
public static JwtToken ignoreExceptionFallback(Integer code) {
log.error("ignore exception input code: [{}] has trigger exception", code);
return new JwtToken("imooc-qinyi-fallback");
}
}
在controller中使用熔断降级策略
@SentinelResource中的exceptionsToIgnore = { NullPointerException.class },可以忽略一部分异常,让服务不走兜底策略,直接报错。
/**
* Sentinel 提供容错降级的功能
* */
@SuppressWarnings("all")
@Slf4j
@RestController
@RequestMapping("/sentinel-fallback")
public class SentinelFallbackController {
/** 注入没有增强的 RestTemplate */
private final RestTemplate restTemplate;
public SentinelFallbackController(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@PostMapping("/get-token")
@SentinelResource(
value = "getTokenFromAuthorityService",
fallback = "getTokenFromAuthorityServiceFallback",
fallbackClass = { QinyiFallbackHandler.class }
)
public JwtToken getTokenFromAuthorityService(
@RequestBody UsernameAndPassword usernameAndPassword) {
String requestUrl =
"http://127.0.0.1:7000/ecommerce-authority-center/authority/token";
log.info("RestTemplate request url and body: [{}], [{}]",
requestUrl, JSON.toJSONString(usernameAndPassword));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return restTemplate.postForObject(
requestUrl,
new HttpEntity<>(JSON.toJSONString(usernameAndPassword), headers),
JwtToken.class
);
}
/**
* 让 Sentinel 忽略一些异常
* */
@GetMapping("/ignore-exception")
@SentinelResource(
value = "ignoreException",
fallback = "ignoreExceptionFallback",
fallbackClass = { QinyiFallbackHandler.class },
exceptionsToIgnore = { NullPointerException.class }
)
public JwtToken ignoreException(@RequestParam Integer code) {
if (code % 2 == 0) {
throw new NullPointerException("yout input code is: " + code);
}
return new JwtToken("qinyi-imooc");
}
}
首先在配置文件中添加对用的配置(这里只是最简单的openfeign的配置,如果需要更详细的配置openfeign,请参考前面openfeign的章节。
# 打开 Sentinel 对 Feign 的支持
feign:
sentinel:
enabled: true
引入依赖
org.springframework.cloud
spring-cloud-starter-openfeign
在入口文件中添加注解@EnableFeignClients
通过 Sentinel 对 OpenFeign 实现熔断降级
/**
* 通过 Sentinel 对 OpenFeign 实现熔断降级
* */
@FeignClient(
value = "e-commerce-imooc",
fallback = SentinelFeignClientFallback.class
)
public interface SentinelFeignClient {
@RequestMapping(value = "qinyi", method = RequestMethod.GET)
CommonResponse getResultByFeign(@RequestParam Integer code);
}
Sentinel 对 OpenFeign 接口的降级策略
/**
* Sentinel 对 OpenFeign 接口的降级策略
* */
@Slf4j
@Component
public class SentinelFeignClientFallback implements SentinelFeignClient {
@Override
public CommonResponse getResultByFeign(Integer code) {
log.error("request supply for test has some error: [{}]", code);
return new CommonResponse<>(
-1,
"sentinel feign fallback",
"input code: "+ code
);
}
}
OpenFeign 集成 Sentinel 实现熔断降级
/**
* OpenFeign 集成 Sentinel 实现熔断降级
* */
@Slf4j
@RestController
@RequestMapping("/sentinel-feign")
public class SentinelFeignController {
private final SentinelFeignClient sentinelFeignClient;
public SentinelFeignController(SentinelFeignClient sentinelFeignClient) {
this.sentinelFeignClient = sentinelFeignClient;
}
/**
* 通过 Feign 接口去获取结果
* */
@GetMapping("/result-by-feign")
public CommonResponse getResultByFeign(@RequestParam Integer code) {
log.info("coming in get result by feign: [{}]", code);
return sentinelFeignClient.getResultByFeign(code);
}
}
◆Sentinel Dashboard将规则保存在内存中,重启之后就会丢失,所以,考虑使用外部持久化方案
◆在Nacos中创建规则,Nacos会推送到客户端
◆Sentinel Dashboard也会从Nacos去获取配置信息
首先在nacos中添加新的配置
这是一个json格式的数组
[
{
"resource": "byResource",
"LimitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
还需要在项目中添加依赖
com.alibaba.csp
sentinel-datasource-nacos
配置数据源
datasource:
# 名称任意, 代表数据源
ds:
nacos:
# NacosDataSourceProperties.java 中定义
server-addr: ${spring.cloud.nacos.discovery.server-addr}
dataId: ${spring.application.name}-sentinel
namespace: ${spring.cloud.nacos.discovery.namespace}
groupId: DEFAULT_GROUP
data-type: json
# 规则类型: com.alibaba.cloud.sentinel.datasource.RuleType
# FlowRule 就是限流规则
rule-type: flow
这时候在sentinel的工作台上就可以看到
一般情况下,所有的外部请求应该都是通过网关进入,所以限流也应该在网关部分进行。
首先在网关微服务中添加依赖
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
com.alibaba.cloud
spring-cloud-alibaba-sentinel-gateway
添加配置
spring:
cloud:
sentinel:
eager: true
transport:
port: 8720
dashboard: 127.0.0.1:7777
启动sentinel,这次要-Dcsp.sentinel.app.type=1设置网关支持
java -Dcsp.sentinel.app.type=1 -Dserver.port=7777 -Dcsp.sentinel.dashboard.server=localhost:7777 -Dproject.name=e-commerce-gateway -jar sentinel-dashboard-1.8.3.jar
(对"e-commerce-nacos-client"服务进行限流,每60秒只能进行3次访问QPS)
/**
* Gateway 集成 Sentinel 实现限流
* */
@Slf4j
@Configuration
public class SentinelGatewayConfiguration {
/** 视图解析器 */
private final List viewResolvers;
/** HTTP 请求和响应数据的编解码配置 */
private final ServerCodecConfigurer serverCodecConfigurer;
/**
* 构造方法
* */
public SentinelGatewayConfiguration(
ObjectProvider> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer
) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
/**
* 限流异常处理器, 限流异常出现时, 执行到这个 handler
* */
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// 默认会返回错误 message, code 429
return new SentinelGatewayBlockExceptionHandler(
this.viewResolvers,
this.serverCodecConfigurer
);
}
/**
* 限流过滤器, 是 Gateway 全局过滤器, 优先级定义为最高
* */
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
/**
* 初始化限流规则
* */
@PostConstruct
public void doInit() {
log.info("---------------------------------------------------");
// 加载网关限流规则
log.info("load sentinel gateway rules (code define)");
initGatewayRules();
log.info("---------------------------------------------------");
}
/**
* 硬编码网关限流规则
* */
private void initGatewayRules() {
Set rules = new HashSet<>();
GatewayFlowRule rule = new GatewayFlowRule();
// 指定限流模式, 根据 route_id 做限流, 默认的模式
rule.setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_ROUTE_ID);
// 指定 route_id -> service id
rule.setResource("e-commerce-nacos-client");
// 按照 QPS 限流
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 统计窗口和限流阈值
rule.setIntervalSec(60);
rule.setCount(3);
rules.add(rule);
// 加载到网关中
GatewayRuleManager.loadRules(rules);
}
}
上文中使用的是默认的异常处理器,我们可以通过自定义的异常处理器来返回一些我们需要的异常信息
/**
* 初始化限流规则
* */
@PostConstruct
public void doInit() {
log.info("---------------------------------------------------");
// 加载网关限流规则
log.info("load sentinel gateway rules (code define)");
initGatewayRules();
// 加载自定义限流异常处理器
initBlockHandler();
log.info("---------------------------------------------------");
}
/**
* 自定义限流异常处理器
* */
private void initBlockHandler() {
// 自定义 BlockRequestHandler
BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
@Override
public Mono handleRequest(ServerWebExchange serverWebExchange,
Throwable throwable) {
log.error("------------- trigger gateway sentinel rule -------------");
Map result = new HashMap<>();
result.put("code", String.valueOf(HttpStatus.TOO_MANY_REQUESTS.value()));
result.put("message", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());
result.put("route", "e-commerce-nacos-client");
return ServerResponse
.status(HttpStatus.TOO_MANY_REQUESTS)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(result));
}
};
// 设置自定义限流异常处理器
GatewayCallbackManager.setBlockHandler(blockRequestHandler);
}
针对单个或者指定几个url进行限流
/**
* 硬编码网关限流规则
* */
private void initGatewayRules() {
Set rules = new HashSet<>();
GatewayFlowRule rule = new GatewayFlowRule();
// 指定限流模式, 根据 route_id 做限流, 默认的模式
rule.setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_ROUTE_ID);
// 指定 route_id -> service id
rule.setResource("e-commerce-nacos-client");
// 按照 QPS 限流
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 统计窗口和限流阈值
rule.setIntervalSec(60);
rule.setCount(3);
//rules.add(rule);
// 限流分组, Sentinel 先去找规则定义, 再去找规则中定义的分组
rules.add(
new GatewayFlowRule("nacos-client-api-1")
.setCount(3).setIntervalSec(60)
);
rules.add(
new GatewayFlowRule("nacos-client-api-2")
.setCount(1).setIntervalSec(60)
);
// 加载到网关中
GatewayRuleManager.loadRules(rules);
// 加载限流分组
initCustomizedApis();
}
/**
* 硬编码网关限流分组
* 1. 最大限制 - 演示
* 2. 具体的分组
* */
private void initCustomizedApis() {
Set definitions = new HashSet<>();
// nacos-client-api 组, 最大的限制
ApiDefinition api = new ApiDefinition("nacos-client-api")
.setPredicateItems(new HashSet() {{
// 模糊匹配 /imooc/ecommerce-nacos-client/ 及其子路径的所有请求
add(new ApiPathPredicateItem()
.setPattern("/imooc/ecommerce-nacos-client/**")
// 根据前缀匹配
.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
// nacos-client-api-1 分组
ApiDefinition api1 = new ApiDefinition("nacos-client-api-1")
.setPredicateItems(new HashSet() {{
add(new ApiPathPredicateItem()
// 精确匹配 /imooc/ecommerce-nacos-client/nacos-client/service-instance
.setPattern("/imooc/ecommerce-nacos-client" +
"/nacos-client/service-instance"));
}});
// nacos-client-api-2 分组
ApiDefinition api2 = new ApiDefinition("nacos-client-api-2")
.setPredicateItems(new HashSet() {{
add(new ApiPathPredicateItem()
// 精确匹配 /imooc/ecommerce-nacos-client/nacos-client/project-config
.setPattern("/imooc/ecommerce-nacos-client" +
"/nacos-client/project-config"));
}});
definitions.add(api1);
definitions.add(api2);
// 加载限流分组
GatewayApiDefinitionManager.loadApiDefinitions(definitions);
}
首先将硬编码的方式注释掉
/**
* 初始化限流规则
* */
//@PostConstruct
public void doInit() {
············
}
添加配置规则gateway-flow-rule-sentinel.json
[
{
"resource": "e-commerce-nacos-client",
"resourceMode": 0,
"count": 3,
"intervalSec": 60
},
{
"resource": "nacos-client-api",
"resourceMode": 1,
"count": 1,
"intervalSec": 60
}
]
添加配置分组gateway-flow-rule-api-sentinel.json
[
{
"apiName": "nacos-client-api",
"predicateItems": [
{
"pattern": "/imooc/ecommerce-nacos-client/nacos-client/project-config"
},
{
"pattern": "/imooc/ecommerce-nacos-client/**",
"matchStrategy": 1
}
]
}
]
在配置文件中添加两个配置
spring:
cloud:
sentinel:
datasource:
#通过本地文件方式, 基于服务级别的配置
dsl.file:
file: classpath:gateway-flow-rule-sentinel.json
# 代表服务级别的限流, 一步步点进去看, 文件类型
ruleType: gw-flow
# 通过本地文件方式, 细粒度对指定 api 进行配置
ds2.file:
file: classpath:gateway-flow-rule-api-sentinel.json
# 代表 API 分组, 一步步点进去看, 文件类型
ruleType: gw-api-group
在nacos上新建两个配置,就是之前的本地文件的配置
在配置文件中修改之前的数据源配置
spring:
application:
name: e-commerce-gateway
cloud:
nacos:
discovery:
enabled: true # 如果不想使用 Nacos 进行服务注册和发现, 设置为 false 即可
server-addr: 1.15.247.9:8848 # Nacos 服务器地址
namespace: 22d40198-8462-499d-a7fe-dbb2da958648
# metadata:
# management:
# context-path: ${server.servlet.context-path}/actuator
sentinel:
eager: true
transport:
port: 8720
dashboard: 127.0.0.1:7777
datasource:
# #通过本地文件方式, 基于服务级别的配置
# dsl.file:
# file: classpath:gateway-flow-rule-sentinel.json
# # 代表服务级别的限流, 一步步点进去看, 文件类型
# ruleType: gw-flow
# # 通过本地文件方式, 细粒度对指定 api 进行配置
# ds2.file:
# file: classpath:gateway-flow-rule-api-sentinel.json
# # 代表 API 分组, 一步步点进去看, 文件类型
# ruleType: gw-api-group
# 集成 Nacos
ds1:
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
namespace: ${spring.cloud.nacos.discovery.namespace}
# 测试时, 看看 Nacos 中修改是否能让 dashboard 生效, 就把第二个 count 也修改为 3
data-id: gateway-flow-rule-sentinel
group-id: DEFAULT_GROUP
data-type: json
rule-type: gw-flow
ds2:
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
namespace: ${spring.cloud.nacos.discovery.namespace}
data-id: gateway-flow-rule-api-sentinel
group-id: DEFAULT_GROUP
data-type: json
rule-type: gw-api-group