如何使用大缓冲区设置HTTP出站网关发送请求
How to set HTTP outbound gateway sending request using big buffer
我使用 Spring Integration 4.3.9.RELEASE 和 Apache HTTP Component HttpClient (4.5.2) 将包含 300k 上传文件的请求中继到后端服务。有时整个配置工作正常。但有时它的表现不是很好,发送请求和得到响应需要将近 10 分钟。我用纯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停顿1s和每0.2k停顿0.1s的场景都有一个close time elapsed值。我想最有可能发生的是发送数据块较小 (0.2k) 但暂停间隔较短 (0.1s)。需要10分钟才能得到回应,这显然不能令人满意。
那怎么把buffer设置大一点才能保证性能呢?
我的配置如下
<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>
非常感谢。
您可以尝试这样的操作:
ConnectionConfig connConfig = ConnectionConfig.custom()
.setBufferSize(DESIRED_BUFFER_SIZE)
.build();
CloseableHttpClient client = HttpClients.custom()
.setDefaultConnectionConfig(connConfig)
.build();
但是为什么你认为问题不在服务器端呢?
增加缓冲区大小无助于提高性能。
最终,我必须创建一个服务激活器,它将通过我的问题中提到的纯 java 方法向远程发送请求。
I write some tests in pure Java (refer to Sending HTTP POST Request In Java) and results as following.
我也比较了发送到服务器的请求,没有发现任何差异。很奇怪。
我使用 Spring Integration 4.3.9.RELEASE 和 Apache HTTP Component HttpClient (4.5.2) 将包含 300k 上传文件的请求中继到后端服务。有时整个配置工作正常。但有时它的表现不是很好,发送请求和得到响应需要将近 10 分钟。我用纯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停顿1s和每0.2k停顿0.1s的场景都有一个close time elapsed值。我想最有可能发生的是发送数据块较小 (0.2k) 但暂停间隔较短 (0.1s)。需要10分钟才能得到回应,这显然不能令人满意。 那怎么把buffer设置大一点才能保证性能呢?
我的配置如下
<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>
非常感谢。
您可以尝试这样的操作:
ConnectionConfig connConfig = ConnectionConfig.custom()
.setBufferSize(DESIRED_BUFFER_SIZE)
.build();
CloseableHttpClient client = HttpClients.custom()
.setDefaultConnectionConfig(connConfig)
.build();
但是为什么你认为问题不在服务器端呢?
增加缓冲区大小无助于提高性能。 最终,我必须创建一个服务激活器,它将通过我的问题中提到的纯 java 方法向远程发送请求。
I write some tests in pure Java (refer to Sending HTTP POST Request In Java) and results as following.
我也比较了发送到服务器的请求,没有发现任何差异。很奇怪。