我使用Spring Integration 4.3.9.RELEASE和Apache HTTP Component HttpClient(4.5.2)将包含300k上传文件的请求中继到后端服务。有时整个配置工作正常。但有时它的表现并不好,它会花费将近10分钟的时间来发送请求并获得相应的响应。我用纯Java编写了一些测试(参考Sending HTTP POST Request In Java),结果如下。
+------------------------------+------------------------+
| Data block size | Pause | Totally time consuming |
+------------------------------+------------------------+
| 2k | 1 second | ~6 minutes |
| 2k | 0.1 seocnd | ~33 seconds |
| 4k | 0.1 second | ~16 seconds |
| 0.2k | 0.1 second | ~6 minutes |
+------------------------------+------------------------+
每2k暂停1次并且每0.2k暂停0.1次的情况都具有接近时间的经过值。我想最有可能发生的事情是发送数据较小的块(0.2k)但停顿间隔较小(0.1s)。显然不满意需要10分钟才能得到回应。 那么如何将缓冲区设置得更大以确保性能呢?
我的配置如下。
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<constructor-arg>
<bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<constructor-arg>
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="org.apache.http.impl.client.HttpClients"/>
<property name="targetMethod" value="createMinimal"/>
</bean>
</constructor-arg>
<property name="connectTimeout" value="${wonders.cloud.api.request.timeout}" />
<property name="readTimeout" value="${wonders.cloud.api.request.timeout}" />
</bean>
</constructor-arg>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
<bean class="org.springframework.http.converter.FormHttpMessageConverter">
</bean>
</list>
</property>
</bean>
<bean id="objectMapper" class="org.springframework.integration.support.json.Jackson2JsonObjectMapper">
<constructor-arg ref="jacksonObjectMapper" />
</bean>
<bean id="jacksonObjectMapper" class="com.fasterxml.jackson.databind.ObjectMapper" >
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat">
<constructor-arg index="0" type="java.lang.String" value="yyyy-MM-dd'T'HH:mm:ss" />
</bean>
</property>
<property name="serializationInclusion" value="#{ T(com.fasterxml.jackson.annotation.JsonInclude.Include).NON_NULL }" />
</bean>
<bean class="org.springframework.beans.factory.config.MethodInvokingBean">
<property name="targetObject" ref="jacksonObjectMapper"/>
<property name="targetMethod" value="disable"/>
<property name="arguments" value="#{ T(com.fasterxml.jackson.databind.DeserializationFeature).FAIL_ON_UNKNOWN_PROPERTIES }"/>
</bean>
<bean class="org.springframework.beans.factory.config.MethodInvokingBean">
<property name="targetObject" ref="jacksonObjectMapper"/>
<property name="targetMethod" value="enable"/>
<property name="arguments" value="#{ T(com.fasterxml.jackson.databind.DeserializationFeature).READ_UNKNOWN_ENUM_VALUES_AS_NULL }"/>
</bean>
<int-http:inbound-gateway id="certificateInboundGateway"
path="/{uuid}/certificate"
supported-methods="POST"
request-channel="certificateRequestChannel"
reply-channel="certificateResponseChannel"
reply-key="fullway"
view-name="index">
<int-http:header name="uuid" expression="#pathVariables.uuid" />
</int-http:inbound-gateway>
<int:channel id="certificateRequestChannel" />
<int:channel id="certificateResponseChannel" />
<int:chain id="certificateProcessChain"
input-channel="certificateRequestChannel"
output-channel="certificateResponseChannel">
<int:header-enricher>
<int:header name="multipartForm" expression="payload"/>
</int:header-enricher>
<int:transformer expression="headers.uuid" />
<int:gateway request-channel="crmMemberInfoRetrieveChannel" />
<int:filter expression="payload != null" />
<int:transformer expression=" T(com.wd.fw.business.facade.huayan.transformer.WondersCloudObjectTransformer).buildCertificateForm(headers.multipartForm, payload.get('userid'), '${wonders.cloud.api.token}') " />
<int:transformer ref="commonHeaderEnricher" method="transform" />
<int:header-enricher>
<int:header name="octopus_sid" expression="'${wonders.cloud.api.octopus.sid}'" overwrite="true" />
<int:header name="Content-Type" expression="'multipart/form-data'" overwrite="true" />
<int:header name="octopus_apiid" expression="'${wonders.cloud.api.certificate.octopus.apiid}'" />
</int:header-enricher>
<int-http:outbound-gateway url="${wonders.cloud.api.protocol}://${wonders.cloud.api.host}/${wonders.cloud.api.context.path}"
http-method="POST"
header-mapper="headerMapper"
rest-template="restTemplate"
charset="UTF-8"
expected-response-type="java.lang.String">
<int-http:request-handler-advice-chain>
<ref bean="retrier" />
</int-http:request-handler-advice-chain>
</int-http:outbound-gateway>
<int:gateway request-channel="dataEncryptChannel" />
</int:chain>
非常感谢。
答案 0 :(得分:0)
您可以尝试这样的事情:
ConnectionConfig connConfig = ConnectionConfig.custom()
.setBufferSize(DESIRED_BUFFER_SIZE)
.build();
CloseableHttpClient client = HttpClients.custom()
.setDefaultConnectionConfig(connConfig)
.build();
Setting socket buffer size in Apache HttpClient
但为什么你认为问题不在服务器端呢?
答案 1 :(得分:0)
增加缓冲区大小无助于提高性能。 最后,我必须创建一个服务激活器,它将通过我的问题中提到的纯Java方法向远程发送请求。
我在纯Java中编写了一些测试(请参阅在Java中发送HTTP POST请求),结果如下。
我还比较发送到服务器的请求,但没有发现任何差异。这很奇怪。