最近在学习sentinel,也是需要在项目中用到,所以在此作以记录。
项目使用的是spring cloud gateway做转发,需要对某些接口进行限流。
gateway项目的pom.xml
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.8.0</version>
</dependency>
<!-- spring cloud alibaba nacos discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<!-- 1.3.3版本无法识别密码中有特殊字符的bug -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.4.2</version>
</dependency>
GatewayConfiguration
我们项目没有使用到sentinel的dashboard ,因为如果用dashboard的话,需要考虑到可用性,必须要保证dashboard不挂掉。那就需要做集群,这个比较麻烦,所以就省略了dashboard了。
在nacos上配置规则,然后根据规则对请求的接口进行限流。
private void initCustomizedApis() {
Set<ApiDefinition> definitions = new HashSet<>();
ApiDefinition webpage = new ApiDefinition("webpage")
.setPredicateItems(new HashSet<ApiPredicateItem>() {{
add(new ApiPathPredicateItem().setPattern("/collect/log/**")
.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
definitions.add(webpage);
GatewayApiDefinitionManager.loadApiDefinitions(definitions);
}
这段代码是创建了一个统一拦截的规则,而对于这个规则的限流则在nacos上配置着。
package cn.yto.collect.gateway.config;
import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Value;
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.Properties;
import java.util.Set;
@Configuration
public class GatewayConfiguration {
@Value("${spring.cloud.sentinel.datasource.ds.nacos.server-addr}")
private String serverAddress;
@Value("${spring.cloud.sentinel.datasource.ds.nacos.groupId}")
private String groupId;
@Value("${spring.cloud.sentinel.datasource.ds.nacos.dataId}")
private String dataId;
@Value("${spring.cloud.sentinel.datasource.ds.nacos.username}")
private String username;
@Value("${spring.cloud.sentinel.datasource.ds.nacos.password}")
private String password;
@Value("${spring.cloud.sentinel.datasource.ds.nacos.namespace}")
private String namespace;
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the block exception handler for Spring Cloud Gateway.
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
// 这里是加载限流规则的。
private void loadRules() {
Properties properties = new Properties();
properties.setProperty("username", username);
properties.setProperty("password", password);
properties.setProperty("serverAddr", serverAddress);
properties.setProperty("namespace", namespace);
ReadableDataSource<String, List<FlowRule>> flowRuleDataSource =
new NacosDataSource<>(properties, groupId, dataId,
source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
}));
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
}
@Bean
@Order(-1)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
private void initCustomizedApis() {
/**
* nacos 配置的规则, 先加载ApiDefinition,再加载resource=webpage_api
* [
* {
* "resource": "webpage_api",
* "resourceMode": 0,
* "pattern": "/yto-collect/business-log/**",
* "count": 1000,
* "intervalSec": 1,
* "matchStrategy":1
* }
* ]
*/
Set<ApiDefinition> definitions = new HashSet<>();
ApiDefinition webpage = new ApiDefinition("webpage")
.setPredicateItems(new HashSet<ApiPredicateItem>() {{
add(new ApiPathPredicateItem().setPattern("/collect/log/**")
.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
definitions.add(webpage);
GatewayApiDefinitionManager.loadApiDefinitions(definitions);
}
@PostConstruct
public void doInit() {
initCustomizedApis();
loadRules();
// initCustomizedApis();
// initGatewayRules();
}
}
nacos上的配置
针对webpage这个分组,每秒1000次的限流。
[
{
"resource": "webpage",
"resourceMode": 0,
"count": 1000,
"intervalSec": 1,
"matchStrategy":1
}
]
有不清楚的,可以一起交流,QQ:303579750,欢迎一起学习