背景描述
近期在公司建设API治理平台过程中,以SpringCloud Gateway为基础,构建了一个API的Mock服务,以API的URI作为路由,根据服务端存储的API DSL,验证请求信息,生成并返回Mock报文。
SpringCloud Gateway具备很好的 动态路由 支持功能,可以在API DSL创建的同时,创建一条Mock路由,这样API DSL创建后,开发人员就可以使用Mock服务进行开发调试工作。
但作为一个企业级应用,所管辖的API的数量众多,SpringCloud Gateway在路由表急剧膨胀后的性能如何?目前没有查阅到明确说明的资料。翻阅其源码发现,断言命中其实是进行的遍历,这样路由表膨胀时,路由性能存疑,需要进行验证,根据验证结果制定近一步优化方案。
验证方法
保持其他所有变量不变,仅调整路由表大小,使用JMH工具进行基准测试,得出路由表膨胀与路由性能的关系。
需要编写三个服务:
-
路由网关
-
挡板服务(路由转发的upstream)
-
JMH测试端
配置信息
CPU Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz
基准速度: 3.60 GHz
插槽: 1
内核: 8
逻辑处理器: 8
虚拟化: 已启用
L1 缓存: 512 KB
L2 缓存: 2.0 MB
L3 缓存: 12.0 MB
测试期间CPU利用率约 50%
SpringCloud Gateway 3.0.3, Java 1.8.0_251
测试过程需控制变量,所以CPU负债不能过高,下图是我执行测试时的CPU负载情况
路由定义示例
{
"_id": {
"$oid": "60c4f055588bca06132e44cb"
},
"predicates": [{
"name": "Path",
"args": {
"_genkey_0": "/1999"
}
}],
"filters": [{
"name": "AddRequestHeader",
"args": {
"_genkey_0": "x-benchmark-routeId",
"_genkey_1": "60c4f055588bca06132e44cb"
}
}, {
"name": "PrefixPath",
"args": {
"_genkey_0": "/ok"
}
}],
"uri": "http://localhost:9999",
"metadata": {},
"order": 1,
"_class": "com.example.scgw.benchmark.route.MongoRouteDefinition"
}
测试结论
见上图,测试结果无论系统的吞吐量,还是响应时间指标,都随着路由表的膨胀变差,当路由表膨胀到10W级别时,服务基本不可用了!
这一结论印证了我的猜想。
优化思路一
保持路由网关的通用性(SpringCloud Gateway设计了很多路由断言手段,包括基于path、method、header、parameter等等),采用两级(多级)路由机制见下图:
优化思路二
Mock服务是一个专有场景,仅根据Path和指定Header进行转发,可以修改SpringCloud Gateway源码,提供一个根据Path+指定Header查找路由的HashMap,这样进行路由断言时就不需进行路由表遍历。
个人倾向于按照思路二进行优化,优化过程见SpringCloud Gateway 路由转发性能优化。
测试相关代码
路由网关
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
MongoRouteDefinition.java
@Document