解放しません:PoolingHttpClientConnectionManagerは、私は次のことを達成するために春を使用しています接続
をサーバー上に、私は、XML形式でRESTインターフェースを介してデータを受け取ります。データをJSONに変換し、別のサーバーにPOSTしたいと思っています。私のコードは、(私は私の雇用者の怒りを避けるために、いくつかの敏感なクラス名/ URLの削除)次のようになります。
メイン/ Configurationクラス:
package stateservice;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class App {
Logger log = LoggerFactory.getLogger(App.class);
public static void main(String[] args) {
System.out.println("Start!");
SpringApplication.run(StateServiceApplication.class, args);
System.out.println("End!");
}
@Bean
public RestTemplate restTemplate() {
log.trace("restTemplate()");
HttpHost proxy = new HttpHost("proxy_url", 8080);
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
// Increase max total connection to 200
cm.setMaxTotal(200);
cm.setDefaultMaxPerRoute(50);
RequestConfig requestConfig = RequestConfig.custom().setProxy(proxy).build();
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
httpClientBuilder.setDefaultRequestConfig(requestConfig);
httpClientBuilder.setConnectionManager(cm);
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(
httpClientBuilder.build());
return new RestTemplate(requestFactory);
}
}
RESTfulなインターフェースを表すクラス:
package stateservice;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import foo.bar.XmlData
@RestController
public class StateController {
private static Logger log = LoggerFactory.getLogger(DataController.class);
@Autowired
ForwarderService forwarder;
@RequestMapping(value = "/data", method = RequestMethod.POST)
public String postState(@RequestBody XmlData data) {
forwarder.forward(data);
return "Done!";
}
}
を
最後に、フォワーダー:
package stateservice;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import foo.bar.Converter;
import foo.bar.XmlData;
@Service
public class ForwarderService {
private static Logger log = LoggerFactory.getLogger(ForwarderService.class);
String uri = "forward_uri";
@Autowired
RestTemplate restTemplate;
@Async
public String forward(XmlData data) {
log.trace("forward(...) - start");
String json = Converter.convert(data);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> response = restTemplate.postForEntity(uri,
new HttpEntity<String>(json, headers), String.class);
// responseEntity.getBody();
// log.trace(responseEntity.toString());
log.trace("forward(...) - end");
return response.getBody();
}
}
ただし、接続マネージャめったにありませんCLOSE_WAIT状態(netstatを使って見ることができる)の接続でシステムが浸水してしまいます。プール内のすべての接続はリースされますが、解放されません。CLOSE_WAIT状態の接続数がulimitに達すると、「開いているファイルが多すぎます」という例外が発生します。
コードのマルチスレッド性私は、ソケットが閉じられない/接続が解放されると思われます。なぜなら、他のスレッドがそれらをブロックしているからです。
私は問題を解決するために何か助けやヒントをいただければ幸いです。
コードは問題ありません。サーバーが応答を提供していますか?あなたは 'requestFactory'で' setConnectTimeout'と 'setReadTimeout'プロパティを設定しようとしましたか? 'ForcededService'を(' @ Async'なしで)同期して呼び出すと動作しますか? – Ruben
はい、サーバーが応答します(ステータス '200 OK')。私はタイムアウトを設定し、転送方式を同期的に呼び出しました - 何も助けられませんでした。 – pczora
私が持っている唯一の提案はKeepAlive戦略を構成することです。 [http client docs](http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html)の第2.6章を参照してください。 – Ruben