分布式系统Sentinel整合Open-Feign限流


一、前言

提示:本文讲到的代码部分来自上文
上文链接地址

二、sentinel控制台

1、调用与被调用方引入依赖

        <!--sentinel依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

2、控制台搭建

控制台搭建地址
下载安装包sentinel-dashboard-1.8.0.jar

3、启动

//启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本,
//-Dserver.port=8100 用于指定 Sentinel 控制台端口为 8100 
//默认用户名和密码都是 sentinel
​
//普通进程
java -Dserver.port=8100 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar

//守护进程
nohup java -Dserver.port=8100 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar &

在这里插入图片描述

三、限流配置

1、多个微服务接入Sentinel配置

调用与被调用都需配置port不一样

spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080 
        port: 9999#dashboard: 8080 控制台端口
#port: 9999 本地启的端口,随机选个不能被占用的,与dashboard进行数据交互,会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互, 若被占用,则开始+1一次扫描

在这里插入图片描述
设置QPS单机阀值为2,一秒大于两个会被流控
在这里插入图片描述
效果图
在这里插入图片描述

四、面板介绍

资源名:默认是请求路径,可自定义
针对来源:对哪个微服务进行限流,默认是不区分来源,全部限流,这个是针对区分上游服务进行限流, 比如 other1服务 被 other2服务、other3服务调用,就可以针对来源进行限流
在这里插入图片描述

  • 流量控制(flow control)
    原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。

  • 两种规则

    • 基于统计并发线程数的流量控制
      并发数控制用于保护业务线程池不被慢调用耗尽
      Sentinel 并发控制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目(正在执行的调用数目)
      ​如果超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。

    • 基于统计QPS的流量控制
      当 QPS 超过某个阈值的时候,则采取措施进行流量控制(一秒内访问)

  • 流量控制的效果包括以下几种

    • 直接拒绝:默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝
    • Warm Up:冷启动/预热,如果系统在此之前长期处于空闲的状态,我们希望处理请求的数量是缓步的增多,经过预期的时间以后,到达系统处理请求个数的最大值
    • 匀速排队:严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法,主要用于处理间隔性突发的流量,如消息队列,想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求
      • 匀速排队等待策略是 Leaky Bucket 算法结合虚拟队列等待机制实现的。
        匀速排队模式暂时不支持 QPS > 1000 的场景

Warm Up:冷启动/预热,如果系统在此之前长期处于空闲的状态,我们希望处理请求的数量是缓步的增多,经过预期的时间以后,到达系统处理请求个数的最大值

五、基于并发线程数进行限流配置

流控规则会下发到微服务,微服务如果重启,则流控规则会消失可以持久化配置

@RestController
@RequestMapping("other2")
public class OtherController2 {
    /**
     * 基于并发线程数进行限流配置,测试
     * @return
     */
    @RequestMapping("getusername6")
    String getusername6() {
        try {
            TimeUnit.SECONDS.sleep(3);//让程序睡三秒中达到延迟效果
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "other2的getUserName6反回的数据";
    }
}

在这里插入图片描述

在这里插入图片描述

六、降级熔断策略

  • 慢调用比例(响应时间): 选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用

    • 比例阈值:修改后不生效-目前已经反馈给官方那边的bug
    • 熔断时长:超过时间后会尝试恢复
    • 最小请求数:熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断
  • 异常比例:当单位统计时长内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断

    • 比例阈值
    • 熔断时长:超过时间后会尝试恢复
    • 最小请求数:熔断触发的最小请求数,请求数小于该值时,即使异常比率超出阈值也不会熔断
  • 异常数:当单位统计时长内的异常数目超过阈值之后会自动进行熔断

    • 异常数:
    • 熔断时长:超过时间后会尝试恢复
    • 最小请求数:熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断

在这里插入图片描述
在这里插入图片描述

1、熔断实操

测试代码

@RestController
@RequestMapping("other2")
public class OtherController2 {
    int temp = 0;

    /**
     * 熔断,测试
     * @return
     */
    @RequestMapping("getusername7")
    String getusername7() {
        temp++;
        if(temp%3 == 0){
            throw  new RuntimeException();
        }
        return "other2的getUserName7反回的数据";
    }
}

在这里插入图片描述

在这里插入图片描述

2、自定义降级异常数据

  • 异常种类
    • FlowException //限流异常
      DegradeException //降级异常
      ParamFlowException //参数限流异常
      SystemBlockException //系统负载异常
      AuthorityException //授权异常

实现BlockExceptionHandler并且重写handle方法

调用方

@Component
public class OtherConfig2 implements BlockExceptionHandler {

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse   httpServletResponse, BlockException e) throws Exception {
        Map<String, Object> backMap = new HashMap<>();
        if (e instanceof FlowException) {
            backMap.put("code", -1);
            backMap.put("msg", "限流-异常啦");
            backMap.put("data", null);
        } else if (e instanceof DegradeException) {
            backMap.put("code", -2);
            backMap.put("msg", "降级-异常啦");
            backMap.put("data", null);
        } else if (e instanceof ParamFlowException) {
            backMap.put("code", -3);
            backMap.put("msg", "热点-异常啦");
            backMap.put("data", null);
        } else if (e instanceof SystemBlockException) {
            backMap.put("code", -4);
            backMap.put("msg", "系统规则-异常啦");
            backMap.put("data", null);
        } else if (e instanceof AuthorityException) {
            backMap.put("code", -5);
            backMap.put("msg", "认证-异常啦");
            backMap.put("data", null);
        }

        // 设置返回json数据
        httpServletResponse.setStatus(200);//响应消息的状态码
        httpServletResponse.setHeader("content-Type", "application/json;charset=UTF-8");
        httpServletResponse.getWriter().write(JSON.toJSONString(backMap, SerializerFeature.WriteMapNullValue));

    }
}

效果图
在这里插入图片描述

七、Sentinel整合OpenFeign配置容错设计实战

但是Feign在调用远程服务的时候,由于远程服务的原因,可能会产生异常。就需要进行相应的容错设计。
当Feign远程调用服务出现问题后,进入到了容错工厂类中的同名方法,执行容错逻辑。而且,Feign调用产生的异常信息也可以获取到。

1、加入依赖

        <!--sentinel依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

2、开启Feign对Sentinel的支持

调用方

#开启Feign对Sentinel的支持
feign:
  sentinel:
    enabled: true

3、配置feign容错类

调用方的service

@FeignClient(value = "spring-other1" ,fallback = OtherServiceFallBack2.class)//服务名称记得和nacos保持一样

例如

@FeignClient(value = "spring-other1" ,fallback = OtherServiceFallBack2.class)//服务名称记得和nacos保持一样
public interface OtherService2 {

    /**
     * 新建接口用于调用Other的getUserName2接口服务
     *
     * @param userName
     * @return
     */
    @RequestMapping("/other1/getusername2")
    String getOther1UserName2(@RequestParam("name") String userName);
}

4、FallBack类继承外调service接口

@Service
public class OtherServiceFallBack2 implements OtherService2 {
    @Override
    public String getOther1UserName2(String userName) {
        return userName+"——该返回为异常返回";
    }
}

5、调用方controller

@RestController
@RequestMapping("other2")
public class OtherController2 {
    /**
     * 使用Open-Feign
     *
     * @param userName
     * @return
     */
    @RequestMapping("getusername4")
    String getUserName4(@RequestParam("name") String userName) {
        String other1UserName2 = otherService2.getOther1UserName2(userName);
        //写入服务名即可
        return other1UserName2 + "-该字段为other2的getUserName反回的数据";
    }
}

6、当被调用方服务出现宕机异常

效果图
在这里插入图片描述

八、升级jdk11

下载jdk11
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
maven项目配置

    <properties>
        <java.version>11</java.version>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>
<think>好的,用户之前问过Java服务之间的相互调用,现在又询问OpenFeign的作用。我需要先回忆一下之前的对话内容,确保这次回答的一致性和连贯性。用户之前得到的信息包括RESTful API、RPC、消息队列和服务网格等,其中Feign Client作为Spring Cloud中的声明式HTTP客户端被提到过。现在用户可能对Feign的具体作用和优势感兴趣。 首先,要明确OpenFeign是什么。它是Netflix开发的,后来成为Spring Cloud的一部分,所以需要说明它是一个声明式的HTTP客户端,用于简化服务间的HTTP调用。用户可能想知道它和之前提到的RestTemplate或WebClient有什么不同,所以需要强调声明式编程的优点,比如接口和注解的使用,减少了模板代码。 接下来,要解释OpenFeign的核心作用。需要分点列出,比如声明式调用、集成服务发现、负载均衡、与Ribbon和Eureka的集成,以及拦截器和日志的支持。用户可能关心它在微服务架构中的实际应用,比如如何通过定义接口来调用其他服务,而无需手动处理HTTP请求。 然后,需要说明它的优点。比如简化开发、与Spring Cloud生态的集成、可扩展性等。用户可能想知道为什么选择OpenFeign而不是其他方式,比如直接使用RestTemplate,所以需要对比两者的差异,突出OpenFeign的高效和便捷。 使用示例部分要具体,展示一个简单的接口定义,让用户直观理解如何使用注解和方法定义来发起请求。这部分需要代码示例,但用户可能需要的是简洁的解释,所以用文字描述即可,避免过于复杂。 适用场景方面,需要结合之前的回答,比如在Spring Cloud微服务中,需要内部服务调用,或者需要快速开发的情况。用户可能是在设计微服务架构,需要选择合适的工具,所以强调OpenFeign在微服务中的常见用途。 最后,总结OpenFeign的作用,并和之前的调用方式对比,比如RestTemplate,说明它的优势。可能还要提到与其他工具如gRPC的区别,但用户的问题主要集中在HTTP调用,所以可以集中在Feign本身的特性。 需要确保回答清晰,结构分明,避免技术术语过多,但又要足够详细,满足用户的技术需求。同时,检查是否有遗漏的关键点,比如与Hystrix的整合、配置选项等,但根据问题,可能不需要深入这些细节,除非用户后续提问。</think>OpenFeign 是一个 **声明式 HTTP 客户端框架**,主要用于 **简化 Java 服务之间的 HTTP 调用**。它是 Spring Cloud 生态中的重要组件,通过接口和注解的方式,将服务间 RESTful API 的调用变得像调用本地方法一样简单。 --- ### **核心作用** 1. **声明式调用** - 开发者只需定义一个 Java 接口,并通过注解(如 `@FeignClient`、`@GetMapping`)声明远程调用的目标服务、路径和参数,无需手动编写 HTTP 请求代码。 - **示例**: ```java @FeignClient(name = "order-service") // 指定目标服务名称 public interface OrderServiceClient { @GetMapping("/orders/{orderId}") // 定义 REST 接口 Order getOrderById(@PathVariable("orderId") String orderId); } ``` 2. **集成服务发现与负载均衡** - 结合 **Eureka**、**Nacos** 等服务注册中心,自动解析服务名称对应的实例地址。 - 默认集成 **Ribbon** 客户端负载均衡,自动选择可用服务实例。 3. **统一配置与扩展** - 支持自定义编码器/解码器(如 JSON、XML)、拦截器(添加请求头、日志等)。 - 可集成 **Hystrix** 或 **Sentinel** 实现熔断降级,增强容错能力。 --- ### **核心优势** | 对比传统方式(如 RestTemplate) | OpenFeign 的优势 | |-------------------------------|------------------| | 需手动拼接 URL、处理请求/响应 | **声明式接口**:通过注解自动生成 HTTP 请求代码 | | 需自行处理服务发现和负载均衡 | **与服务注册中心无缝集成**,自动发现服务实例 | | 代码冗余,维护成本高 | **代码简洁**,接口即文档,易维护 | | 熔断、日志等功能需额外开发 | **可扩展性强**,轻松集成 Spring Cloud 生态组件 | --- ### **适用场景** 1. **微服务间 RESTful API 调用** 在 Spring Cloud 微服务架构中,服务 A 通过 OpenFeign 调用服务 B 的 REST 接口(如查询订单、扣减库存)。 2. **需要快速开发的场景** 通过接口定义直接生成客户端代码,减少重复劳动。 3. **需要统一治理调用的场景** 结合 Hystrix/Sentinel 实现熔断,结合 Sleuth 实现调用链路追踪。 --- ### **示例流程** 1. **服务提供者**(如 `order-service`)暴露 REST API: ```java @RestController public class OrderController { @GetMapping("/orders/{orderId}") public Order getOrder(@PathVariable String orderId) { // 查询订单逻辑 } } ``` 2. **服务消费者**通过 OpenFeign 调用: ```java @Autowired private OrderServiceClient orderServiceClient; // 注入 Feign 客户端 public void processOrder(String orderId) { Order order = orderServiceClient.getOrderById(orderId); // 像调用本地方法一样 // 后续业务逻辑 } ``` --- ### **总结** OpenFeign 的核心价值是 **将远程 HTTP 调用抽象为本地接口调用**,开发者只需关注业务逻辑,而无需处理 HTTP 通信细节。它降低了微服务间调用的复杂度,是 Spring Cloud 中实现服务通信的推荐方式之一。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

和烨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值