热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

关于网关:得物技术网关路由匹配性能优化

为了进一步增强网络安全防备工作,近期对网关服务做了相干的平安降级,其中变动最大的一点是,网关不再提供URI含糊匹配的模式,形如apiv1apporder**这样的配置曾经不在反对,置信很多小伙伴曾经感触到了日常开发上线的不便,然而须要了解的是,随着公司的体量的迅速倒退,各方面越来越规范化,平安方面增强管控显

为了进一步增强网络安全防备工作,近期对网关服务做了相干的平安降级,其中变动最大的一点是,网关不再提供URI含糊匹配的模式,形如 /api/v1/app/order/** 这样的配置曾经不在反对,置信很多小伙伴曾经感触到了日常开发上线的不便,然而须要了解的是,随着公司的体量的迅速倒退,各方面越来越规范化,平安方面增强管控显然还是十分必要的。

首先看下得物流量传递的根本门路:

APP网关流量门路:四层高防 –> 阿里云SLB –> Gateway –> 业务服务/业务网关(提供协定转化 &接口聚合)

通常来说与业务方打交道的最多的是gateway 服务,很多萌新可能不是很了解网关具体在干啥,这里做个简要阐明,网关最大的作用是提供流量散发,同时具备流量管控,防爬,黑白名单,根本鉴权,接口超时,灰度等常见性能;小伙伴们日常开发中最长用到的就是流量转发,比方新起一个服务须要对外网裸露接口,此时就须要在网关的路由治理上进行配置。

所以Spring gateway 的路由匹配就成了一个十分外围的要害性能,这里咱们翻阅一下 Spring gateway 的源码。

因为Spring gateway 应用webflux 技术,整体的代码格调较为诡异。

这里简略介绍下webflux的基本概念:

flux 示意 1~N 数据元素

mono ,示意 0~1 个数据元素,

针对数据流的所有操作,在没有订阅之前都不会被触发,只有调用了 subscribe办法后才会理论触发。


图一*

这里咱们看下 DispatcherHandler 的handle 办法,该办法会进行webHandler 的适配,对于网关来说这里次要匹配的是RoutePredicateHandlerMapping 这一对象,咱们能够从 hadlerMappings 对象中看到:

RoutePredicateHandlerMapping 中的webHandle为 FilteringWebHandler 该handle 中蕴含了gateway 自带的以及网关自定义的共28个 GolobalFilter

讲到这里很多小伙伴可能会好奇,这个路由匹配到底是在哪儿做的呢,别急,咱们缓缓开趴!

依照图一所示,选中mapping后会获取Handler,而获取handler 后优会调用 invokeHandler 办法,那么我么无妨先到 getHandler 办法中看看,点开 RoutePredicateHandlerMapping 源码,咱们郁闷的发现并没有 getHandler 办法,而只有getHandlerInternal 办法,认真看下 RoutePredicateHandlerMapping 的继承关系发现该类继承了 AbstractHandlerMapping, 而AbstractHandlerMapping 中 getHandler 办法早已存在,实现了HandlerMapping 接口同时也做了局部实现 ;废话不多说,源码底下无内鬼!!

原来getHandlerInternal 是在 getHandler 办法中被调用的。这就解释得通了,

仔细观察了 getHandler 中的逻辑,并没有路由匹配的逻辑,此时嫌疑最大的当属 RoutePredicateHandlerMapping 的 getHandlerInternal 了!

不出所料,lookupRoute 没跑了!!

lookupRoute的代码很简略,外围逻辑为简略的匹配,同时增加错误处理,在匹配胜利的状况下会把路由信息增加到 ServerWebExchange 中的attributes 中,代码如下:

察看filterWhen,咱们会发现这是一个for循环匹配,也就是说,效率为O n, 在路由信息比拟多的状况下十分蹩脚,当然这不能怪Spring,毕竟gateway 设计之初,是反对各种正则,含糊匹配的,这种要求下,做到O 1的效率并不事实 ,然而联合得物以后的应用场景,咱们能够做进一步的优化:

因为新的路由增加为准确模式,也就是每个接口对应一个路由,这种前提下,咱们很显然的想到了HASH 算法,因为对于pathVariable模式的path也不再反对(小伙伴们能够思考下,这种接口有什么毛病) ,在收到申请的时候间接提取path局部,通过hash的形式获取到对应的路由信息,革新后的路由查找逻辑如下所示:

findRoute()办法中的逻辑非常简单的:

为了保障并发平安,这里的pathRouteMap 为 ConcurrentHashMap ,其实批改为HashMap 也是能够的,因为路由匹配时,对map是只读操作,更新时候是整体map 援用替换:这里附上刷新路由缓存信息的代码

因为更新路由信息的操作属于高危且外围的操作,对于一个批次的更新最好可能原子性实现,这里咱们引入了Copy on write 的思路,批改的时候,先批改bakMap ,等到bakMap中的全副路由信息更新实现后,咱们将理论应用的map 援用指向bakMap, 同时将bakMap设置为空。此外更新路由的操作一般来说都是事件触发异步实现,因而对于性能要求并不高,这里加上锁进一步保障路由更新完整性,避免在多个线程调用时,map与bakMap之间呈现不匹配的状况!

须要指出的是 gateway 的路由查找逻辑依赖于 CachingRouteLocator, 该类监听路由更新事件,理论的路由刷新通过公布事件的形式实现。察看源码,咱们发现解决路由刷新事件时调用了fetch 办法;

同时在初始化阶段以及缓存命中生效阶段时也调用了 fetch办法(这里缓存是gateway自带的缓存机制,而非咱们增加的Map缓存)

因而咱们能够在fetch 办法中退出 refreshPathRouteMap() 办法;

在lookupRoute 办法中的 this.routeLocator.getRoutes() 理论调用的是CachingRouteLocator#getRoutes()办法。此办法间接返回被缓存的的信息,这里的缓存指的是 gateway 自带的

routes = CacheFlux.lookup(cache, CACHE_KEY, Route.class).onCacheMissResume(this::fetch);

逻辑简略翻译一下,就是如果缓存命中失败会调用fetch办法从新加载路由信息。

至此,路由匹配的逻辑大抵剖析实现!其实对于之前的 /api/v1/app/order/* 这种模式的路由也能够通过hash形式进行减速,只须要将 * 去掉,作为map的key,在解决申请的时候,尝试获取申请的前缀进行匹配即可!

最终咱们实战察看一下改良的实际效果:

能够发现,理论的CPU占用从原来的均匀24% –> 12% ,比原先降落了一半左右!

文/簌语

关注得物技术,携手走向技术的云端


推荐阅读
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文介绍了在使用Python中的aiohttp模块模拟服务器时出现的连接失败问题,并提供了相应的解决方法。文章中详细说明了出错的代码以及相关的软件版本和环境信息,同时也提到了相关的警告信息和函数的替代方案。通过阅读本文,读者可以了解到如何解决Python连接服务器失败的问题,并对aiohttp模块有更深入的了解。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 本文介绍了Windows操作系统的版本及其特点,包括Windows 7系统的6个版本:Starter、Home Basic、Home Premium、Professional、Enterprise、Ultimate。Windows操作系统是微软公司研发的一套操作系统,具有人机操作性优异、支持的应用软件较多、对硬件支持良好等优点。Windows 7 Starter是功能最少的版本,缺乏Aero特效功能,没有64位支持,最初设计不能同时运行三个以上应用程序。 ... [详细]
author-avatar
手机用户2602926791
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有