3 | SpringCloud:Gateway从入门到出坑

说句实话,我觉得Spring Cloud Gateway看起来很牛逼。首先是因为zuul的难产,颇有一种谁行谁上的感觉;再一个是WebFlux的加持,瞬间逼格就上去了。但是感觉苦逼的又回到了原点,因为WebFlux看简介是说基于Netty来实现的,绕来绕去又回到了Netty。言归正传,如果只是简单的

说句实话,我觉得Spring Cloud Gateway看起来很牛逼。首先是因为zuul的难产,颇有一种谁行谁上的感觉;再一个是WebFlux的加持,瞬间逼格就上去了。但是感觉苦逼的又回到了原点,因为WebFlux看简介是说基于Netty来实现的,绕来绕去又回到了Netty。

言归正传,如果只是简单的使用,对路由在yaml文件中进行配置是最简单的,以及进行断言、过滤。整体使用,感觉不难。但是,我相信,源码应该不好看?。

配置步骤

①新建名叫gateway的module,导入spring-cloud-starter-gateway依赖到pom,并加入对nacos配置、服务发现相关的依赖,如下:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
    <version>2.2.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <version>2.2.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2.2.0.RELEASE</version>
</dependency>

spring-cloud-starter-gateway的依赖树如下:

这个netty相关的依赖看着有点眼熟。

②编写启动类,开启服务注册与发现

@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

③在resouces下编写bootstrap.yaml配置文件(本来配置原本打算是要放到nacos里面,这里图个方便,直接放bootstrap里面了,所以这里看起来可能有点怪),最简单的是在这里定义路由、断言。

server:
  port: 7777
spring:
  application:
    name: gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: hello
          uri: lb://module01
          predicates:
            - Path=/hello/**
    nacos:
      discovery:
        server-addr: localhost:80
      config:
        server-addr: localhost:80
        file-extension: yaml

④此时启动gateway模块,通过7777端口即可访问到相应的接口,如下:

⑤还可以对gateway转发的每一条请求,做一个filter操作,如下:

@Component
public class CustomFilter implements Ordered, GlobalFilter {
    Logger logger = Logger.getLogger(this.getClass().getName());
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        logger.info("收到请求,来自:" + exchange.getRequest().getRemoteAddress().getHostName());
        return chain.filter(exchange);
    }

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

此时的控制台会有日志打出,说明拦截生效了:

此处filter的可操作空间就比较大了,可以放一些针对全局请求的处理。

疑问cloud.gateway.discovery.locator.enabled值默认为false,但是不加这个配置,通过服务名称+lb的配置也能生效,因此对它的作用应该不是开启微服务名转发的功能,那它的功能究竟是什么?

答案是这个

gateway在项目中的使用(以测试环境为例)

①所有的请求走34的30450端口。这个端口是nginx,做静态页面与后端接口的转发。

②由于34是k8s的一个node,因此通过信息查询,可以得出占用30450端口的pod

③进入main-src-web-test查看nginx的配置信息

④找到31898端口对应的服务

⑤此服务即项目中的gateway服务,其gateway相关的配置信息如下:

server:
  port: 9898
  
context:
  excludePaths:
  - /emc-admin
 
spring:
  cloud:
    sentinel:
      transport:
        port: 2${server.port}
        dashboard: 192.168.100.34:30858
      datasource:
        default:
          nacos:
            serverAddr: ${nacos.server}
            dataId: sentinel-${spring.application.name}.json
            groupId: DEFAULT_GROUP
            dataType: json
            ruleType: flow
    gateway:
      routes:
      - id: emc-admin
        uri: lb://emc-admin
        predicates:
        - Path=/emc-admin/**
        filters:
        - StripPrefix=1

项目中的gateway还集成了sentinel,也就是自定义了一个Filter,并在其中,对每一条请求,都交给sentinel进行处理,由此实现熔断、降级、限流。实现如下:

private Mono<Void> chainFilter(ServerWebExchange exchange, GatewayFilterChain chain, String requestURI) {
    try {
        Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
        ContextUtil.enter(route.getUri().toString());
        AsyncEntry entry = SphU.asyncEntry(requestURI, EntryType.IN);
        return chain.filter(exchange).doFinally(type -> {
            ContextUtil.runOnContext(entry.getAsyncContext(), () -> {
                entry.exit();
            });
        });
    } catch (BlockException ex) {
        log.warn("{} request blocked", requestURI);
        return responseFailure(exchange.getResponse(), HttpStatus.SERVICE_UNAVAILABLE);
    }
}

Read more

Volcano 与 Kubernetes GPU 调度学习笔记

本笔记系统整理 Volcano 调度器、Kubernetes 调度框架、GPU Device Plugin、HAMi 等云原生 AI 调度领域的核心知识,适合用于学习、复习和工程实践参考。 目录 * 第一部分:Volcano 入门 * 1. Volcano 是什么 * 2. 安装与快速使用 * 3. 核心特性一览 * 第二部分:Volcano 整体架构 * 4. Volcano 解决的核心问题 * 5. 整体架构与数据流 * 6. 三层抽象模型 * 第三部分:Volcano 核心实现原理 * 7. Session 机制 * 8. Gang Scheduling 实现 * 9. Queue 与 DRF 公平调度

容器镜像(4):镜像的常用工具箱

容器镜像(4):镜像的常用工具箱

前几篇在讲多架构镜像时已经用过 skopeo 和 crane 做镜像复制,这篇系统整理这两个工具的完整能力,同时介绍几个日常操作镜像时同样好用的工具。 一、skopeo:不依赖 Daemon 的镜像瑞士军刀 skopeo 的核心价值是绕过 Docker daemon,直接与 Registry API 交互。上一篇用它做镜像复制和离线传输,但它的能力远不止于此。 1.1 安装 # Ubuntu / Debian sudo apt install -y skopeo skopeo --version # skopeo version 1.15.1 1.2 inspect:免拉取检查镜像元数据 docker inspect 需要先把镜像拉到本地,skopeo inspect 直接向 Registry

容器镜像(3):多架构镜像构建

容器镜像(3):多架构镜像构建

一、什么是多架构镜像 1.1 OCI Image Index 上一篇介绍了单平台镜像的结构:一个 Manifest 指向 Config 和若干 Layer blob。多架构镜像在此之上多了一层——OCI Image Index(也叫 Manifest List),是一个轻量的索引文件,把多个单平台 Manifest 组织在一起: $ docker manifest inspect golang:1.22-alpine { "schemaVersion": 2, "mediaType": "application/vnd.oci.image.index.v1+json", "manifests&

容器镜像(2):containerd 视角下的镜像

容器镜像(2):containerd 视角下的镜像

一、为什么需要了解 containerd 如果你只用 docker run 跑容器,从来不关心底层,那可以不了解 containerd。但如果你在用 Kubernetes,或者想真正理解"容器运行时"是什么,containerd 是绕不开的。 事实上,当你执行 docker run 的时候,containerd 早就在后台悄悄工作了——Docker 从 1.11 版本开始,就把核心运行时剥离出来交给 containerd 负责。 1.1 Docker 的架构演变 早期的 Docker(1.10 及之前)是一个"大一统"的单体程序:一个 dockerd