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。