Spring Cloud Gateway动态路由及路由插件实现方案

news2025/1/11 4:48:48

前言

sim-framework之前使用Zuul作为网关,结合Eureka实现了动态路由及灰度路由,但是存在以下几个问题:

  • 性能问题:Zuul基于线程隔离,一个请求需要一个线程处理,而Gateway基于事件驱动,少量线程即可支持大量并发(仅仅是并发度和吞吐量,并不能提高业务处理效率),在性能不是很好的服务器上,太多的线程数反而会降低并发度。
  • 流行度:Zuul在后期的SpringCloud版本中将不会再继续集成,所以有必要更换为Gateway。
  • 版本问题:除了Zuul在SpringCloud版本中的集成问题,另一个是因为SpringBoot对Java版本的支持问题,SpringBoot3.x后仅支持JDK17及以后的版本,而早期的Zuul并不能使用上JDK17后的新特性;其次后续也可以以更小的成本升级到JDK21,使用它的虚拟线程,进一步提高性能。

因此对网关进行了重构,更新了基础依赖版本,引入了Gateway和Nacos,移除了Eureka。

动态路由实现

所谓动态路由,是指在不停机的情况下,动态的配置路由地址。之前使用Zuul时,通过扩展ZuulProperties.ZuulRoute实现了一个DatabaseRouteLocator[源码],通过从数据库中加载路由配置,然后发布RoutesRefreshedEvent 事件去触发路由更新,整体流程如下:
在这里插入图片描述
更换为Gateway后,整体流程如下:
在这里插入图片描述

其中最主要的是增加了使用redis监听消息来更新路由,相比于定时任务,提高了配置变更的实时性,并且在网关重启的时候,会从redis中拉取全量的路由配置,并加载到内存中,同时也保留了定时任务刷新配置,因为redis的发布订阅是不可靠的,可能会因为连接异常或者网关节点停机等原因,导致无法收到消息,无法触发路由更新,所以仍然需要定时任务定时刷新作为补偿。这里为什么不适用消息队列呢?因为作为一个轻量级的框架,就尽可能的少引入外部组件,所以这里暂且使用redis作为路由配置更新通知的中间件。

Gateway的动态路由实现方式很简单,Gateway中有一个RouteDefinitionRepository,它保存着路由的配置信息,并且它提供了savedelete方法,我们只需要调用这两个方法更新路由后,再发布RefreshRoutesEvent事件即可。

public Mono<Void> add(RouteDefinition route) {
        log.info("Add route: {}", route);
        return routeDefinitionRepository.save(Mono.just(route))
                .thenEmpty((v) -> publisher.publishEvent(new RefreshRoutesEvent(this)));
    }


    public Mono<Void> update(RouteDefinition route) {
        log.info("Update route: {}", route);
        return routeDefinitionRepository.save(Mono.just(route))
                .thenEmpty((v) -> publisher.publishEvent(new RefreshRoutesEvent(this)));
    }

    public Mono<Void> delete(String id) {
        log.info("Delete route, Route ID: {}", id);
        return this.routeDefinitionRepository.delete(Mono.just(id))
                .onErrorResume(NotFoundException.class, e -> Mono.empty())
                .thenEmpty((v) -> publisher.publishEvent(new RefreshRoutesEvent(this)));
    }

sim-framework提供了可视化的路由配置,再不重启网关的情况下可实现动态路由配置。
在这里插入图片描述

路由插件实现

Gateway提供了很多的PredicateFilter,但是总有一些场景无法满足我们,所以我们可以通过自定义插件的方式,将通用的、可复用的、无强业务相关性的流程,封装为一个网关插件,比如鉴权、限流、流量分发等等。

Gateway提供了AbstractRoutePredicateFactoryAbstractGatewayFilterFactory,分别对应路由的匹配器和过滤器,我们可以通过继承它来实现一个自定义的匹配器或者过滤器。

以下,实现一个自定义的过滤器,它的作用是将获取到的权限信息,再经过权限验证后,转发到下游服务时,将它移除掉,避免暴露过多的信息给下游服务:

@Component
public class RemovePermissionGatewayFilterFactory extends AbstractGatewayFilterFactory<RemovePermissionGatewayFilterFactory.Config> implements GatewayFilterSupport {

    public RemovePermissionGatewayFilterFactory(AuthProperties properties) {
        super(Config.class);
        this.properties = properties;
    }

    private final AuthProperties properties;

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            if (!shouldFilter(request, properties)) {
                return chain.filter(exchange);
            }
            return exchange.getPrincipal().map(principal -> (UserPrincipal) principal).doOnNext(user -> {
                user.setPermissions(null);
                exchange.mutate().principal(Mono.justOrEmpty(user));
            }).then(chain.filter(exchange));
        };
    }

    public static class Config {
        //ignore
    }
}

apply方法中,我可以拿到exchange,通过它可以获取到请求对象和响应对象,从而可以对请求以及响应做任何处理。

将自定义的过滤器注册为Bean即可在配置文件中使用它:

spring:
  cloud:
    gateway:
      routes:
        - id: sim-service-admin
          uri: lb://sim-service-admin
          predicates:
            - Path=/server/**
          filters:
            - StripPrefix=1
            - Authentication
            - Permission
            - RemovePermission

注意命名规范:SpringCloud建议,自定义过滤器类名以GatewayFilterFactory结尾,我们应当遵循该规范,避免日后出现问题。同理匹配器也一样,建议以RoutePredicateFactory结尾。

以上,是对于路由的静态扩展(提前编写好插件代码),考虑到作为一个网关,承载了整个系统的流量入口,并不能频繁的重启,所以需要提供动态扩展的能力,也就是动态加载插件的能力。对于动态扩展,我们目前使用动态加载jar包的形式,利用Spring的Bean动态注册,将自定义的插件注册为Bean后即可配置使用(该部分目前正在开发中)。

在这里插入图片描述
对于插件这部分,我们将其抽象为网关组件,并提供组件管理功能,可以注册自定义组件,也可以新增内置组件(对网关二次开发),并且支持组件的版本管理和回退。

整体大致流程如下:
在这里插入图片描述
这部分的实现细节,后续单独补充。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2053539.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Go项目布局

Go项目布局&#xff0c;自举语言&#xff0c;源码是靠Go自己实现的 所以Go源码可以参考作为项目布局 源码放在src目录下 cmd放main internal目录下放不希望外部访问的代码&#xff08;业务&#xff09; common目录下可以放直接 import外部访问的 etc放配置文件yaml

第二届海南大数据创新应用大赛 - 算法赛道冠军比赛攻略_海南新境界队

关联比赛: 第二届海南大数据创新应用大赛 - 智能算法赛 第二届海南大数据创新应用大赛 - 算法赛道冠军比赛攻略 首先很幸运能拿到这次初赛冠军&#xff0c;本着积极学习和提升自我的态度&#xff0c;团队成员通力合作是获胜关键&#xff0c;再次感谢。 赛题背景分析和理解 …

gpio的使用----->4412的裸机的使用(第三节)

这一节主要是 4412 的裸机的使用 0 4412 的硬件原理图 数据手册 然后是数据手册的解析&#xff1a; 每一组都有这几个 寄存器。 需要注意&#xff1a; 1、 4412 的中断是 与输入&#xff0c;输出在同一个级别的&#xff0c;与stm32不同。 2、 我是在uboot 上进行编程的&#x…

重头开始嵌入式第二十二天(Linux系统编程 进程)

进程 目录 进程 1.进程的概念 2.PCB&#xff08;process control block&#xff09; 3.进程和程序有什么区别&#xff1f; 4.进程的内存分布 5.进程的分类 守护进程 6.进程的作用 7.进程的状态 8.进程的调度 9.查询进程的相关指令 1.ps aux 2.top 3.kill和killa…

12 Text 组件

12 Text 组件 Tkinter 是 Python 的标准 GUI 库&#xff0c;而 Text 组件是其中用于显示和编辑多行文本的控件。以下是对 Text 组件的详细说明和一个使用案例。 Text 组件属性 基本属性 width: 文本框的宽度&#xff0c;通常以字符数为单位。height: 文本框的高度&#xff…

亚世光电:消费电子年度表演

机圈风云再起&#xff0c;消费电子乘风而起&#xff1f; 今天我们来聊——亚世光电 最近&#xff0c;华为mate60突然降价&#xff0c;被大家怀疑是为新品上市做准备&#xff0c;算算时间&#xff0c;下半年的消费电子大战也即将拉开帷幕&#xff0c;而亚世光电所在的光电显示领…

sklearn-线性回归

文章目录 一、sklearn-线性回归介绍二、线性回归1.一元线性回归2.多元线性回归模型3.最小二乘法 三、一元线性回归应用1.导入库2.绘制散点图3.建立回归模型并进行训练4.模型评估与数据查看5.模型测试 四、多元线性回归应用1.导入库2.计算相关性3.数据预处理4.训练评估模型5.模型…

iOS 18.1 Beta 2评测:新变化与体验升级

苹果公司近日向开发者推送了iOS 18.1 Beta 2更新&#xff0c;这一版本基于beta1版本进行多个方面优化和改进&#xff0c;为用户带来了更加流畅和个性化的使用体验。作为一位热衷于体验新系统的用户&#xff0c;小编也是第一时间升级了Beta 2版本&#xff0c;并对其进行了全面的…

Java二十三种设计模式-状态模式(20/23)

本文深入探讨了状态模式&#xff0c;一种允许对象根据其内部状态变化而改变行为的软件设计模式。文章从定义、组成部分、实现方式、使用场景、优缺点分析、与其他模式的比较&#xff0c;到最佳实践和建议&#xff0c;全面介绍了状态模式的各个方面。通过Java语言的实现示例和实…

2024前端面试题-篇章一(个人向)

1.vue2生命周期&#xff08;省略&#xff09; 2.vue3生命周期&#xff08;省略&#xff09; 3.vue2页面生命周期与组件生命周期执行顺序&#xff1a; 一般是 页面先创建&#xff0c;然后准备再准备挂载&#xff0c;挂载的时候发现有组件再执行组件的生命周期&#xff0c;组件…

数字影像技术是如何改变我们看待世界的方式呢?

在当今的科技时代&#xff0c;数字影像技术正以惊人的速度改变着我们的生活和视觉体验。那么&#xff0c;什么是数字影像技术呢&#xff1f; 数字影像技术是指通过数字化手段对图像和视频进行获取、处理、存储、传输和展示的一系列技术。 它利用各种数字设备&#xff0c;如数…

msf+proxychains组合搭建socks5隧道 | 内网穿透

实验环境 网络拓扑&#xff1a; kali&#xff1a; VMnet1&#xff08;公网&#xff09;192.168.52.134 win10&#xff1a; VMnet1&#xff08;公网&#xff09;192.168.52.135VMnet2&#xff08;内网&#xff09;192.168.72.133 win2008&#xff1a; VMnet2&#xff08…

【数据结构初阶】二叉树--基本概念

hello&#xff01; 目录 一、树 1.1 树的概念和结构 1.2 树的相关术语 1.3 树的表示 1.4 树形结构实际应用场景 二、二叉树 2.1 概念和结构 2.2 特殊的二叉树 2.2.1 满二叉树 2.2.2 完全二叉树 2.3 二叉树的存储结构 2.3.1 顺序结构 2.3.2 链式结构 …

转行到大模型,完整版攻略从大模型零基础到大模型精通,我是这样过来的

在当今这个日新月异的时代&#xff0c;技术的更新迭代速度远超我们的想象。对于那些渴望在职业生涯中寻求新挑战的人来说&#xff0c;转向人工智能领域&#xff0c;尤其是投身于大规模语言模型的研究与开发&#xff0c;无疑是一个充满机遇的选择。本文将为您揭示如何从零开始&a…

阿里十万卡训练集群 网络拓扑架构和优势 Alibaba HPN: A Data Center Network for Large Language Model Training

本博客的视频教程在这&#xff1a; 2.2阿里十万卡集群 网络拓扑架构和优势 Alibaba HPN: A Data Center Network for Large Language Model_哔哩哔哩_bilibili 一、大模型训练的核心问题 1.1 流量模式的问题 大语言模型训练的流量模式问题可参考这个&#xff1a; ECMP等价…

Linux 服务器下非root用户安装CUDA完整流程(多次踩雷经验总结)

参考博客&#xff1a; linux下安装cuda和cudnn&#xff08;非root权限&#xff09;_cuda下载安装 远程服务器 linux-CSDN博客 Linux下非root用户安装CUDA_linux下cuda-toolkit-archive-CSDN博客 非root用户安装cuda10.1&#xff0c;以及CUDA不同版本间切换_非root用户.run文…

已解决centos7 yum报错:cannot find a valid baseurl for repo:base/7/x86_64的解决方案

出现cannot find a valid baseurl for repo:base/7/x86_64错误通常是由于YUM仓库源无法找到或无法访问&#xff0c;导致YUM无法正常工作。这种情况常见于CentOS 7系统。解决这个问题需要检查几个方面&#xff0c;如网络连接、DNS设置和YUM仓库源配置。 &#x1f9d1; 博主简介&…

aspose-words中插入附件及遇到的问题

aspose-words版本&#xff1a;21.1 java&#xff1a;1.8 目标&#xff1a; 前端使用tinymce编辑一段内容&#xff0c;后端使用aspose-words将html转为word&#xff0c;并将html中的附件转换为word中的附件。 形如&#xff1a; 实现方案&#xff1a; 使用正则表达式找出需要替…

setData的 Qt::CheckStateRole是model中checkbox的状态(选中否)

checkbox的状态 bool MissionModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role Qt::CheckStateRole && col 3 ) { } }

【嵌入式裸机开发】基于stm32的照相机(OV7670摄像头、STM32、TFTLCD)

基于STM32的照相机 准备工作最终效果一、下位机1、主函数2、OV7670初始化 二、上位机1、控制拍照2、接收图片数据 准备工作 一、硬件及片上资源: 1,串口1(波特率:921600,PA9/PA10通过usb转ttl连接电脑&#xff0c;或者其他方法)上传图片数据至上位机 2,串口2(波特率:115200,PA…