配置Sentinel Server端可视化界面
下载Sentinel
下载完成后
运行以下代码
java -jar sentinel-dashboard-1.8.3.jar
运行后的结果
访问 localhost:8080 出现如下界面
*账号:sentinel *
*密码:sentinel *
代码配置部分
普通搭建(2种方法)
查看nacos搭建
消费者导入sentinel的jar包
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
编写application.yml配置文件
#端口
server:
port: 7781
#服务名
spring:
application:
name: user-consumer-sentine
# 注册到Nacos
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
# 开启sentinel
enabled: true
transport:
# 将服务配置到sentinel中
dashboard: localhost:8080
resttemplate:
sentinel:
# 开启ribbon与sentinel整合
enabled: true
编写Controller层
@Slf4j // lombok包
@RestController
@RequestMapping("/sentinel")
public class UserController {
@Resource
RestTemplate restTemplate;
@RequestMapping("/getUser/{id}")
/**
* blockHandler 异常降级后处理的方法
* blockHandlerClass 异常降级后处理的类
* fallback 限流熔断后处理的方法
* fallbackClass 限流熔断后处理的类
*/
@SentinelResource(
fallback = "handleFallback", fallbackClass = EarsSentinelCompilations.class,
blockHandler = "handleBlock", blockHandlerClass = EarsSentinelCompilations.class
)
public TbUser findById(@PathVariable Integer id){
String url = "http://user-provider/user/find/"+id;
TbUser forObject = restTemplate.getForObject(url, TbUser.class);
log.info(String.valueOf(forObject));
return forObject;
}
}
@SentinelResource:
blockHandler: 异常降级后处理的方法
blockHandlerClass: 异常降级后处理的类
fallback: 限流熔断后处理的方法
fallbackClass: 限流熔断后处理的类
编写Sentinel熔断降级处理类
public class EarsSentinelCompilations {
// 异常
public static TbUser handleFallback(@PathVariable("id") Integer id){
return TbUser.builder().id(-1).name("Ribbon兜底").note("异常报错").build();
}
// 非异常
public static TbUser handleBlock(@PathVariable("id") Integer id){
return TbUser.builder().id(-1).name("Ribbon兜底兜底").note("非异常报错").build();
}
}
编写启动类
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class UserSentinelApplication7781 {
public static void main(String[] args) {
SpringApplication.run(UserSentinelApplication7781.class,args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
运行Nacos,运行Sentienl,运行启动类
为了测试效果:给服务提供者写一个报错
@Slf4j
@RestController
@RequestMapping("user")
public class UserController {
@Resource
UserService userService;
@SneakyThrows
@RequestMapping("find/{id}")
public TbUser findById(@PathVariable Integer id){
log.info("provide:id:"+id);
/*测试远程调用的超时时间
Thread.sleep(4000);*/
// int i = 1/0;
return userService.getUserId(id);
}
}
结果如下:
成功进入降级处理方法
第二种方法
对注入的Restemplate的注解上加,@SentinelRestTemplate
@Bean
@LoadBalanced
@SentinelRestTemplate(
fallback = "handleFallback", fallbackClass = EarsSentinelRestTemplate.class,
blockHandler = "handleBlock", blockHandlerClass = EarsSentinelRestTemplate.class
)
public RestTemplate restTemplate(){
return new RestTemplate();
}
新建一个处理熔断降级的类
public class EarsSentinelRestTemplate {
/**
* 静态方法
* 返回值: SentinelClientHttpResponse
* 参数 : request , byte[] , clientRquestExcetion , blockException
*/
//限流熔断
public static SentinelClientHttpResponse handleBlock(HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution,
BlockException ex) {
return new SentinelClientHttpResponse("熔断");
}
//异常降级
public static SentinelClientHttpResponse handleFallback(HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution,
BlockException ex) {
return new SentinelClientHttpResponse("降级");
}
}
使用可视化界面设置限流
由于免费版的,重启服务消费者设置的限流规则就会消失,持久化保存限流规则,需要使用企业版
侧边栏选择:簇点链路 > 选择 /sentinel/getUser/{id}
对 /sentinel/getUser/{id} 添加一个规则
阈值类型:
QPS(每秒查询率 Query Per Second) :每秒的响应请求数
线程数
流控模式:
直接: 流控模式:最简单的模式,只要超过单机阈值就对资源名(接口url)进行限流。
关联: 流控模式:需要设置资源名(例如/res1)和关联资源(例如/res2),若关联资源/res2超过单机阈值,则/res1被限流(res2不会被限流)。
链路: 流控模式:当从某个接口过来的资源达到限流条件时,开启限流
流控效果:
快速失败: 直接拒绝请求。
Warm Up(预热): 需设置预热时长(单位秒),假设为5,则效果就是前五秒请求资源名时,单机阈值始终为1,5秒后,阈值恢复到正常值,即设定的值。(服务刚启动时,各个性能指标均未达到巅峰,此时不易处理过多的请求,这种情况就可以使用预热。打个比方,就好比早上刚起床,还比较困,但随着时间的推移,工作学习效率也逐渐提高了,能够处理更复杂的任务)。
排队等待: 需设置预热时长(单位毫秒,假设为300),当请求的资源超过单机阈值时,不会立马抛异常,会在0.3秒后再次请求该资源,若能调通,则不抛异常,否则抛出异常。
测试
使用 Jmeter 对API进行压力测试
设置10个线程,1秒类完成,永久运行,记得测试完后关闭
启动后压力测试后访问这个API
响应结果
Blocked by Sentinel (flow limiting) 被Sentinel阻塞(限流)
使用Feign调用 (3种方法)
导入opfeign的jar文件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
第一种普通使用
编写feign接口
@FeignClient("user-provider")
public interface FeignService {
@GetMapping("user/find/{id}")
TbUser findById(@PathVariable("id") Integer id);
}
编写处理熔断降级类
/**
* 普通兜底类
*/
public class EarsSentinelCompilations {
// 降级处理
public static TbUser handleFallback(@PathVariable("id") Integer id){
return TbUser.builder().id(-1).name("整合feign的普通兜底").note("异常报错").build();
}
// 熔断处理
public static TbUser handleBlock(@PathVariable("id") Integer id){
return TbUser.builder().id(-1).name("整合feign的普通兜底").note("非异常报错").build();
}
}
第二种 单独降级处理
编写feign接口
//指定的伪客户端接口的回退类。 回退类必须实现由该注释注释的接口,并且是一个有效的spring bean
@FeignClient(value = "user-provider",fallback = FeignServiceImpl.class)
@FeignClient("user-provider")
public interface FeignService {
@GetMapping("user/find/{id}")
TbUser findById(@PathVariable("id") Integer id);
}
编写处理降级类
/**
*客户端接口的回退类
*/
//@Component
public class FeignServiceImpl implements FeignService {
@Override
public TbUser findById(Integer id) {
return TbUser.builder().id(-1).name("整合feign的回退兜底").note("异常报错").build();
}
}
第三种 单独熔断处理
编写feign接口
//为指定的Feign客户端接口定义一个备用工厂。 回退工厂必须生成回退类的实例,这些实例实现了由FeignClient标注的接口。 回退工厂必须是一个有效的spring bean。
@FeignClient(value = "user-provider",fallbackFactory = FeignServiceBeanImpl.class)
@FeignClient("user-provider")
public interface FeignService {
@GetMapping("user/find/{id}")
TbUser findById(@PathVariable("id") Integer id);
}
编写处理熔断类
/**
* Feign客户端接口定义一个备用工厂
*/
@Slf4j
@Component
public class FeignServiceBeanImpl implements FallbackFactory<FeignService> {
@Override
public FeignService create(Throwable cause) {
log.info(String.valueOf(cause));
return (message) -> {
log.info(String.valueOf(message));
return TbUser.builder().id(-1).name("整合feign的工厂兜底").note("异常报错").build();
};
}
}
编写Controller
@Slf4j // lombok:的包
@RestController
@RequestMapping("/sentinel")
public class UserController {
@Resource
FeignService feignService;
@RequestMapping("/feign/getUser/{id}")
/**
* blockHandler 异常降级后处理的方法
* blockHandlerClass 异常降级后处理的类
* fallback 限流熔断后处理的方法
* fallbackClass 限流熔断后处理的类
*/
@SentinelResource(
fallback = "handleFallback", fallbackClass = EarsSentinelCompilations.class,
blockHandler = "handleBlock", blockHandlerClass = EarsSentinelCompilations.class
)
public TbUser findById(@PathVariable Integer id){
// 使用feign调用
TbUser tbUser = feignService.findById(id);
log.info(String.valueOf(tbUser));
return tbUser;
}
}
编写application.yml配置文件
#端口
server:
port: 7781
#服务名
spring:
application:
name: user-consumer-sentine
# 注册到Nacos
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
# 开启sentinel
enabled: true
transport:
# 将服务配置到sentinel中
dashboard: localhost:8080
# 开启feign和sentinel的整合
feign:
sentinel:
enabled: true
编写启动类
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableFeignClients
public class UserSentinelFeignApplication7782 {
public static void main(String[] args) {
SpringApplication.run(UserSentinelFeignApplication7782.class,args);
}
}