1.Spring Cloud gateway与zuul1实现方式对比分析
zuul 1本质上是一个web servlet,基于servlet2.5,代码简单易看懂,但是使用阻塞api,不支持任何长连接,如websocket。
Spring cloud gateway使用netty进行网络通信建立在Spring Framework 5,Project Reactor和Spring Boot 2上,使用非阻塞API。支持Websockets,因为它与Spring紧密集成,所以它是一个更好的开发者体验。
优劣势分析:
|
优点 |
缺点 |
Spring cloud gateway |
|
|
zuul 1 |
|
|
2.压测工具选择
经过各个维度的对比测试,压测工具选择wrk
wrk是一款简单的HTTP压测工具,托管在Github上有20k star,https://github.com/wg/wrk。
wrk的一个很好的特性就是能用很少的线程压出很大的并发量。原因是它使用了一些操作系统特定的高性能io机制,比如选择,epoll,kqueue等。其实它是复用了redis的ae异步事件驱动框架。确切的说ae事件驱动框架并不是redis发明的,它来至于Tcl的解释器jim,这个小巧高效的框架,因为被redis采用而更多的被大家所熟知。
3.测试方法与环境
结合业务实际情况,压测部分主要压测HTTP 1.1协议,由于使用的tomcat容器压测并发范围100~1500(250是最佳并发),spring cloud gateway 2.1.1和spring cloud支持最高zuul版本1.3.1。
建立三个项目用于测试
项目1:使用springboot搭建springcloud gateway
项目2:使用springboot搭建springcloud zuul
项目3:使用springboot搭建测试api,分别编写空负载接口与模拟50ms业务处理接口
分别使用springcloud gateway与zuul代理测试api,压测其性能
测试服务器信息:
机器ip |
cpu大小 |
内存大小 |
硬盘大小 |
备注 |
-.--.-.- |
4核 |
32G |
1T |
测试项目服务器 |
-.-.-.- |
4核 |
32G |
1T |
压测服务器 |
4.压测
4.1 100并发空负载测试
测试网关 |
吞吐率(req/sec) |
最大耗时(ms) |
平均耗时(ms) |
错误率 |
springcloud gateway |
16933 |
59.51 |
5.9 |
0% |
zuul |
14629 |
98.96 |
7.72 |
0% |
对比 |
16% |
-40% |
-24% |
0 |
4.2 250 并发空负载测试
测试网关 |
吞吐率(req/sec) |
最大耗时(ms) |
平均耗时(ms) |
错误率 |
springcloud gateway |
19246 |
163.63 |
13.27 |
0% |
zuul |
13140 |
415.85 |
24.64 |
0% |
对比 |
46% |
-61% |
-46% |
0 |
4.3 500 并发空负载测试
测试网关 |
吞吐率(req/sec) |
最大耗时(ms) |
平均耗时(ms) |
错误率 |
springcloud gateway |
19827 |
1050 |
38.73 |
0% |
zuul |
13181 |
403 |
40.37 |
0% |
对比 |
50% |
161% |
-4% |
0 |
4.4 1000并发空负载测试
测试网关 |
吞吐率(req/sec) |
最大耗时(ms) |
平均耗时(ms) |
错误率 |
springcloud gateway |
20818 |
1270 |
72.71 |
0% |
zuul |
12933 |
504.83 |
77.32 |
0% |
对比 |
61% |
152% |
-6% |
0 |
4.5 100并发模拟50ms业务处理
测试网关 |
吞吐率(req/sec) |
最大耗时(ms) |
平均耗时(ms) |
错误率 |
springcloud gateway |
1838 |
109.29 |
51.66 |
0% |
zuul |
379 |
1650 |
274.54 |
0% |
对比 |
385% |
-93% |
-81% |
0 |
4.6 250 并发模拟50ms业务处理
测试网关 |
吞吐率(req/sec) |
最大耗时(ms) |
平均耗时(ms) |
错误率 |
springcloud gateway |
3945.93 |
278 |
60.93 |
0% |
zuul |
393 |
1980 |
555.31 |
0% |
对比 |
904% |
-86% |
-89% |
0 |
4.7 500并发模拟50ms业务处理
测试网关 |
吞吐率(req/sec) |
最大耗时(ms) |
平均耗时(ms) |
错误率 |
springcloud gateway |
3928.37 |
332.22 |
124.58 |
0% |
zuul |
393.39 |
2130 |
1060 |
0% |
对比 |
899% |
-84% |
-88% |
0 |
4.8 1000并发模拟50ms业务处理
测试网关 |
吞吐率(req/sec) |
最大耗时(ms) |
平均耗时(ms) |
错误率 |
springcloud gateway |
3955.03 |
1470 |
255.88 |
0% |
zuul |
390.14 |
1990 |
1020 |
0% |
对比 |
914% |
-26% |
-75% |
0 |
5. 结果初步分析
初步分析,在空负载的时候,SpringCloud Gateway比zuul 1 性能高50%左右,在模拟处理50ms业务后,,SpringCloud Gateway比zuul 1 性能高9倍左右。
但是考虑到zuul使用默认配置,结果可能不准,上网查找zuul生产优化配置调优后再次进行50ms业务处理压测。而SpringCloud Gateway查阅资料后暂无需优化
zuul优化参数参考如下:
红框标记的参数是生产推荐参数,优化配置后再次进行压力测试
- zuul优化后的压测对比
5.1 100并发模拟50ms业务处理
测试网关 |
吞吐率(req/sec) |
最大耗时(ms) |
平均耗时(ms) |
错误率 |
springcloud gateway |
1838 |
109.29 |
51.66 |
0% |
zuul |
1836.87 |
84.21 |
51.68 |
0% |
对比 |
0% |
30% |
0% |
0 |
5.2 250 并发模拟50ms业务处理
测试网关 |
吞吐率(req/sec) |
最大耗时(ms) |
平均耗时(ms) |
错误率 |
springcloud gateway |
3945.93 |
278 |
60.93 |
0% |
zuul |
3918.83 |
104.74 |
60.56 |
0% |
对比 |
1% |
165% |
1% |
#DIV/0! |
5.3 500并发模拟50ms业务处理
测试网关 |
吞吐率(req/sec) |
最大耗时(ms) |
平均耗时(ms) |
错误率 |
springcloud gateway |
3928.37 |
332.22 |
124.58 |
0% |
zuul |
3955.43 |
176.69 |
124.46 |
0% |
对比 |
-1% |
88% |
0% |
#DIV/0! |
5.4 1000并发模拟50ms业务处理
测试网关 |
吞吐率(req/sec) |
最大耗时(ms) |
平均耗时(ms) |
错误率 |
springcloud gateway |
3955.03 |
1470 |
255.88 |
0% |
zuul |
3957.12 |
427 |
246 |
0% |
对比 |
0% |
244% |
4% |
0 |
6.最终结果与结论
6.1 性能比较结论
在实际生产使用中zuul 1与gateway性能没有差距
可以看出,在实际生产使用中,zuul 1虽然使用的是同步io,但是可以通过参数优化提高性能理论上可以达到极限性能,而springcloud gateway使用的是异步io,不需优化既可以达到接近极限的性能。
从5.1~5.4的压测结果来看,优化后的zuul 1和springcloud gateway性能都很强,由于底层使用的是java基本已经是极限性能(从二者十分接近可以看出),二者平均耗时与最大耗时的比较恰好是同步和异步的特征,异步总体平均耗时比同步略高一点点,而异步由于线程内部切换导致响应时间分布没有同步均匀。这个特性与测试结果符合,证实了测试数据的可靠性。
6.2 zuul1与gateway选择参考
如果是新的Springcloud项目,建议使用gateway,因为Spring官方主推gateway,而zuul最高只支持到1.3.1版本。而zuul 2的实现原理也是异步netty,与gateway,可以推断出gateway网关使用的技术是未来的主流方向,同时有很好的官方支持,与Springcloud兼容性好,并且开发使用简单。
如果是使用zuul的已有项目,不建议更换网关,使用Spring自带的zuul 1较为稳定,且有大量的业内生产验证,排查问题方便,同时性能也不存在问题,缺点是不支持长连接,不支持websocket。