当前位置: 首页 > article >正文

【springcloud】快速搭建一套分布式服务springcloudalibaba(二)

第二篇 基于nacos搭建分布式项目 网关
项目所需 maven + nacos + java8 + idea + git + mysql(用户信息) + redis(用于限流)
本文通过网关实现用户登录拦截,网关系统/用户系统/商品系统 用户未带token请求除登录以外的任何操作都被拦截返回登录页面。
请先准备好环境,可以直接clone下来项目去部署。

基于nacos搭建分布式项目 网关

  • 分布式系统为什么需要网关
  • 项目结构
  • 创建项目
    • 路由参数解析
      • 其实主要用到的就那几个就可以实现。(示例)
      • spring.cloud.gateway.routes.filters
      • 过滤器示例(熔断器与限流)
    • 用户认证与日志监控
      • 示例代码
    • 熔断与限流
      • 熔断
      • 限流
        • 自定义限流key
        • 测试
    • 灰度发布与流量控制
      • 基于路径的流量分发
      • 基于 Header 的流量分发
      • 基于权重的流量分发
  • 结尾

分布式系统为什么需要网关

在分布式系统中,网关(Gateway) 是一个非常重要的组件,它充当了系统的统一入口,负责处理外部请求并将其路由到内部服务。

  1. 统一入口(客户端只需与网关交互,而不需要直接访问内部服务)
  2. 路由与负载均衡(请求 /user/** 路由到用户服务,请求 /order/** 路由到订单服务)
  3. 安全与认证(网关可以集中处理身份验证(如 JWT、OAuth2)和授权(如权限校验)
  4. 限流与熔断(支持熔断和限流机制,当某个服务不可用或者超出瞬时流量限制时,快速失败并返回降级响应。)
  5. 日志与监控 (网关可以集中记录请求日志,便于问题排查和性能分析)
  6. 跨域支持(网关可以统一处理跨域请求(CORS),避免每个服务单独配置)
  7. 灰度发布与流量控制(网关可以根据请求的 Header、参数或其他条件,将流量分发到不同版本的服务。)
    接下里我们一个一个实现看看

图内各个服务节点可以集群部署。
在这里插入图片描述

项目结构

快速部署分布式项目


git clone git@gitee.com:goodluckv/ali-cloud-common.git
git clone git@gitee.com:goodluckv/ali-cloud-gateway.git
git clone git@gitee.com:goodluckv/ali-cloud-user.git
git clone git@gitee.com:goodluckv/ali-cloud-goods.git

在这里插入图片描述

创建项目

快速创建,可参考第一篇快速搭建,加入spring-cloud-starter-gateway。gateway网关项目不需要spring-boot-starter-web包。Spring MVC 是基于阻塞式 I/O 的传统 Web 框架,通常用于构建同步的 Web 应用程序。
Spring Cloud Gateway 是基于 Spring WebFlux 的响应式编程框架,使用非阻塞式 I/O,适用于构建异步、高性能的网关服务。

在这里插入图片描述

nacos 中的config

命名gateway-service-dev.yaml


user:
  name: 自动刷新
  age: 30

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/user/**
          filters:
            - StripPrefix=1
            # 熔断
            - name: CircuitBreaker
              args:
                name: systemBreaker
                fallbackUri: forward:/system/fallback/tip
            # 限流
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 1 # 每秒允许的请求数
                redis-rate-limiter.burstCapacity: 5 # 每秒最大请求数
                key-resolver: "#{@pathKeyResolver}"  # 限流的键解析器
        - id: login-service
          uri: lb://user-service
          predicates:
            - Path=/account/**

路由参数解析

路由可以直接配置在nacos的动态配置中

*[HTML]:

配置分类配置项用途说明示例值/配置
路由配置spring.cloud.gateway.routes.id路由唯一标识符,用于区分不同路由规则user-service
spring.cloud.gateway.routes.uri目标服务URI(支持httplb负载均衡模式)lb://user-servicehttp://localhost:8080
spring.cloud.gateway.routes.predicates断言条件集合,用于匹配HTTP请求特征(如路径、请求头等)- Path=/api/**
- Method=GET
spring.cloud.gateway.routes.filters过滤器集合,用于修改请求/响应(如添加头、路径重写等)- AddRequestHeader=X-Request-Id,123
- StripPrefix=2 (去除前缀)
全局配置spring.cloud.gateway.discovery.locator.enabled是否与服务发现组件集成(如Eureka),启用动态路由true
spring.cloud.gateway.default-filters全局过滤器列表,作用于所有路由- DedupeResponseHeader=Access-Control-Allow-Origin
跨域配置spring.cloud.gateway.globalcors.cors-configurations配置跨域资源共享(CORS)规则'/**':
allowedOrigins: "*"
allowedMethods: ["GET", "POST"]
HTTP客户端配置spring.cloud.gateway.httpclient.pool.max-connections设置HTTP连接池最大连接数(优化高并发场景)500
spring.cloud.gateway.httpclient.connect-timeout连接超时时间(毫秒)30000
限流配置spring.cloud.gateway.ratelimiter.enabled是否启用请求速率限制(需配合Redis等存储)true
spring.cloud.gateway.ratelimiter.redis-rate-limiter.replenishRate每秒允许的请求数10
指标监控spring.cloud.gateway.metrics.enabled启用Prometheus等监控指标采集true
超时配置spring.cloud.gateway.httpclient.response-timeout响应超时时间(毫秒)60000

其实主要用到的就那几个就可以实现。(示例)

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/user/**
          filters:
            - StripPrefix=1

spring.cloud.gateway.routes.filters

关于过滤器 又有很多 参数 ,比如熔断与限流都可以在这里面配置

*[HTML]:

过滤器名称用途说明示例配置来源
AddRequestHeader添加请求头,常用于传递认证信息或自定义标识- AddRequestHeader=X-User-Id, 1001
AddRequestParameter添加请求参数,常用于补充请求参数- AddRequestParameter=key1, value1
PrefixPath在请求路径前添加前缀,用于统一接口前缀- PrefixPath=/api/v1
StripPrefix去除路径前缀,将请求转发到后端时忽略指定层级的路径- StripPrefix=2(移除路径前两个层级)
RewritePath重写请求路径,支持正则表达式匹配和替换- RewritePath=/old/(?<segment>.*), /new/$\{segment}
Retry配置请求重试策略(如超时重试次数、状态码触发条件)- Retry=3(默认重试3次)
- Retry=retries=3,statuses=500,methods=GET
RequestRateLimiter基于令牌桶算法限流,需配合 Redis 或其他存储实现- RequestRateLimiter=10, 20, #{@userKeyResolver}(每秒10令牌,容量20)
SetStatus强制修改响应状态码,常用于统一异常处理- SetStatus=401
RemoveRequestHeader移除指定请求头,用于敏感信息过滤- RemoveRequestHeader=Authorization
RemoveResponseHeader移除指定响应头,用于隐藏后端服务细节- RemoveResponseHeader=Server
SaveSession强制保存 WebSession,用于需要会话管理的场景- SaveSession
RedirectTo重定向请求,支持 HTTP 状态码和 URL 配置- RedirectTo=302, http://example.com

过滤器示例(熔断器与限流)

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
          # 请求头为/user开头的uri都路由到userservice服务
            - Path=/user/**
          filters:
          # StripPrefix 转发的路径第一个/user会被去掉 比如 请求/user/info 实际请求 http://user-service/info 这么配置是为了更好区分各个服务, 
            - StripPrefix=1
            # 熔断
            - name: CircuitBreaker
              args:
                name: systemBreaker
                fallbackUri: forward:/system/fallback/tip
            # 限流
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 1 # 每秒允许的请求数
                redis-rate-limiter.burstCapacity: 5 # 每秒最大请求数
                key-resolver: "#{@pathKeyResolver}"  # 限流的键解析器

用户认证与日志监控

示例代码中 加入了jwt,我们只需要实现GlobalFilter, Ordered 这俩接口 ,然后重写filter 方法即可实现过滤。可以配置多个过滤器。

示例代码

order 数字越小执行优先级越高(可以写负数)。


@Configuration
@Slf4j
public class GatewayJwtTokenFilter implements GlobalFilter, Ordered {


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String rawPath = request.getURI().getRawPath();
        HttpHeaders headers = request.getHeaders();
        log.info("rawPath: {}", rawPath);
        if (!rawPath.startsWith("/account")) {
            // 检查用户是否登录,这里假设通过检查请求头中的某个字段来判断
            String token = exchange.getRequest().getHeaders().getFirst("Authorization");
            Res<UserAccount> res = JwtUtil.getUser(token, UserAccountSecretInit.ACCOUNT_SECRETKEY);
            if (!res.getCode().equals(Res.SUCCESS_CODE)) {
                // 未登录,重定向到 /login 页面
                exchange.getResponse().setStatusCode(HttpStatus.FOUND);
                exchange.getResponse().getHeaders().set("Location", "/account/login.html");
                return exchange.getResponse().setComplete();
            }
        }

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }

}

熔断与限流

熔断

当某个服务或组件出现故障时,快速失败并停止对其的调用,避免故障扩散到整个系统。有好几种组件,本文用的reactor-resilience4j,阿里的spring-cloud-starter-alibaba-sentinel也不错。
默认情况下服务不可用的话页面返回503
需要使用到spring-cloud-starter-circuitbreaker-reactor-resilience4j

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
        </dependency>

在这里插入图片描述
模拟用户登录服务崩溃的情况(user-service没有启动)
访问 http://127.0.0.1:8010/account/login.html 网关系统自动重定向到熔断页面,如果不配置熔断页面会提示503
在这里插入图片描述

限流

分布式系统限流 是一种用于控制系统中请求流量的技术,目的是在系统资源有限的情况下,确保系统能够稳定运行,避免因流量过大而导致系统崩溃或性能下降。
可以限制ip,url,不同用户,每秒请求次数,最大请求次数。
需要使用到redis用于存储key

    <!-- Redis Reactive (用于限流) -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    </dependency>
自定义限流key

    @Bean
    public KeyResolver pathKeyResolver() {
        KeyResolver keyResolver = pathKeyGet();
        log.info(keyResolver.toString());
        log.info("创建限流key存入redis: {} ", JSON.toJSONString(keyResolver));
        return keyResolver;
    }

    public KeyResolver pathKeyGet() {
        return exchange -> {
            // 获取请求路径
            String path = exchange.getRequest().getPath().toString();
            String hostAddress = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
            String key = hostAddress + "_" + path;
            log.info("compositeKey 限流key:{}", key);
            return Mono.just(key);
        };
    }
测试

我设置的同一ip每秒请求同一url不能超过3次,在我本地测试第四次会出现该页面。计算方式根据控制台结果是按第一次请求时间开始算的,如果第一次请求过了一秒,按顺序从第二次请求时间开始算。

在这里插入图片描述

灰度发布与流量控制

基于路径的流量分发

可以直接将user服务前置一个版本的uri,比如/v1/user/xxx /v2/user/xxx

spring:
  cloud:
    gateway:
      routes:
        - id: v1_route
          uri: lb://user-service-v1
          predicates:
            - Path=/v1/user/**
          filters:
            - StripPrefix=2
        - id: v2_route
          uri: lb://user-service-v2
          predicates:
            - Path=/v2/user/**
         filters:
            - StripPrefix=2

基于 Header 的流量分发

通过请求头中(如 version)将流量分发到不同版本的服务

spring:
  cloud:
    gateway:
      routes:
        - id: v1_route
          uri: lb://user-service-v1
          predicates:
            - Header=version, v1  # 匹配请求头 version=v1
        - id: v2_route
          uri: lb://user-service-v2
          predicates:
            - Header=version, v2  # 匹配请求头 version=v2

基于权重的流量分发

Weight 过滤器用于按权重分发流量。
group1 是分组的名称,相同分组的权重总和应为 100。

spring:
  cloud:
    gateway:
      routes:
        - id: weight_route
          uri: lb://user-service-v1
          predicates:
            - Path=/service/**
          filters:
            - Weight=group1, 80  # 80% 的流量
        - id: weight_route_v2
          uri: lb://user-service-v2
          predicates:
            - Path=/service/**
          filters:
            - Weight=group1, 20  # 20% 的流量

结尾

第一篇快速部署一套分布式服务

希望本文可以帮到你。


http://www.kler.cn/a/579169.html

相关文章:

  • 前端常用布局
  • Deeplabv3+改进4:在主干网络中添加GAMAattention|助力涨点!
  • Python实现鼠标点击获取窗口进程信息
  • Android FragmentContainerView如何使用
  • Oracle 字符类型对比
  • Manus AI Agent 技术解读:架构、机制与竞品对比
  • React 中 Hooks 函数及作用
  • 玛卡巴卡的k8s知识点问答(一)
  • 《打破常规:量子比特如何同时“是0又是1”》
  • 基于Spring Boot的多级缓存架构实现
  • 【vscode编辑器配置】
  • Linux中的TCP编程接口基本使用
  • PE文件结构详解(DOS头/NT头/节表/导入表)使用010 Editor手动解析notepad++.exe的PE结构
  • 启智畅想集装箱号码识别技术,具备的特点与优势
  • python机试1:读取和输出数据
  • 开发ai模型最佳的系统是Ubuntu还是linux?
  • 深度学习/强化学习调参技巧
  • 如何在rust中解析 windows 的 lnk文件(快捷方式)
  • Android Coil3缩略图、默认占位图placeholder、error加载错误显示,Kotlin(5)
  • Java直通车系列14【Spring MVC】(深入学习 Controller 编写)