docker 安装sentinel
docker run -d -p 8858:8858 \
--name sentinel-dashboard \
-e AUTH_USERNAME=sentinel \
-e AUTH_PASSWORD=sentinel \
-e NACOS_SERVER_ADDR=192.168.16.161:8848 \
bladex/sentinel-dashboard:latest
pom 依赖
<!-- 容错 sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- sentinel核心库 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.4</version>
</dependency>
<!-- 如果要使用@SentinelResource必须添加此依赖 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.8.4</version>
</dependency>
<!-- 整合sentinel控制台 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.4</version>
</dependency>
<!--sentinel配置持久化到nacos所需依赖-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.8.4</version>
</dependency>
<!-- 监控 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 集群限流 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-cluster-client-default</artifactId>
<version>1.8.4</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-cluster-server-default</artifactId>
<version>1.8.4</version>
</dependency>
application.yml配置
spring:
application:
name: sys
cloud:
sentinel:
enabled: true
transport:
port: 8730
dashboard: 192.168.16.161:8858
# client-ip 服务器ip
client-ip: 127.0.0.1
datasource:
ds1:
nacos:
server-addr: 192.168.16.161:8848
data-id: ${spring.application.name}-sentinel-rules
namespace: c157a644-7f46-4a63-9c81-25e890f15736
group-id: DEFAULT_GROUP
data-type: json
rule-type: flow
启动脚本
clientip=`ifconfig -a|grep inet|grep -v $*.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:"`
echo "-------clientip $clientip--------"
nohup java -jar -Xms512M -Xms512M -XX:PermSize=512M -XX:MaxPermSize=512M $PWD/$jar*.jar --spring.profiles.active=prod --spring.cloud.sentinel.transport.client-ip=$clientip >/dev/null 2>&1 &
echo "$jar restart success"
nacos配置
- QPS 非集群
[
{
"app":"service-sys",
"resource": "/verification/send",
"count": 10,
"grade": 1,
"limitApp": "default",
"strategy": 0,
"controlBehavior": 0,
"clusterMode" : true,
"clusterConfig" : {
"flowId" : 901,
"thresholdType" : 1,
"fallbackToLocalWhenFail" : true
}
},
{
"app":"service-sys",
"resource": "/captcha/get",
"count": 10,
"grade": 1,
"limitApp": "default",
"strategy": 0,
"controlBehavior": 0,
"clusterMode" : true,
"clusterConfig" : {
"flowId" : 902,
"thresholdType" : 1,
"fallbackToLocalWhenFail" : true
}
}
]
- 集群阀值
resource API 名称 count QPS 阀值 intervalSec 秒
[
{
"resource": "service-tenant",
"resourceMode": 0,
"count": 1000,
"intervalSec": 1
},
{
"resource": "service-sys",
"resourceMode": 0,
"count": 1000,
"intervalSec": 1
}
,
{
"resource": "service-auth",
"resourceMode": 0,
"count": 1000,
"intervalSec": 1
}
,
{
"resource": "service-user",
"resourceMode": 0,
"count": 1000,
"intervalSec": 1
}
]
自定义@SentinelResource 使用
- Handler异常的返回方法要和Controller 方法一样
@Slf4j
@Service
public class TestService {
// 限流与阻塞处理
@SentinelResource(value = "doSomeThing", blockHandler = "exceptionHandler")
public void doSomeThing(String str) {
log.info(str);
}
public void exceptionHandler(String str, BlockException ex) {
log.error("blockHandler:" + str, ex);
}
// 熔断与降级处理
@SentinelResource(value = "doSomeThing2", fallback = "fallbackHandler")
public void doSomeThing2(String str) {
log.info(str);
throw new RuntimeException("发生异常");
}
public void fallbackHandler(String str) {
log.error("fallbackHandler:" + str);
}
}
全局异常
@Configuration
public class SysBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
throw new AppBusinessException("S01000", "您操作行为异常,请稍后再试");
// String json = "{\"code\": -1, \"data\": null, \"message\": \"行为验证码异常,请稍后再试\"}";
// response.setHeader("Content-Type", "application/json;charset=UTF-8");
// response.getWriter().write(JSONUtil.toJsonStr(json));
}
}
sentinel gateway 使用
<!-- sentinel核心库 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.4</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-alibaba-sentinel-gateway -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
<version>1.8.4</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.4</version>
</dependency>
<!-- sentilen用 nacos 做 持久化-->
<!-- https://mvnrepository.com/artifact/com.alibaba.csp/sentinel-datasource-nacos -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.8.4</version>
</dependency>
gateway 全局限流配置
@Configuration
public class SysGatewayConfiguration {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public SysGatewayConfiguration(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 SysSentinelGatewayBlockExceptionHandler(viewResolvers,serverCodecConfigurer);
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
}
public class SysSentinelGatewayBlockExceptionHandler extends SentinelGatewayBlockExceptionHandler {
private List<ViewResolver> viewResolvers;
private List<HttpMessageWriter<?>> messageWriters;
public SysSentinelGatewayBlockExceptionHandler(List<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
super(viewResolvers,serverCodecConfigurer);
this.viewResolvers = viewResolvers;
this.messageWriters = serverCodecConfigurer.getWriters();
}
@Override
public Mono<Void> handle(ServerWebExchange serverWebExchange, Throwable throwable) {
if(serverWebExchange.getResponse().isCommitted()){
return Mono.error(throwable);
}
if(!BlockException.isBlockException(throwable)){
return Mono.error(throwable);
}
return handleBlockedRequest(serverWebExchange, throwable).flatMap(response -> {
try {
return writeResponse(response, serverWebExchange);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) {
return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
}
private final Supplier<ServerResponse.Context> contextSupplier = () -> new ServerResponse.Context() {
@Override
public List<HttpMessageWriter<?>> messageWriters() {
return SysSentinelGatewayBlockExceptionHandler.this.messageWriters;
}
@Override
public List<ViewResolver> viewResolvers() {
return SysSentinelGatewayBlockExceptionHandler.this.viewResolvers;
}
};
private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) throws Exception {
//throw new Exception("您操作行为异常,请稍后再试");
ServerHttpResponse resp = exchange.getResponse();
resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
String json = "{\"code\": -1, \"data\": null, \"message\": \"您操作行为异常,请稍后再试\"}";
DataBuffer buffer = resp.bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8));
return resp.writeWith(Mono.just(buffer));
}
}