SpringCIoud-Gateway 从升级到放弃
为什麽要升级为spring-cloud-gateway?
Spring Cloud Gateway features:
Built on Spring Framework 5, Project Reactor and Spring Boot 2.0
Able to match routes on any request attribute.
Predicates and filters are specific to routes.
Hystrix Circuit Breaker integration.
Spring Cloud DiscoveryClient integration
Easy to write Predicates and Filters
Request Rate Limiting
Path Rewriting
这是官方说的,spring gateway相对spring zuul要新很多,应用也更加自由,开发体验更好。但是我在测试中发现,spring-cloud-gateway相对于zuul来说,更加出众的还是其性能,当然最后让我放弃的也是因为这一点。
网上的朋友也有做一些gateway和zuul的性能比较,大多的结论也是gateway要优于zuul,同时也更加稳定。
但是我们不能轻信,所以我也做了测试,这部分测试内容若不感兴趣可以跳过,zuul就不测试了。
2.spring-cloud-gateway的初步测试
step.1:测试准备:
1.gateway版本:2.0.1
2.服务主机:10.1.4.32,16G内存,4核虚拟机
3.测试客户端:10.1.4.34,16G内存,4核虚拟机
4.测试工具wrk
step.2:建立gateway工程并写两个测试http接口,
1.http://10.1.4.32:14077/hello [POST]
2.http://10.1.4.32:14077/test [GET]
step.3:开始测试
step.4:测试结果
复制代码
[wrk@localhost wrk]$ ./wrk -t 15 -c500 -d 10 --latency http://10.1.4.32:14077/test
Running 10s test @ http://10.1.4.32:14077/test
15 threads and 500 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 3.38ms 3.26ms 113.45ms 95.76%
Req/Sec 10.84k 1.44k 26.48k 89.50%
Latency Distribution
50% 2.79ms
75% 3.51ms
90% 4.21ms
99% 17.23ms
1625714 requests in 10.10s, 131.79MB read
Requests/sec: 160961.07
Transfer/sec: 13.05MB
复制代码
以及:
复制代码
[wrk@localhost wrk]$ ./wrk -t 15 -c500 -d 10 --latency -s scripts/gateway.lua http://10.1.4.32:14077/hello
Running 10s test @ http://10.1.4.32:14077/hello
15 threads and 500 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 5.21ms 3.96ms 255.59ms 96.75%
Req/Sec 6.62k 604.79 13.72k 88.48%
Latency Distribution
50% 4.78ms
75% 5.55ms
90% 6.32ms
99% 14.87ms
994374 requests in 10.10s, 539.59MB read
Requests/sec: 98471.14
Transfer/sec: 53.43MB
复制代码
说明,如果测试结果差别较大可能是因为测试工具的问题。
结果显示,POST方法的性能TPS达到了10W/s,而GET方法的性能TPS达到了16W/s。
这看起来很不可思议,因为正常的微服务,能达到2W/s的性能已经是良好,达到10W实在是不可思议。但是前面说了spring-cloud-gateway引入了Spring Reactor反应式编程,应对的便是这种高并发需求。
当然,即便spring-cloud-gateway给了我们很大惊喜,但是如果因此就引入了spring-cloud-gateway,那还是会有些草率,毕竟gateway是用来干什么的?是路由和过滤。继续测试。
step.5:加上路由和过滤器,在配置文件中加入下面内容
复制代码
spring:
cloud:
gateway:
routes:
- id: test
uri: http://10.1.4.32:14077/test
predicates:
- Path=/tt
filters:
- AddRequestParameter=foo, bar
复制代码
表示,给test方法加入了路由,并且加入了官方提供的过滤器:AddRequestParameter=foo, bar
step.6:测试,并附测试结果:
复制代码
[wrk@localhost wrk]$ ./wrk -t 15 -c500 -d 10 --latency http://10.1.4.32:14077/tt
Running 10s test @ http://10.1.4.32:14077/tt
15 threads and 500 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 18.99ms 12.15ms 122.69ms 70.84%
Req/Sec 1.82k 155.77 2.36k 73.94%
Latency Distribution
50% 17.03ms
75% 25.49ms
90% 35.02ms
99% 57.13ms
274529 requests in 10.10s, 22.25MB read
Requests/sec: 27182.88
Transfer/sec: 2.20MB
复制代码
性能只剩27000/s,貌似降低了很多,但是比起zuul仍然快了不少。因为在这台机器上,测试zuul或许都不能到达2W。
那么,是不是就应该使用spring-cloud-gateway了?
3.开始使用spring-cloud-gateway
在使用上spring-cluod-gateway之后,我开始编辑自己的过滤器,需求要求写两个过滤器,修改请求体和响应体。
因为需要对特定的请求使用过滤器,所以这里使用gateway-filter,有些代码官方有,有些网友提供,两个过滤器代码大致如下:
解密过滤器,pre:
View Code
加密过滤器,使用源码的提供的修改方法,post:
View Code
这里需要转移一下话题,这个过滤器修改其实有几种方法,可以自己写,也可以应用源码提供的例子。上面的两种写法已经测试都能使用,其实我还有两种方式,大同小异就是了,但也准备贴出来,也记录一下问题:
下面这个其实就是源码中的例子,只不过不引用,自己写:
View Code
这种例子中,发现修改response body的时候,会引起代码进入NioEventLoop类中的run方法,死循环无法退出,我也不清楚为什么,修改需谨慎。
另一种,跟这位网友写得差不多,只不过我没测试就是了:https://www.jianshu.com/p/9f00e0e1681c
View Code
这个方法会出现问题,body的截取长度经常没有完全。
我本来是到这个网址下面寻找答案,作者是这样回复的:
上面只是简单的样例,FIux是发送多个数据的,当报文长时会拆分,处理一次只能拿到一部分报文,可以使用Flux.toArray方法将数据聚合后处理,也可以参照https://www.jianshu.com/p/9b781fb1aaa0里面的响应处理。
确实是这个问题,所以我们也可以仿照他的另外一个例子写,大家可以到他的简书博客中去看,值得提醒的是,他的例子中,版本也是2.0.1,若是版本改为2.1以上,就不能用哦!
这里蛮贴一下:
View Code
那么万事具备,代码都写好了,我们又需要进行性能测试。这边要记住,我用的是官方的那个例子,其他的写法也用过了,但是结果差不多。
4.再一次测试spring-cloud-gateway 网关路由性能
step.1:性能测试,改一下配置,表示加入了过滤器。这里为什么只有一个过滤器,因为这个过滤器问题比较大,过程就略过了。
复制代码
- id: an
uri: http://10.1.4.32:14077/hello
predicates:
- Path=/an
filters:
- An
复制代码
经过多次测试,其他的过滤器都还好,只有修改response body的过滤器,严重影响性能,且有读写错误。
step.2:测试,以及测试结果
复制代码
[wrk@localhost wrk]$ ./wrk -t 15 -c500 -d 10 --latency -s scripts/gateway.lua http://10.1.4.32:14077/an
Running 10s test @ http://10.1.4.32:14077/an
15 threads and 500 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.03s 488.75ms 2.00s 60.62%
Req/Sec 26.59 13.84 80.00 67.60%
Latency Distribution
50% 931.54ms
75% 1.45s
90% 1.76s
99% 1.97s
3848 requests in 10.10s, 1.64MB read
Socket errors: connect 0, read 0, write 0, timeout 458
Requests/sec: 381.05
Transfer/sec: 166.71KB
复制代码
结果多出一行,socket错误,而且还是超时,而且,日志中也存在错误:
复制代码
2019-03-06T16:09:33,396|INFO ||AsyncResolver-bootstrap-executor-0||||Resolving eureka endpoints via configuration
2019-03-06T16:10:38,268|ERROR||reactor-http-server-epoll-18||||Unhandled failure: Connection has been closed, response already set (status=200)
2019-03-06T16:10:38,268|WARN ||reactor-http-server-epoll-18||||Handling completed with error: Connection has been closed
2019-03-06T16:10:38,269|ERROR||reactor-http-server-epoll-18||||Unhandled failure: null, response already set (status=200)
2019-03-06T16:10:38,269|WARN ||reactor-http-server-epoll-18||||Handling completed with error: null
2019-03-06T16:10:38,294|ERROR||reactor-http-server-epoll-18||||Unhandled failure: syscall:write(..) failed: 断开的管道, response already set (status=null)
2019-03-06T16:10:38,294|WARN ||reactor-http-server-epoll-18||||Handling completed with error: syscall:write(..) failed: 断开的管道
2019-03-06T16:10:38,306|ERROR||reactor-http-server-epoll-23||||Unhandled failure: syscall:write(..) failed: 断开的管道, response already set (status=null)
2019-03-06T16:10:38,306|WARN ||reactor-http-server-epoll-23||||Handling completed with error: syscall:write(..) failed: 断开的管道
2019-03-06T16:14:33,397|INFO ||AsyncResolver-bootstrap-executor-0||||Resolving eureka endpoints via configuration
复制代码
这个问题很严重了,因为单个请求的时候,并不会报错,这个错误只发生在高并发压测下,无法追踪。最重要的是,我们看到性能只剩下300/s,这是万万不能接受的,生产更不能接收。
这个问题很难解释,因为我们采用的是官方提供的写法,我们回头看官方的修改response 类,好吧,不用看了,因为:
复制代码
package org.springframework.cloud.gateway.filter.factory.rewrite;
/**
* This filter is BETA and may be subject to change in a future release.
*/
public class ModifyResponseBodyGatewayFilterFactory
extends AbstractGatewayFilterFactory {
复制代码
官方已经说了,这是测试版本,不顶用。
不死心,又想起了gateway提供的GlobalFilter,将刚才的代码写到全局过滤器中再试试,但是结果相同!
凉凉...
跪求结论跟我不同的启发文档,或者只能等下一版本了。
https://www.cnblogs.com/garfieldcgf/p/10484119.html