Sentinel

为了保护服务之间的稳定性,从流量的切入点。从流量控制,流量路由,熔断降级,系统自适应过载保护,热点流量防护等多个维度保护服务的稳定性。

要想使用sentinel需要先进行依赖的集成

XML 复制代码
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

当我们集成之后就可以在本地进行配置了

bash 复制代码
sentinel:
  transport:
    dashboard: http://127.0.0.1:8080
  eager: true

当我们配置之后即可以在我们sentinel的控制台进行使用了

这个时候就可以对我们想要进行的资源进行添加声明,让我们能够在控制台进行控制。

异常处理

web接口

我们对于web接口来说,对于流控来讲,我们如果不自己进行异常抛出的设置的话,就会默认使用BlockExceptionHandler里面的默认抛出,所以我们可以进行一下设置

java 复制代码
package com.kang.order.exception;
​
import com.alibaba.csp.sentinel.adapter.spring.webmvc_v6x.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kang.common.R;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
​
import java.io.PrintWriter;
​
@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {
    private ObjectMapper objectMapper = new ObjectMapper();
​
    @Override
    public void handle(HttpServletRequest httpServletRequest,
                       HttpServletResponse httpServletResponse,
                       String s, BlockException e) throws Exception {
        httpServletResponse.setContentType("application/json;charset=utf-8");
        PrintWriter writer = httpServletResponse.getWriter();
        writer.write(objectMapper.writeValueAsString(R.error(500, s+"服务器限流了,因为:"+e.getMessage())));
        writer.flush();
    }
}

我们进行一个流控的异常设置,就可以在我们流量访问过大的时候进行自定义的异常抛出。

注意!!!

我们的sentinel是默认把规则存储在内存当中,所以我们项目重新启动的话就需要重新进行设置。

@Sentinel Resource标注的方法

我们对该注解标注的方法进行限流控制就会发现,当我们进行刷新的时候就会出现报错

当我们标注注解之后就会,进行切入,切入之后拿到注解名之后就会获取注解值,然后使用SphU.entry进行错误的辨别,当无错的时候就会正常,有错误的时候就会进入底层,查看容器当中是否有BlockHandler方法,如果指定了方法就会进行我们自定义的逻辑方法,如果没有指定就会走sentinel的底层的fallback方法,如果你指定了fallback方法,那么底层就会走我们写的fallback方法,如果fallback方法为空就会走一个defaultFallback方法,同上,如果还是没有就会将这个异常进行抛出。

我们只需要对我们的方法进行blockHandler进行重写,就可以实现最终的返回

java 复制代码
@SentinelResource(value = "createOrder",blockHandler = "createOrderFallback")
public Order createOrderFallback(Long productId, Long userId, BlockException e) {
    Order order = new Order();
    order.setId(0L);
    order.setTotalAmount(new BigDecimal("0"));
    order.setUserid(userId);
    order.setNickName("未知用户");
    order.setAddress("异常信息: "+e.getClass());
​
    return  order;
}

所以我们的@SentinelResource注解多半不要写在controller层面进行使用。

远程调用的流控

当我们的OpenFigen进行远程调用的时候进行限流,它起始就是我们最开始进行的OpenFigen远程调用的时候写的一个兜底原则

java 复制代码
package com.kang.order.feign.fallback;
import java.math.BigDecimal;
​
import com.kang.order.feign.ProductFeignClient;
import com.kang.product.bean.Product;
import org.springframework.stereotype.Component;
​
@Component
public class ProductFeignClientFallback implements ProductFeignClient {
    @Override
    public Product getProductById(Long productId) {
        System.out.println("回调函数实现了");
        Product Product = new Product();
        Product.setId(0L);
        Product.setPrice(new BigDecimal("0"));
        Product.setProductName("未知商品");
        Product.setNum(0);
​
        return Product;
    }
}

当我们的OpenFigen远程调用失败的时候就会走fallback进行一个兜底的返回。

SphU硬编码

java 复制代码
try {
    SphU.entry("createOrder")
} catch (BlockException e) {
    throw new RuntimeException(e);
}

当我们想要对某一段代码进行检查的时候,就可以使用SphU.entry方法,这个方法需要进行try/catch方法进行包裹,异常处理在catch里面进行处理就可以了。

流控规则

当客户端发送大量请求的时候,Sentinel就可以进行请求的限流,防止多余的请求,保护系统的资源不被浪费。

我们使用链路进行流控的时候需要注意在yaml文件里面关闭上下文配置web-context-unify: false,这样才能够在簇点链路里面找到两个。

当我们对方法中的特定方法进行配置的时候就可以指定路径,最终达到只在某一路径下进行限流设置,使得我们可以只在某一个访问路径下,相同的访问方法,但是却有不同的限流策略。

当我们进行关联的时候,就可以对关联的资源进行限流

java 复制代码
@GetMapping("/readDb")
public String readDb(){
    return "readDb success---------";
}
@GetMapping("/writeDb")
public String writeDb(){
    return "writeDb success---------";
}

虽然是关联策略,但是需要注意的是,只有当我们进行readDb操作的时候,然后突然访问writeDb的情况下才会出现限流。

流控效果的快速失败也就是在同一节点下,打过来的请求都会失效,Warm Up也就是越热,当我们的请求过多的时候,它会先进行几秒钟的预热,然后再达到高水平的执行。而排队等待就是当我们设置的阈值达到的时候进行等待,等待时间超过我们设置的值,就会丢弃。

注意:排队等待,warm up不支持关联和链路状态下的模式。

熔断降级

熔断降级通常是为了保护自身,我们通常在客户端进行配置。为了防止多个远程调用之间,出现雪崩问题,所以我们就可以使用熔断降级。

熔断降级里面有如图所示的三种规则,而慢调用比例的规则就是当我们最大的响应时间为1000ms,然后80%的请求出现问题,就会出现熔断10秒。

当我们使用异常比例进行熔断策略的时候,事实上达成熔断的要求时请求就会直接进行回调函数。所以,当我们有了熔断策略的时候我们的程序就会更加的健壮。

异常数也很简单,当我们设置好之后,无论发送多少请求,我们的请求只要异常数达到了异常数的设置值,那么都将是错误的,直接进行回调函数。

热点限流规则

热点就是我们经常访问的数据,事实上热点限制的规则就是将请求进行了精细化,也就是说我们可以对特定的商品或者库存,这个时候就可以对其进行了限流。

当我们进行热点限流的时候,需要注意,首先我们想对某一个模块,只允许一条线路进行运行,这个时候sentinel就需要对请求的参数进行判断了,只有当我们不允许有默认值的时候,这个时候就可以进行热点限流了。

我们进行这样的限流之后就可以设置热点规则了:

这样设置就可以对userId进行限流了,只有当我们带userId的时候才会对其进行限流。

当我们想对某一个特定的用户进行不限流的时候就可以这样设置:

当我们想对达到下架商品的效果的时候,就可以进以下设置,也就是说,需要注意的就是,我们对商品进行限制的时候,就需要进行新的限流规则,因为最开始我们设置的就是用户的限流规则。

补充:

fallback和blockHandler,我们注解进行策略的时候是先进行blockHandler然后再进行fallback,如果我们是进行fallback进行兜底返回的话,那么在我们的兜底回调的时候就需要进行异常的修改