1 基础概念
熔断:A 服务调用 B 服务的某个功能,由于网络不稳定问题,或者 B 服务卡机,导致功能时间超长。如果这样子的次数太多,就可以直接将 B 断路了(A 不再请求 B 接口),凡是调用 B 的直接返回降级数据,不必等待 B 的超长执行。 这样 B 的故障问题,就不会级联影响到 A。
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
- </dependency>
根据依赖版本下载相应的
sentinel-dashboard-1.6.3.jar
https://github.com/alibaba/Sentinel/releases/download/1.6.3/sentinel-dashboard-1.6.3.jarReleases · alibaba/Sentinel · GitHub

然后使用命令台启动(server.port指端口,自行填写):
java -jar sentinel-dashboard-1.6.3.jar --server.port=8333
然后输入http://localhost:8333/ 即可看到页面

初始账号密码都是sentinel
配置文件中加入:
- spring.cloud.sentinel.transport.dashboard=localhost:8333
- spring.cloud.sentinel.transport.port=8719
=======================================================================
限流
启动项目,随便访问一个API

新增流控规则(每秒请求数为1):

可以看到出现了流控规则:
疯狂刷新页面,就会出现:

限流成功了
为了得到更多信息,对外暴露endpoint
在pom中导入:
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-actuator</artifactId>
- </dependency>
配置文件中加入:
management.endpoints.web.exposure.include=*
重启项目,疯狂刷新刚刚的接口,就可以在实时监控中看到:

接下来自定义流量控制显示的内容(显示内容自定):
- @Configuration
- public class SeckillSentinelConfig {
-
- public SeckillSentinelConfig() {
- 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));
- }
- });
- }
- }
因为流控规则保存在内存中,重启项目会消失,所以需要重新添加流控规则。再次重新刷新页面,就会出现自定义的显示内容了:

流控模式说明:

关联:对资源A的限流,是关联资源B流量大时才会触发

链路:对资源A的限流,是只有经过入口资源B时才触发,直接访问资源A是不触发的
流控效果说明:

Warm Up:经过10秒阈值会升到100

排队等待:多出来的访问请求超过3秒才失效,之前是一直等待
=======================================================================
熔断降级
在需要用到sentinel的所有微服务里都加入sentinel依赖和actuator依赖,并配置:
- spring.cloud.sentinel.transport.dashboard=localhost:8333
- management.endpoints.web.exposure.include=*
-
- feign.sentinel.enabled=true
比如我的product服务调用seckill服务的接口,

则在定义feign的时候可以指定fallback内容:
- @FeignClient(value = "gulimall-seckill",fallback = SeckillFeignServiceFallBack.class)
- public interface SeckillFeignService {
-
- /**
- * 根据skuId查询商品是否参加秒杀活动
- * @param skuId
- * @return
- */
- @GetMapping(value = "/sku/seckill/{skuId}")
- R getSkuSeckilInfo(@PathVariable("skuId") Long skuId);
-
- }
指定了fallback为SeckillFeignServiceFallBack(返回内容自定)
- @Slf4j
- @Component
- public class SeckillFeignServiceFallBack implements SeckillFeignService {
- @Override
- public R getSkuSeckilInfo(Long skuId) {
- log.info("熔断");
- return R.error(BizCodeEnum.TO_MANY_REQUEST.getCode(),BizCodeEnum.TO_MANY_REQUEST.getMessage());
- }
- }
停止seckill服务,访问product服务,可以看到日志平台提示熔断。
对seckill服务点击降级按钮:
RT:
当进入的请求的响应时间超过了1000毫秒,则实施熔断,10秒后检查若还是这样就继续熔断,否则结束熔断。
当访问量超大时,需要对一些服务做出服务,可直接让远程服务本身指定降级策略,这样虽然远程服务依然在运行,但运行是默认返回降级策略。
自定义一个叫“seckillSkus”的资源:
- @Override
- public List
getCurrentSeckillSkus() { -
- try (Entry entry = SphU.entry("seckillSkus")) {
-
- //业务
-
- } catch (BlockException e) {
- log.error("资源被限流{}",e.getMessage());
- }
- return null;
- }
接着就可以利用这个资源名进行流控或者熔断降级了。
以上是使用代码的形式,优点为较为灵活。
然后就是以注解的形式:
@SentinelResource(value = "getCurrentSeckillSkusResource",blockHandler = "blockHandler")
因为指定了blockHandler,所以还要写一个blockHandler出来
- public List<SeckillSkuRedisTo> blockHandler(BlockException e) {
- log.error("getCurrentSeckillSkusResource被限流了,{}",e.getMessage());
- return null;
- }
效果是一样的,自定了一个叫getCurrentSeckillSkusResource的资源
========================================================================
网关层配置sentinel
除了上述所需导入的依赖和配置,还需要在网关模块加入以下的依赖:
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
- </dependency>
为了看到新效果,需要使用1.7以上的版本,所以重新下载一个1.7以上的sentinel-dashboard-1.7.1.jar。然后启动服务,可以看到网关和其它的不同之处:

可以看到网关出现在了请求链路里:

对秒杀服务的网管进行配置:

其中Burst Size代表忽然流量暴增时额外增加的请求数
通过api管理可以同时管理多个api

还可以通过配置文件定制返回结果:
- spring.cloud.sentinel.scg.fallback.content-type=application/json
- spring.cloud.sentinel.scg.fallback.response-status=400
- spring.cloud.sentinel.scg.fallback.response-body=wrong
或者写代码来配置:
- 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
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
body = ServerResponse.ok().body(Mono.just(errorJson), String.class); - return body;
- }
- });
- }
- }