如何使用大缓冲区设置HTTP出站网关发送请求

时间:2017-09-04 11:23:25

标签: file-upload spring-integration apache-httpclient-4.x

我使用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>

非常感谢。

2 个答案:

答案 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

Is there a way to see what the current value and change it for the socket buffer size used by Apache Http Client?

但为什么你认为问题不在服务器端呢?

答案 1 :(得分:0)

增加缓冲区大小无助于提高性能。 最后,我必须创建一个服务激活器,它将通过我的问题中提到的纯Java方法向远程发送请求。

  

我在纯Java中编写了一些测试(请参阅在Java中发送HTTP POST请求),结果如下。

我还比较发送到服务器的请求,但没有发现任何差异。这很奇怪。