SpringCloud F版FeignClient的坑

现象:

近期做压力测试,服务是基于spring cloud F版的,分为server和client,调用方式为FeignClient。
测试工具为jmeter。
结果发现,并发线程数较多(>40)时,持续一段时间后,请求总数差不多达到100万时,开始出现请求失败。这个错误比例在10%~30%之间。
看日志,发现错误有两种:
一种是ribbon报找不到目标服务,错误信息如下:

Caused by: com.netflix.client.ClientException: Load balancer does not have available server for client: halo-framework-example-server
	at com.netflix.loadbalancer.LoadBalancerContext.getServerFromLoadBalancer(LoadBalancerContext.java:483)
	at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:184)
	at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:180)
	at rx.Observable.unsafeSubscribe(Observable.java:10327)
	at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:94)
	at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:42)

另一种是无法绑定地址,错误信息如下:

java.net.ConnectException: Cannot assign requested address (connect failed)
	at java.net.PlainSocketImpl.socketConnect(Native Method) ~[na:1.8.0_152]
	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) ~[na:1.8.0_152]
	at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) ~[na:1.8.0_152]
	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) ~[na:1.8.0_152]
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) ~[na:1.8.0_152]
	at java.net.Socket.connect(Socket.java:589) ~[na:1.8.0_152]
	at sun.net.NetworkClient.doConnect(NetworkClient.java:175) ~[na:1.8.0_152]
	at sun.net.www.http.HttpClient.openServer(HttpClient.java:463) ~[na:1.8.0_152]
	at sun.net.www.http.HttpClient.openServer(HttpClient.java:558) ~[na:1.8.0_152]
	at sun.net.www.http.HttpClient.(HttpClient.java:242) ~[na:1.8.0_152]
	at sun.net.www.http.HttpClient.New(HttpClient.java:339) ~[na:1.8.0_152]
	at sun.net.www.http.HttpClient.New(HttpClient.java:357) ~[na:1.8.0_152]

针对第一个错误,首先是怀疑代码有问题,结果看了一天的代码,仔细检查了feignclient调用的过程,没有发现什么问题。
针对第二个问题,网上可以找到不少帖子,意思都是,本地端口消耗完了,所以需要增加端口数量。但是我们使用feignclient的本意,是通过apache httpclient或okhttp提供高性能服务,端口数量消耗过多并不是我们希望发生的。

调查步骤

首先,我们增加了tomcat的线程数,feign.httpclient的线程等。

feign.httpclient.max-connections-per-route=200
feign.httpclient.max-connections=500

测试结果还是没有变化。

后来忽然意识到,前面ConnectException的调用栈里,根本没有apache httpclient。
于是开始看feignclient调用哪个httpclient的代码。
spring-cloud-openfeign-core包里,有FeignRibbonClientAutoConfiguration文件。里面配置如下:

@Import({ HttpClientFeignLoadBalancedConfiguration.class,
		OkHttpFeignLoadBalancedConfiguration.class,
		DefaultFeignLoadBalancedConfiguration.class })
public class FeignRibbonClientAutoConfiguration {

import的3个文件分别定义了apache httpclient,okhttpclient,java自带的httpclient。

第一个文件的头部如下:

@Configuration
@ConditionalOnClass(ApacheHttpClient.class)
@ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true)
class HttpClientFeignLoadBalancedConfiguration {

可以发现,前面的conditiononclass是个奇怪的类:ApacheHttpClient
这个类找不到定义。
百度了一把,发现这个类属于包属于一个feign-httpclient的包。
maven仓库配置如下:



    io.github.openfeign
    feign-httpclient
    9.7.0

此处选择和feign-core版本一致的包。

加上这个包后,jemeter跑到1000万次请求,都没有出现上述的错误。
至于为什么第二个问题解决后,第一个问题也没有了,还是没有想明白。

你可能感兴趣的:(SpringCloud F版FeignClient的坑)