Я использую Spring для достижения следующего:PoolingHttpClientConnectionManager не освобождает соединения
На сервере, я получаю данные через интерфейс REST в качестве XML-формате. Я хочу преобразовать данные в JSON и POST на другой сервер. Мой код (я удалил некоторые чувствительные имена классов/URL, чтобы избежать гнева моего работодателя) выглядит следующим образом:
Основной класс/Конфигурация:
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, я получаю «Слишком много открытых файлов» - исключения
Из-за многопоточного характера кода , Я подозреваю, что сокеты не могут быть закрыты/соединения освобождены, потому что какой-то другой поток как-то блокирует их.
Я бы очень признателен за любую помощь или любой намек, который вы можете дать мне, чтобы решить эту проблему.
Ваш код выглядит нормально. Вы уверены, что сервер доставляет ответы? вы пытались установить свойства 'setConnectTimeout' и' setReadTimeout' в 'requestFactory'? Работает ли он, когда вы вызываете 'ForwardedService' синхронно (без' @ Async')? – Ruben
Да, сервер отвечает (статус «200 OK»). Я установил таймауты и синхронно вызвал метод пересылки - ничего не помогло. – pczora
Единственное, что у меня есть, это настроить стратегию KeepAlive. Взгляните на главу 2.6 в [http client docs] (http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html) – Ruben