springcloud04——网关gateway、熔断器 sentinel

发布于:2025-08-01 ⋅ 阅读:(22) ⋅ 点赞:(0)

目录

注册中心 nacos | eurekaServer |zookeeper(dubbo)

配置中心 nacos | config Server

远程服务调用 httpClient | RestTemplate | OpenFeign

负载均衡服务 ribbon | loadbalancer

网关 zuul | gateway

熔断器 hystrix | sentinel

网关

sentinel

流控

压测工具

1、作用

2、熔断

3、降级

配置启动sentinel

注册微服务到sentinel

测试流控

降级测试

流控模式详解

Sentinel 流控效果详解

hystrix 熔断器


注册中心 nacos | eurekaServer |zookeeper(dubbo)

配置中心 nacos | config Server

远程服务调用 httpClient | RestTemplate | OpenFeign

负载均衡服务 ribbon | loadbalancer

网关 zuul | gateway

熔断器 hystrix | sentinel

网关

1、统一项目入口 不需要关注每一个微服务的ip和端口,客户端只需要网关的ip和端口

2、路由功能 转发请求到达目标服务

网关的配置文件,通过路由鉴权(断言匹配,路由地址匹配,路径匹配),满足规则,转发请求到目标服务

- id: provider
#          uri: http://localhost:8080/  #静态路由
          uri: lb://provider    #动态路由
          predicates:   #断言匹配
            - Path=/pro/**
          filters:
            - RewritePath=/pro/(?<segment>.*), /p/$\{segment}
#            - StripPrefix=1  #删除前缀路径  删除一层
#            - PrefixPath=/p
            - AddRequestParameter=name,zhangsan

3、过滤无效请求,减少对目标服务器的压力,可以同时起到安全性作用

4、负载均衡服务器 负载均衡算法(轮询、随机) nginx(反向代理和负载均衡服务器)

5、局部过滤器

修改请求路径 StripPrefix=1 删除一层路径

- RewritePath=/pro/(?<segment>.*), /p/${segment} 重写路径

添加请求头 AddRequestHeader

添加请求参数 AddRequestparameter=key,value

6、全局过滤器

package com.hl.filter;
​
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
​
/*
全局过滤器
 */
@Component
public class GlobalGatewayFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("filter.........");
        //放行,继续到达下一个过滤器
        return chain.filter(exchange);
    }
    //数字越小,执行越往前
    @Override
    public int getOrder() {
        return 0;
    }
}
  • GlobalFilter 全局过滤器,不需要在配置文件中配置,系统初始化时加载,并作用在每个路由上。

  • Spring Cloud Gateway 核心的功能也是通过内置的全局过滤器来完成。

sentinel

限流、降级

资源Sentinel中的核心概念之一。我们说的资源,可以是任何东西,服务,服务里的方法,甚至是一段代码。最常用的资源是我们代码中的Java方法。Sentinel提供了@SentinelResource注解用于定义资源,并提供了AspectJ的扩展用于自动定义资源、处理BlockException等。

流控

  • QPS(每秒请求数量):当调用该api的QPS达到阈值的时候,进行限流

  • 线程数:当调用该api的线程数达到阈值的时候,进行限流

压测工具

压力测试工具,jmeter

1、作用

  • 为什么要使用熔断和降级

在一个分布式系统里,一个服务依赖多个服务,可能存在某个服务调用失败,比如超时、异常等,需要保证在一个依赖出问题的情况下,不会导致整体服务失败。

2、熔断

暂时中断程序,稍后可继续访问。

3、降级

走降级方案,返回之前指定的失败给用户。(柔性失败)

避免服务整体崩溃,系统宕机。让当前方法失败,返回失败响应给调用者。

配置启动sentinel

1、下载安装包 https://github.com/alibaba/Sentinel/releases

2、启动(win+r    cmd)

java  -Dserver.port=8718  -jar 安装包路径/安装包名称
​
 
java  -Dserver.port=8718 -Dcsp.sentinel.dashboard.server=localhost:8718 -Dproject.name=sentinel-dashboard -Dcsp.sentinel.api.port=8719 -jar D:\IDEA2024\sentinel-dashboard-1.8.0.jar

默认用户名:sentinel

密码: sentinel

注册微服务到sentinel

配置文件:

# Nacos帮助文档: https://nacos.io/zh-cn/docs/concepts.html
# Nacos认证信息
spring.cloud.nacos.config.username=nacos
spring.cloud.nacos.config.password=nacos
spring.cloud.nacos.config.contextPath=/nacos
# 设置配置中心服务端地址
spring.cloud.nacos.config.server-addr=localhost:8848
# Nacos 配置中心的namespace。需要注意,如果使用 public 的 namcespace ,请不要填写这个值,直接留空即可
# spring.cloud.nacos.config.namespace=
spring.config.import=nacos:product.yml?refresh=true
​
​
​
# Nacos帮助文档: https://nacos.io/zh-cn/docs/concepts.html
spring.application.name=product
​
​
​
# Nacos认证信息
spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos
# Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
spring.cloud.nacos.discovery.server-addr=localhost:8848
# 注册到 nacos 的指定 namespace,默认为 public
spring.cloud.nacos.discovery.namespace=public
​
​
# 应用服务 WEB 访问端口
server.port=8088
# Sentinel 控制台地址
spring.cloud.sentinel.transport.dashboard=localhost:8718
# 取消Sentinel控制台懒加载
# 默认情况下 Sentinel 会在客户端首次调用的时候进行初始化,开始向控制台发送心跳包
# 配置 sentinel.eager=true 时,取消Sentinel控制台懒加载功能
spring.cloud.sentinel.eager=true
# 如果有多套网络,又无法正确获取本机IP,则需要使用下面的参数设置当前机器可被外部访问的IP地址,供admin控制台使用
# spring.cloud.sentinel.transport.client-ip=

测试流控

@RestController
@RequestMapping("/demo")
public class DemoController {
​
    @Autowired
    private DemoService demoService;
​
    @GetMapping("/bonjour/{name}")
    public String apiSayHelloLocal(@PathVariable String name) throws Exception {
        for(int i = 1;i<10;i++){
            String s1 = demoService.bonjour(name);
            System.out.println(s1);
        }
        return ff;
    }
@Service
public class DemoService {
    @SentinelResource(value = "DemoService#bonjour",
            defaultFallback = "bonjourFallback")
    public String bonjour(String name) throws Exception {
        return "Bonjour, " + name;
    }
​
    public String bonjourFallback(Throwable t) {
        if (BlockException.isBlockException(t)) {
            return "Blocked by Sentinel: " + t.getClass().getSimpleName();
        }
        return "Oops, failed: " + t.getClass().getCanonicalName();
    }
}

降级测试

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
​
package com.hl.product.demos.sentinel;
​
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
​
/**
 * @author Eric Zhao
 */
@RestController
@RequestMapping("/demo")
public class DemoController {
​
    @Autowired
    private DemoService demoService;
​
    @GetMapping("/bonjour/{name}")
    public String apiSayHelloLocal(@PathVariable String name) throws Exception {
        boolean flag = true;
        String s0 = demoService.bonjour(name,flag);
        System.out.println(s0);
​
        flag = false;
        for(int i = 1;i<10;i++){
            String s1 = demoService.bonjour(name,flag);
            System.out.println(s1);
        }
        System.out.println("---------------");
        flag = true;
        String ff = demoService.bonjour(name,flag);
        System.out.println(ff);
​
        return ff;
    }
​
​
}
/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
​
package com.hl.product.demos.sentinel;
​
import org.springframework.stereotype.Service;
​
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
​
/**
 * @author Eric Zhao
 */
@Service
public class DemoService {
    @SentinelResource(value = "DemoService#bonjour",
            defaultFallback = "bonjourFallback")
    public String bonjour(String name,Boolean flag) throws Exception {
        if(flag == false){
            throw new Exception("异常。。。。。。");
        }
        return "Bonjour, " + name;
    }
​
    public String bonjourFallback(Throwable t) {
        if (BlockException.isBlockException(t)) {
            return "Blocked by Sentinel: " + t.getClass().getSimpleName();
        }
        return "Oops, failed: " + t.getClass().getCanonicalName();
    }
}
/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.hl.product.demos.sentinel;

import java.io.PrintWriter;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;

/**
 * @author Eric Zhao
 */
@Configuration
public class SentinelWebConfig {

    @Bean
    public BlockExceptionHandler sentinelBlockExceptionHandler() {
        return (request, response, e) -> {
            // 429 Too Many Requests
            response.setStatus(429);

            PrintWriter out = response.getWriter();
            out.print("Oops, blocked by Sentinel: " + e.getClass().getSimpleName());
            out.flush();
            out.close();
        };
    }
}

流控模式详解

  1. 直接模式

    • 概念:直接模式是最基本的流控模式。它是对当前资源(接口或方法)本身的请求进行流量控制。当请求到达被保护的资源时,Sentinel 会直接根据设置的规则(如 QPS 阈值、并发线程数阈值等)来判断是否允许该请求通过。

    • 示例:假设有一个用户登录接口/login,设置其 QPS(每秒查询率)的直接流控阈值为 100。这意味着当每秒请求该/login接口的次数超过 100 时,Sentinel 就会开始进行流量控制,可能会对超出的请求进行限流(如直接拒绝、排队等待等处理方式)。

    • 应用场景:适用于对单一资源的流量进行简单直接的控制,比如限制某个核心 API 接口的访问频率,以防止该接口被过度调用而导致系统崩溃或性能下降。

  2. 关联模式

    • 概念:关联模式是一种相对复杂的流控方式。它主要用于当两个资源之间存在关联关系时,通过对其中一个资源的流量控制来间接控制另一个资源的流量。当关联的资源 A 达到流控阈值时,就会对目标资源 B 进行流量控制。

    • 示例:考虑一个电商系统,有一个商品详情接口/product/detail和一个购买接口/product/buy。这两个接口是关联的,因为用户在查看商品详情后可能会进行购买。如果设置/product/detail接口与/product/buy接口为关联模式,并且当/product/detail的 QPS 达到某个阈值(如 50)时,开始对/product/buy接口进行流量控制,比如限制/product/buy接口的 QPS 为 30。这样可以防止在商品详情页被大量访问时,购买接口被过度请求而导致库存系统等后端服务压力过大。

    • 应用场景:常用于存在先后调用关系或者关联关系的资源之间,例如在一个业务流程中,前一个步骤的操作频繁可能会导致后一个步骤的服务压力过大,通过关联模式可以提前控制后一个步骤的流量。

  3. 链路模式

    • 概念:链路模式主要是从调用链路的角度进行流量控制。它会根据请求的调用链路来判断是否进行流量控制。在微服务架构或者复杂的分布式系统中,一个请求可能会经过多个服务和方法的调用链路。Sentinel 链路模式可以针对特定的调用链路进行流控,而不是简单地基于资源本身。

    • 示例:假设有一个分布式系统,包括服务 A、服务 B 和服务 C。服务 A 调用服务 B,服务 B 又调用服务 C。在服务 B 中有一个方法methodB,在链路模式下,可以针对从服务 A - 服务 B - 服务 C 这个特定链路中对methodB进行流量控制。如果在其他链路中也调用了methodB,只要不是这个特定的链路,就不受这个链路模式下的流控规则限制。

    • 应用场景:特别适用于微服务架构和复杂的分布式系统,能够精确地对特定的调用链路进行流量管理,避免因为某个链路的流量过大而影响整个系统的稳定性,同时又不会影响其他链路对相同资源的正常调用。

Sentinel 流控效果详解

Sentinel 流控效果主要有快速失败、Warm Up 和排队等待三种,它们的区别如下:

  1. 快速失败(Fail Fast)

    • 概念

      • 当请求流量超过设定的阈值时,直接拒绝超出的请求。这种方式能够快速地对超出流量进行限制,以保护后端服务。

    • 示例

      • 假设对一个 API 接口设置的 QPS(每秒查询率)阈值为 100,当每秒请求数达到 101 时,第 101 个及之后的请求会立即被拒绝,并返回相应的限流错误信息,如 HTTP 状态码为 429(Too Many Requests)。

    • 应用场景

      • 适用于对系统资源消耗较大,且对请求的实时性要求不是特别高的接口。例如,一些批量数据处理接口,当流量过载时,直接拒绝新请求可以避免系统因过度负载而崩溃。同时,对于一些非关键业务的接口,快速失败可以简单有效地控制流量,确保核心业务的稳定运行。

  2. Warm Up(预热)

    • 概念

      • 预热模式是一种渐进式的流量控制方式。它会根据设定的预热时长和阈值,在系统启动或者流量突然增加时,缓慢地增加允许通过的流量,直到达到设定的最大阈值。这样可以避免系统在冷启动或者流量突发时,因为瞬间的高负载而出现性能问题。

    • 示例

      • 假设设置一个接口的 QPS 阈值为 100,预热时长为 5 分钟。系统启动时,开始允许通过的 QPS 可能只有 20,然后随着时间逐渐增加,在 5 分钟后达到 100。如果在预热期间流量就超过了当前允许的阈值,超出部分会被拒绝。

    • 应用场景

      • 常用于系统冷启动后需要逐步加载资源(如缓存预热、数据库连接池初始化等)的场景。同时,对于一些具有性能瓶颈,需要一定时间来适应高流量的服务,如数据库密集型的接口或者计算资源消耗大的算法接口,Warm Up 模式可以让系统有一个缓冲阶段,平稳地过渡到高流量状态。

  3. 排队等待(Rate Limiter)

    • 概念

      • 当请求流量超过阈值时,不是直接拒绝请求,而是让请求进行排队等待。Sentinel 会按照请求的到达顺序,将超出阈值部分的请求放入队列中,当系统有能力处理新请求时,再从队列中取出请求进行处理。这样可以保证请求在一定程度上的公平性,避免大量请求被直接拒绝。

    • 示例

      • 设一个接口的 QPS 阈值为 100,队列长度为 200。当每秒请求数达到 120 时,其中 20 个请求会被放入队列中排队等待。如果系统处理速度能够跟上,这些排队的请求会在后续得到处理。

    • 应用场景

      • 适用于对请求响应时间要求相对不那么严格,且希望尽可能处理所有请求的场景。比如,对于一些异步任务处理的接口,或者消息队列消费者接口,排队等待可以确保请求不会因为瞬间流量高峰而丢失,同时可以在一定程度上平滑流量,提高系统整体的资源利用率。

hystrix 熔断器

熔断和降级

熔断(目标服务不让访问,暂时中断)

降级(目标资源服务访问时,走降级方法,备份方法,返回特定信息给调用者,避免无限制等待)

熔断器 有三个状态: 打开 半开 关闭


网站公告

今日签到

点亮在社区的每一天
去签到