Spring Zuul 性能调优,如何提升平均响应时间200% ?
最近负责公司的 Gateway 项目,我们用 Spring Zuul 来做 HTTP 转发,但是发现请求多的时候,AWS 的健康检查就失败了,但是实际上程序还在跑,在日志上也没有任何东西错误打印出来出来。通过本身上报的性能数据发现,backend_processing_time 非常高,正常的情况下,这个数据约等于下游服务的响应时间。但是下游服务的响应时间都在500毫秒左右,所以问题出在 Zuul 本身上。
我们的 backend_processing_time 实际上就是取的 Zuul 本身的 SimpleHostRoutingFilter 的执行时间,如果花在网络通信上的时间不多,那么一定是这个 Filter 本身在哪里卡住了。我阅读了这个 Filter 的源码,发现实际上这个 Filter 本身是用的 Apache HTTP Client 来执行网络请求的,而且是用的池化的链接。
在 Zuul 的配置里,有这么一个配置 `zuu.host.max-per-route-connections` 这个配置对应的就是 Apache HTTP Client 中的 DefaultMaxPerRoute,文档这么写到:
A request for a route for which the manager already has a persistent connection available in the pool will be serviced by leasing a connection from the pool rather than creating a brand new connection.
PoolingHttpClientConnectionManager
maintains a maximum limit of connections on a per route basis and in total. Per default this implementation will create no more than 2 concurrent connections per given route and no more 20 connections in total. For many real-world applications these limits may prove too constraining, especially if they use HTTP as a transport protocol for their services.
这个类似于数据库的链接池,一般而言从链接池拿链接的时候,都会有个超时时间,过了这个超时时间,会抛异常。其实这个超时时间也是有的,对应的是 Apache HTTP Client 中的 `getRequestTimeout`。问题是,在 Zuul 中,这个超时时间为-1,并且不能设置。根据 Apache HTTP Client 中的文档,
Returns the timeout in milliseconds used when requesting a connection from the connection manager. A timeout value of zero is interpreted as an infinite timeout. A timeout value of zero is interpreted as an infinite timeout. A negative value is interpreted as undefined (system default).
所以当 HTTP 链接拿完以后,线程就等在那里,造成整个系统 Hang 住。解决办法就是,提升这个max-per-route-connections的数值,以下是两次压测的结果
max-connection-per-route = 20
max-connection-per-route = 300
从压测结果得知,评价响应时间提升了200%,P90 提升了 100%。