大名鼎鼎的 sentinel
没用过的都想用,用过都说好,下面是集成过程。
在开始之前首先需要看一下
一、搭建 sentinel
服务
sentinel docker
选择以下一种即可
- 基于alpine的docker源码镜像
- 已上传到阿里云公共仓库的镜像
docker-compose.yml
sentinel:
container_name: sentinel-dashboard
image: registry.cn-hangzhou.aliyuncs.com/lcts/sentinel-dashboard:1.7.1
restart: always
ports:
- "8858:8080"
environment:
TZ : "Asia/Shanghai"
会在本地端口 8858
启动一个 sentinel
服务
访问 http://localhost:8858
默认账户和密码是 sentinel
二、在项目中集成 sentinel
maven
依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<!--提供 sentinel 监控-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- sentinel 与 dubbo2.7.x以上的整合包 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-apache-dubbo-adapter</artifactId>
<version>1.7.1</version>
</dependency>
<!-- sentinel 提供 AspectJ 的扩展用于自动定义资源、处理 BlockException等 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.7.1</version>
</dependency>
- 基于
bean
的配置
/**
* Sentinel 配置
*/
@Configuration
public class SentinelConfiguration {
/**
* 配置方法级别的Sentinel aop
*/
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
/**
* 让web层请求都经过 sentinelFilter,如果不需要监控web层 可以去掉这个方法
*/
@Bean
public FilterRegistrationBean sentinelFilterRegistration() {
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
registration.setFilter(new CommonFilter());
registration.addUrlPatterns("/*");
registration.setName("sentinelFilter");
registration.setOrder(1);
return registration;
}
}
- 启动配置中增加
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8858
nacos:
discovery:
server-addr: localhost:8848 #Nacos服务器侦听器的IP和端口 #80不能省略
weight: 10 # 值范围:1到100。值越大,权重越大
三、在项目中使用 sentinel
- 演示在
controller
层的使用
@RestController
@RequestMapping("/config")
public class ConfigController {
@Value("${spring.profiles.active}")
String active;
@Autowired
RestTemplate restTemplate;
/**
* http://localhost:8080/config/get
*/
@GetMapping("get")
public String get(@RequestParam(required = false) String str) {
return active + " | " + str;
}
/**
* http://localhost:8080/config/rest
*/
@SentinelResource("ss")
@GetMapping("rest")
public String rest() {
return restTemplate.getForObject("http://nacos-provider/config/get/" + "?str=consumerSend", String.class);
}
}
- 基于业务实现层的使用
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.lc.cloud.alibaba.api.TestDubboService;
import com.lc.cloud.alibaba.consumer.fuse.SentinelTestServiceBlockHandler;
import com.lc.cloud.alibaba.consumer.fuse.SentinelTestServiceFallbackHandler;
import com.lc.cloud.alibaba.consumer.domain.service.SentinelTestService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;
@Service
public class SentinelTestServiceImpl implements SentinelTestService {
@Reference
TestDubboService testDubboService;
/*******
* 注意 :若 blockHandler 和 fallback 都进行了配置
* 则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑
*/
@SentinelResource(blockHandler = "get2BlockHandler",
blockHandlerClass = {SentinelTestServiceBlockHandler.class},
fallback = "get1FallbackHandler",
fallbackClass = {SentinelTestServiceFallbackHandler.class})
@Override
public String get(String str) {
if (1 == 1) throw new RuntimeException("自定义异常");
return testDubboService.get(str);
}
@SentinelResource(blockHandler = "get2BlockHandler",
blockHandlerClass = {SentinelTestServiceBlockHandler.class})
@Override
public String get2(String str) {
if (1 == 1) throw new RuntimeException("自定义异常");
return testDubboService.get2(str);
}
@SentinelResource(fallback = "get3Fallback")
@Override
public String get3(String str) {
if (1 == 1) throw new RuntimeException("自定义异常");
return testDubboService.get3(str);
}
//这里的服务降级或回退方法只需要 public 修饰
public String get2BlockHandler(String str) {
return "get2BlockHandler :" + str;
}
public String get3Fallback(String str) {
return "get3Fallback :" + str;
}
}
注意:
-
最灵性的地方在于
@SentinelResource
注解,想要哪个被监控就加哪个,上面基于bean
配置的时候已经加入了web
层 ,所以 web层不需要显式使用这个注解了 -
blockHandlerClass fallbackClass
对应的方法 必须是public static
修饰 ,而且调用优先级最高。也就是在有
blockHandler
fallback
blockHandlerClass
fallbackClass
都存在的情况下,只会调用 blockHandlerClass fallbackClass
- 需要特别注意的是
@SentinelResource
下面的这几个属性的用法,这里不使用篇幅介绍了,可以直接去看本项目源码,或者sentinel
文档
/**
* @return name of the Sentinel resource
*/
String value() default "";
/**
* @return name of the block exception function, empty by default
*/
String blockHandler() default "";
/**
* The {@code blockHandler} is located in the same class with the original method by default.
* However, if some methods share the same signature and intend to set the same block handler,
* then users can set the class where the block handler exists. Note that the block handler method
* must be static.
*
* @return the class where the block handler exists, should not provide more than one classes
*/
Class<?>[] blockHandlerClass() default {};
/**
* @return name of the fallback function, empty by default
*/
String fallback() default "";
/**
* The {@code defaultFallback} is used as the default universal fallback method.
* It should not accept any parameters, and the return type should be compatible
* with the original method.
*
* @return name of the default fallback method, empty by default
* @since 1.6.0
*/
String defaultFallback() default "";
/**
* The {@code fallback} is located in the same class with the original method by default.
* However, if some methods share the same signature and intend to set the same fallback,
* then users can set the class where the fallback function exists. Note that the shared fallback method
* must be static.
*
* @return the class where the fallback method is located (only single class)
* @since 1.6.0
*/
Class<?>[] fallbackClass() default {};
四、在监控面板中使用 sentinel
访问 http://localhost:8858
默认账户和密码是 sentinel
后 请求上面的示例,你会看到惊喜,更多用法请参考 sentinel
文档
到此 sentinel
集成完成