一、简介
官网:https://gitee.com/rmlb/Sentinel/wikis/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8?sort_id=3419419
对于sentinel的可视化说明:
sentinel要有效果,必须是在1秒内请求5次以上才会进行统计。
1.1 熔断降级限流
什么是熔断
A 服务调用 B 服务的某个功能,由于网络不稳定问题,或者 B 服务卡机,导致功能时
间超长。如果这样子的次数太多。我们就可以直接将 B 断路了(A 不再请求 B 接口),凡是
调用 B 的直接返回降级数据,不必等待 B 的超长执行。 这样 B 的故障问题,就不会级联影
响到 A。
什么是降级
整个网站处于流量高峰期,服务器压力剧增,根据当前业务情况及流量,对一些服务和
页面进行有策略的降级[停止服务,所有的调用直接返回降级数据]。以此缓解服务器资源的
的压力,以保证核心业务的正常运行,同时也保持了客户和大部分客户的得到正确的相应。
异同:
相同点:
1、为了保证集群大部分服务的可用性和可靠性,防止崩溃,牺牲小我
2、用户最终都是体验到某个功能不可用
不同点:
1、熔断是被调用方故障,触发的系统主动规则2、降级是基于全局考虑,停止一些正常服务,释放资源
什么是限流
对打入服务的请求流量进行控制,使服务能够承担不超过自己能力的流量压力
1.2 Hystrix 与 Sentinel 比较
二、使用步骤
主要分为几个步骤:
定义资源
定义规则
检验规则是否生效
2.1 定义资源
方式一★:主流框架的默认适配
方式二★:抛出异常的方式定义资源
方式三:返回布尔值方式定义资源
方式四★:注解方式定义资源
方式五:异步调用支持
三、springboot整合Sentinel
官网:https://gitee.com/rmlb/Sentinel/wikis/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8?sort_id=3419419
/**
* 1、整合Sentinel
* 1)、导入依赖 spring-cloud-starter-alibaba-sentinel
* 2)、下载sentinel控制台
* 3)、配置 sentinel 控制台地址信息
* 4)、在控制台调整参数、【默认所有的流控规则保存在内存中,重启失效】
*
* 2、每一个微服务都导入 actuator :并配合 management.endpoints.web.exposure.include=*
* 3、自定义 sentinel 流控返回的数据
*
* 4、使用Sentinel来保护feign远程调用,熔断;
* 1)、调用方的熔断保护:feign.sentinel.enable=true
* 2)、调用方手动指定远程服务的降级策略。远程服务被降级处理。触发我们的熔断回调方法
* 3)、超大浏览的时候,必须牺牲一些远程服务。在服务的提供方(远程服务)指定降级策略;
* 提供方是在运行,但是不允许自己的业务逻辑,返回的是默认的降级数据(限流的数据)
*
* 5、自定义受保护的资源
* 1)、代码
* try (Entry entry = SphU.entry("seckillSkus")) {
* //业务逻辑
* } catch(Exception e) {}
*
* 2)、基于注解
* // 原本的业务方法.
@SentinelResource(blockHandler = "blockHandlerForGetUser")
public User getUserById(String id) {
throw new RuntimeException("getUserById command failed");
}
// blockHandler 函数,原方法调用被限流/降级/系统保护的时候调用
public User blockHandlerForGetUser(String id, BlockException ex) {
return new User("admin");
}
*
*/
第一步:引入依赖
在公共gulimall-common中引入
<!--限流&熔断&降级-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
在每个微服务中引入
<!--限流&熔断&降级 实现实时监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
查看版本
下载sentinel:https://github.com/alibaba/Sentinel/releases
第二步:在每个微服务中配置sentinel
#sentinel 限流&熔断&降级的配置
spring.cloud.sentinel.transport.dashboard=localhost:8080
#默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
spring.cloud.sentinel.transport.port: 8719
#暴露所有端点,为了实时监控使用
management.endpoints.web.exposure.include=*
# 开启feign得熔断降级功能
feign.sentinel.enabled=true
在方法上添加注释: @SentinelResource
第三步:触发流量控制或者降级策略后的返回值自定义
/**
* @Description: 自定义限流返回方法
* @Created: with IntelliJ IDEA.
* @createTime: 2020-07-13 11:30
**/
@Configuration
public class GulimallSeckillSentinelConfig {
public GulimallSeckillSentinelConfig() {
WebCallbackManager.setUrlBlockHandler(new UrlBlockHandler() {
@Override
public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException ex) throws IOException {
R error = R.error(BizCodeEnum.TO_MANY_REQUEST.getCode(), BizCodeEnum.TO_MANY_REQUEST.getMessage());
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
response.getWriter().write(JSON.toJSONString(error));
}
});
}
}
第四步:配置Feign调用不成功的熔断控制
方式一:在feign的调用方进行熔断降级控制,比如在超大浏览的时候,必须牺牲一些远程服务的降级策略。远程服务被降级触发我们的熔断回调方法。
@Configuration
public class GulimallCouponSentinelConfig {
public GulimallCouponSentinelConfig() {
WebCallbackManager.setUrlBlockHandler(new UrlBlockHandler() {
@Override
public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException ex) throws IOException {
R error = R.error(BizCodeEnum.TO_MANY_REQUEST.getCode(), BizCodeEnum.TO_MANY_REQUEST.getMessage()).put("coupon","降级");
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
response.getWriter().write(JSON.toJSONString(error));
}
});
}
}
方式二:在feign的提供方进行熔断降级控制
测试代码在下面的内容:五、Feign调用失败的降级处理,处理时在feign的调用端
没有熔断时:
熔断后的降级处理,这是上一步配置的返回值类型。
如果远程微服务掉线就会进入本服务的feign错误回调
第五步:测试
测试主要分为几个步骤:
定义资源
定义规则
检验规则是否生效
由于资源的定义的有5种,所以测试也有5种,我们只拿方式二和方式四举例
方式一★:主流框架的默认适配
方式二★:抛出异常的方式定义资源
方式三:返回布尔值方式定义资源
方式四★:注解方式定义资源
方式五:异步调用支持
为了测试方便,我把方式二和方式四结合使用了
@Resource
private CouponFeignService couponFeignService;
@GetMapping("/getinfo")
@ResponseBody
@SentinelResource(value = "seckill-hello-method",blockHandler ="getInfoblockHandler")
public R getInfo(){
Map<String,Object> map = null;
// 使用自定义的资源来进行限流熔断降级
try (Entry entry = SphU.entry("seckill-hello-map")) {
//业务逻辑
map = new HashMap<>();
map.put("category","产品部");
} catch(BlockException e) {
System.out.println("maruis--限流---->" + e.getMessage());
}
R r = couponFeignService.getProductInfo("张三");
r.put("data",map);
return r;
}
/**
* getInfo 方法限流熔断或降级后的回调
* @return
*/
public R getInfoblockHandler(BlockException e){
return R.error().put("msg",e);
}
定义限流规则:
测试
测试
四、sentinel控制台
默认:http://localhost:8080
1)、簇点路径
2)流控规则
通过簇点链路和流控规则都可以添加规则。
五、Feign调用失败的降级处理,处理时在feign的调用端
5.1 编写feign接口
value = “gulimall-coupon” 远程调用的微服务名称
fallback = CouponFeignServiceFallBack.class 远程调用失败的回调方法,注意这个回调方法时实现下面的feign接口的。
@FeignClient(value = "gulimall-coupon",fallback = CouponFeignServiceFallBack.class)
public interface CouponFeignService {
/**
* 查询最近三天需要参加秒杀商品的信息
* @return
*/
@GetMapping(value = "/coupon/seckillsession/Lates3DaySession")
R getLates3DaySession();
/**
* 获取信息
* @return
*/
@GetMapping(value = "/hello/getinfo")
R getProductInfo(String username);
}
5.2 编写feign调用失败的回调,这相当于本地降级
注意:
1)一定要把回调的方法注入到ioc容器中,这样5.1 的调用才可以引用它,此处用的@Component
2) 实现CouponFeignService 中的所有方法,这样哪个方法调用失败就会回调到哪个方法中,并且还会携带参数。
@Component
public class CouponFeignServiceFallBack implements CouponFeignService {
@Override
public R getLates3DaySession() {
System.out.println("maruis------>" + "getLates3DaySession");
return R.error();
}
@Override
public R getProductInfo(String username) {
System.out.println("maruis------>" + "getProductInfo");
return R.error().put("data",username);
}
}
5.3 通过controller 测试
@Resource
private CouponFeignService couponFeignService;
@GetMapping("/getinfo")
@ResponseBody
public R getInfo(){
return couponFeignService.getProductInfo("张三");
}
@GetMapping("/3day")
@ResponseBody
public R get3DayInfo(){
R lates3DaySession = couponFeignService.getLates3DaySession();
return lates3DaySession;
}
5.4 远程服务的controller
@RestController
@RequestMapping("hello")
public class HelloController {
@RequestMapping("/getinfo")
public R getInfo() throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(300);
System.out.println("maruis------>" + "获取商品信息");
return R.ok().put("info","123456");
}
}
5.4 测试效果
测试时:不要启动远程调用的微服务
六、网关限流
文档:https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81
6.1 添加依赖
<!--限流&熔断&降级 实现实时监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- <!–限流&熔断&降级–>-->
<!-- <dependency>-->
<!-- <groupId>com.alibaba.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>-->
<!-- </dependency>-->
<!--
sentinel 与网关的整合,前提是已经导入sentinel依赖,我们在上面的gulimall-common中已经导入了sentinel的依赖
2.1.0.RELEASE 这个版本号与springboot的版本是一致的。
-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
6.2 配置
sentinel配置
#sentinel 限流&熔断&降级的配置
spring.cloud.sentinel.transport.dashboard=localhost:8080
#默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
spring.cloud.sentinel.transport.port: 8719
#暴露所有端点,为了实时监控使用
management.endpoints.web.exposure.include=*
# 开启feign得熔断降级功能
feign.sentinel.enabled=true
限流熔断降级的回调配置
package com.atguigu.gulimall.config;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.fastjson.JSON;
import com.atguigu.common.exception.BizCodeEnum;
import com.atguigu.common.utils.R;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Configuration
public class SentinelGatewayConfig {
public SentinelGatewayConfig() {
GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
//网关限流了请求,就会调用此回调
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable t) {
R error = R.error(BizCodeEnum.TO_MANY_REQUEST.getCode(), BizCodeEnum.TO_MANY_REQUEST.getMessage());
String errorJson = JSON.toJSONString(error);
Mono<ServerResponse> body = ServerResponse.ok().body(Mono.just(errorJson), String.class);
return body;
}
});
}
}
6.3 测试
添加限流规则
利用postman添加了请求头hello
也可以对某一组的分类行进限流策略
新建api分组
七、sentinel的持久化
略