SpringCloud Alibaba(中):服务熔断降级-Sentinel

Sentinel

Sentinel是阿里巴巴开源的分布式系统流量防卫防护组件,主要对分布式系统中的流量进行控制、熔断降级等保护操作。Sentinel的目标是成为互联网级别分布式系统的流量防卫防护组件,它与系统的各个部分集成,保护着系统的入口和出口。

概念:

Sentinel是一个分布式系统的流量防卫防护组件,它通过对分布式系统中的流量进行控制、熔断降级等保护操作,保障系统的稳定性和可用性。

背景:

随着分布式系统的广泛应用,系统的复杂度和耦合度越来越高,系统中的流量控制和保护变得越来越重要。Sentinel正是在这样的背景下诞生的,它通过流量控制、熔断降级等手段,保护着分布式系统的入口和出口,保障系统的稳定性和可用性。

运用:

Sentinel可以运用于各种分布式系统中,例如微服务架构、SOA架构等。它对系统的各个部分进行流量控制、熔断降级等保护操作,从而提高系统的可用性和稳定性。

定位:

Sentinel主要定位于分布式系统的流量防卫防护组件,它与系统的各个部分集成,对系统的入口和出口进行保护。它不仅提供流量控制、熔断降级等基础功能,还支持自定义策略和插件扩展,可以满足不同场景下的需求。

使用:

Sentinel的使用非常简单,可以通过配置文件或API进行配置和调用。它提供了丰富的统计数据和监控信息,方便用户对系统进行监控和管理。同时,Sentinel还提供了多种语言的客户端库,方便用户进行集成和使用。

API:

Sentinel提供了丰富的API供用户进行自定义策略和插件扩展。它的API包括流量控制、熔断降级、系统调用等各个方面。用户可以通过调用这些API实现自定义的流量控制和熔断降级策略。

Sentinel可以通过这些 API 来设置流量控制规则、获取系统状态、执行流量控制等操作。例如,FlowRuleManager.loadRules() 方法可以加载流量控制规则;SystemStateManager.getBlockQpsInInterval(String resource, Duration interval) 方法可以获取资源在特定时间段内的被限流次数等。

总结:

Sentinel是一个分布式系统的流量防卫防护组件,它通过对分布式系统中的流量进行控制、熔断降级等保护操作,保障系统的稳定性和可用性。它具有简单易用、灵活可扩展等特点,可以适用于各种分布式系统中。


常见的容错思路

​ 要防止雪崩的扩散,我们就要做好服务的容错,容错说白了就是保护自己不被猪队友拖垮的一些措施, 下面介绍常见的服务容错思路和组件。

常见的容错思路

常见的容错思路有隔离、超时、限流、熔断、降级这几种,下面分别介绍一下。

  • 隔离机制: 比如服务A内限制有100个线程, 现在服务A可能会调用服务B,服务C,服务D.我们在服务A进行远程调用的时候,给不同的服务分配固定的线程,不会把所有线程都分配给某个微服务. 比如调用服务B分配30个线程,调用服务C分配30个线程,调用服务D分配40个线程. 这样进行资源的隔离,保证即使下游某个服务挂了,也不至于把服务A的线程消耗完。比如服务B挂了,这时候最多只会占用服务A的30个线程,服务A还有70个线程可以调用服务C和服务D.
  • 超时机制: 在上游服务调用下游服务的时候,设置一个最大响应时间,如果超过这个时间,下游未作出反应,

    就断开请求,释放掉线程。

  • 限流机制: 限流就是限制系统的输入和输出流量已达到保护系统的目的。为了保证系统的稳固运行,一旦达到

    的需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的目的。

  • 熔断机制: 在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整

    体的可用性,可以暂时切断对下游服务的调用。这种牺牲局部,保全整体的措施就叫做熔断。

服务熔断一般有三种状态:

  • 熔断关闭状态(Closed)

服务没有故障时,熔断器所处的状态,对调用方的调用不做任何限制

  • 熔断开启状态(Open)

后续对该服务接口的调用不再经过网络,直接执行本地的fallback方法

  • 半熔断状态(Half-Open)

尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率。如果成功率达到预

期,则说明服务已恢复,进入熔断关闭状态;如果成功率仍旧很低,则重新进入熔断开启状

态。

  • 降级机制: 降级其实就是为服务提供一个兜底方案,一旦服务无法正常调用,就使用兜底方案。

Sentinel流量控制规则

Sentinel具有流控、热点、降级、授权和系统规则保护等功能。

流控是指控制分布式系统的流量,防止系统被过大的流量击垮。Sentinel可以通过设置流量控制阈值,对超过阈值的流量进行限流操作。

热点是指系统中访问频率较高的部分,通常是系统的瓶颈所在。Sentinel可以通过热点限流功能,对热点流量进行限制,避免热点流量过大导致系统崩溃。

降级是指当系统出现故障或响应过慢时,通过降低部分功能或服务的等级,保证整个系统的可用性。Sentinel可以通过降级功能,对故障的服务进行降级处理,避免故障影响整个系统的运行。

授权是指对不同的用户或服务设置不同的访问权限,保证系统的安全性。Sentinel可以通过设置黑白名单规则,对指定的用户或服务进行授权操作。

系统规则保护是指对系统的入口和出口进行保护,防止系统被恶意攻击或滥用。Sentinel可以通过设置系统保护规则,对系统的入口和出口进行防护操作。


sentinel 自定义异常 + @sentinelresources 注解使用

Sentinel 可以通过自定义异常和 @SentinelResource 注解来提供更加灵活的保护机制。

首先,Sentinel 允许用户自定义异常处理类,通过继承 BlockException 类并重写其中的方法,可以定制异常处理逻辑。同时,在定义资源时,可以使用 @SentinelResource 注解来指定异常处理类,以便在发生异常时执行自定义的异常处理逻辑。

  • FlowException 限流异常

  • DegradeException 降级异常

  • ParamFlowException 参数限流异常

  • AuthorityException 授权异常

  • SystemBlockException 系统负载异常

在shop-order-server项目中定义异常返回处理类

java 复制代码
package cn.wolfcode.error;
@Component
public class ExceptionHandlerPage implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        response.setContentType("application/json;charset=utf-8");
        ResultData data = null;
        if (e instanceof FlowException) {
            data = new ResultData(-1, "接口被限流了");
        } else if (e instanceof DegradeException) {
            data = new ResultData(-2, "接口被降级了");
        }else if (e instanceof ParamFlowException) {
            data = new ResultData(-3, "参数限流异常");
        }else if (e instanceof AuthorityException) {
            data = new ResultData(-4, "授权异常");
        }else if (e instanceof SystemBlockException) {
            data = new ResultData(-5, "系统负载异常了...");
        }
        response.getWriter().write(JSON.toJSONString(data));
    }
}
@Data
@AllArgsConstructor//全参构造
@NoArgsConstructor//无参构造
class ResultData {
    private int code;
    private String message;
}

其次,@SentinelResource 注解可以用于定义资源并提供可选的异常处理和 fallback 配置项。通过使用 @SentinelResource 注解,用户可以方便地将特定的类、方法或函数定义为资源,并在其中配置异常处理和 fallback 逻辑。这样,在系统运行时,Sentinel 可以自动对这些资源进行保护,确保系统的稳定性和可用性。

@SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项。

其主要参数如下:

属性 作用
value 资源名称,必需项(不能为空)
entryType entry 类型,可选项(默认为 EntryType.OUT
blockHandler/blockHandlerClass blockHandler 对应处理 BlockException 的函数名称,可选项。blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
fallback/fallbackClass fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求: 1. 返回值类型必须与原函数返回值类型一致; 2.方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。 3.fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
defaultFallback 默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback 函数签名要求: 1. 返回值类型必须与原函数返回值类型一致; 2. 方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。 3. defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
exceptionsToIgnore 用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

定义限流和降级后的处理方法

直接将限流和降级方法定义在方法中

java 复制代码
package cn.wolfcode.controller;
@RestController
@Slf4j
public class AnnoController {
    @RequestMapping("/anno1")
    @SentinelResource(value = "anno1",
            blockHandler="anno1BlockHandler",
            fallback = "anno1Fallback"
    )
    public String anno1(String name){
        if("wolfcode".equals(name)){
            throw new RuntimeException();
        }
        return "anno1";
    }
    public String anno1BlockHandler(String name,BlockException ex){
        log.error("{}", ex);
        return "接口被限流或者降级了";
    }
    //Throwable时进入的方法
    public String anno1Fallback(String name,Throwable throwable) {
        log.error("{}", throwable);
        return "接口发生异常了";
    }
}

Feign整合Sentinel

  1. 在shop-order-server项目的配置文件中开启feign对Sentinel的支持

    yaml 复制代码
    feign:
      sentinel:
        enabled: true
  2. 创建容错类

    java 复制代码
    @Component
    public class ProductFeignFallBack implements IProductFeginService {
        @Override
        public Product findByPid(Long pid) {
            Product product = new Product();
            product.setPid(-1L);
            product.setPname("兜底数据");
            product.setPprice(0.0);
            return product;
        }
    }
  3. 在feign接口中定义容错类

    java 复制代码
    @FeignClient(name = "product-service",fallback = ProductFeignFallBack.class)
    public interface ProductFeignApi {
        @RequestMapping("/product/{pid}")
        public Product findByPid(@PathVariable("pid") Long pid);
    }
  4. 停止所有 商品服务,重启 shop-order 服务,访问请求,观察容错效果

可能上面的案例并不是特别恰当,我们只是通过案例来演示Feign集成Sentinel实现降级的效果. 接下来我们具体更贴切的案例来讲解Feign降级的作用.

比如我们在购物的时候,查看商品详情页面的时候,里面包含库存信息,商品详情信息,评论信息,这个需求包含的微服务如下:

假设现在评论服务宕机了,那是不是意味用户发出查看商品请求也无法正常显示了,商品都看不到了,那用户也无法进行下单的操作了. 但是对于用户来说,评论看不到并不影响他购物,所以这时候我们应该对评论服务进行及·降级处理,返回一个兜底数据(空数据),这样用户的查看商品请求能正常显示,只是评论数据看不到而已,这样的话,用户的下单请求也不会受到影响。

面试题:结合Feign后,你在项目中的降级方法中会实现什么样的操作/功能?

  • 记录操作日志,业务日志
  • 尝试重试操作
  • 记录操作失败信息(MQ),方便后续人工介入
  • 异常提示
相关推荐
荆州克莱7 小时前
Vue3 源码解析(三):静态提升
spring boot·spring·spring cloud·css3·技术
AskHarries16 小时前
如何将Spring Cloud Task发布Data Flow上执行?
java·后端·spring cloud
Grey_fantasy18 小时前
高级编程之结构化代码
java·spring boot·spring cloud
.生产的驴20 小时前
SpringCloud OpenFeign用户转发在请求头中添加用户信息 微服务内部调用
spring boot·后端·spring·spring cloud·微服务·架构
爱加瓦小瑞小瑞1 天前
Sentinel服务保护
sentinel
一元咖啡1 天前
SpringCloud Gateway转发请求到同一个服务的不同端口
spring·spring cloud·gateway
天天扭码1 天前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
跳跳的向阳花1 天前
03-03、SpringCloud第三章,负载均衡Ribbon和Feign
spring cloud·ribbon·负载均衡
天天扭码2 天前
五天SpringCloud计划——DAY1之mybatis-plus的使用
java·spring cloud·mybatis