๐ฟ org.apache.http.NoHttpResponseException ๐ฟ
์ธ๋ถ ์๋ฒ์ ์ฐ๋ ํ ์ด์ ์ค์ ๊ฐํ์ ์ผ๋ก ์ ์์ ์ธ ์๋ต์ด ๋จ์ด์ง์ง ์์๋๋ฐ, stacktrace๋ฅผ ์ดํด๋ณด๋ ์ฌ์๋ ํ๋ฉด ํด๊ฒฐ๋ ๋ฏํ๋ฐ ๋ช ํํ์ง ์์ผ๋ฏ๋ก ์ข ๋ ์ฐพ์๋ณด๊ธฐ๋ก ํ๋ค.
ํ๊ฒ ์๋ฒ์์ ์ ํจํ์ง ์์ HTTP ์๋ต์ผ๋ก ์ ๋๋ก ์๋ตํ๊ธฐ๋ฅผ ์คํจํ๋ค๋ ์ ํธ๋ผ๊ณ ํ๋๋ฐ ๋ฌธ์ ๋ ์ด๊ฑฐ๋ค.
ํ์์ ์ด์ ๋ HTTP/1.1์ Keep-Alive๋ก ์ธํด httpclient๋ ํต์ ์ด ๋๋ connection์ ์ข ๋ฃํ์ง ์๊ณ ๋์ผhost:port์ ๋ํด ๋์ผํ ์ปค๋ฅ์ ์ ์ด์ฉํ๋ ค ํ๊ธฐ ๋๋ฌธ์ด๋ค.
๋น๋ก ์๋ฒ์ธก์ ํต์ ์ด ์๋ฃ๋์ด ํด๋น ์ฐ๊ฒฐ์ close ํ ์ง๋ผ๋ client ์ธก์ ์ปค๋ฅ์ ๊ฐ์ฒด๊ฐ ์ฌ์ ํ ์ด๋ ค์๊ณ ๋ฐ์ดํฐ๊ฐ ์ธ์ ๋๊ธธ ๊ธฐ๋ค๋ฆฌ๊ณ ์๊ฒ๋๋ค. ( close()์ ์ค์ ์๋ฏธ๋ ์์ผ์ ๋จ์ ์ด ์๋ “๋๋ ๋ ์ด์ ๋ณด๋ผ ๋ฐ์ดํฐ๊ฐ ์์ต๋๋ค.“๋ก ์๋์ธก์์๋ ํด๋น ์ปค๋ฅ์ ์ ๋จ์ ํ์ง ์๋ ์ด์ ์ฌ์ ํ ๋ฐ์ดํฐ๊ฐ ์ธ์ ๋ ์ ์์์ ์๋ฏธํ๋ค. )
์ด๋๋ฅผ half-closed connection ์ผ๋ก ํํํ๋ฉฐ ์ด๋ TCP๊ฐ ๊ทธ๋ ๊ฒ ๋์ํ๊ฒ๋ ์ค๊ณ๋์๊ธฐ ๋๋ฌธ์ผ๋ก ๋ฒ๊ทธ๊ฐ ์๋๋ค. ์ด๋ฐ ์ํฉ์ด ๋๋ฉด JVM์์ connection ๊ฐ์ฒด๋ ๋น์ฐํ ์ด์์์ง๋ง ๋ด๋ถ ์์ผ์ CLOSE_WAIT ์ํ๊ฐ ๋๋ค.
์ ์์ ์ธ ์ํ์ด๊ณ ํต์ ์ด ๋๋ ์ํฉ์ด์ง๋ง ์ด์์๋ ์ปค๋ฅ์ ์ผ๋ก ๋ ์ฐ๊ฒฐ์ ๋งบ์ผ๋ฉด์ ๋ฐ์ํ๋ค ๋ผ๋ ๊ฒ.
์ด์ ๋ฌธ์ ํด๊ฒฐ๋ฐฉ์์ ์ฐพ์๋ณด๋๋ก ํ๋ค.
๋ฒ์ ๋ฌธ์ ๋ผ๊ณ ํ๋ ์๊ฒฌ์ด ์์์ง๋ง ์ต์ ๋ฒ์ ์ ์ฌ์ฉํ๊ณ ์์ผ๋ฏ๋ก ์ด ์๊ธฐ๋ ๋ง์ง ์๊ณ
public PoolingHttpClientConnectionManager(HttpClientConnectionOperator httpClientConnectionOperator, HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory, long timeToLive, TimeUnit tunit) {
this.log = LogFactory.getLog(this.getClass());
this.configData = new PoolingHttpClientConnectionManager.ConfigData();
this.pool = new CPool(new PoolingHttpClientConnectionManager.InternalConnectionFactory(this.configData, connFactory), 2, 20, timeToLive, tunit);
this.pool.setValidateAfterInactivity(2000);
this.connectionOperator = (HttpClientConnectionOperator)Args.notNull(httpClientConnectionOperator, "HttpClientConnectionOperator");
this.isShutDown = new AtomicBoolean(false);
}
์ปค๋ฅ์ ์ ์ฌ์ฉํ๊ธฐ ์ ์ ๋ง์ง๋ง์ผ๋ก ์ฌ์ฉํ๋ ๊ฒฝ๊ณผ์๊ฐ(`validAfterInactivity` = 2000ms default)์ ์ข ๋ ์ค์ด๋ผ๋ ์๊ธฐ๊ฐ ์์ด ์๋ํด๋ณด๋ ค ํ์ง๋ง, ๋ง์นจ ์๋ํด๋ณด์๋ ์ฌ๋์ด ์์ด ํ์ธํด๋ณด๋ ์ ๋๋ก ์ํนํ์ง ์๋๋ค ํด์ ๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ฐพ์๋ณธ๋ค.
๋ง์ง๋ง์ผ๋ก ์ ์ฉํ ํด๊ฒฐ์ฑ ์ ์๋์ ๊ฐ๋ค.
HttpClient ํต์ ์ ์ด์ฉํ ๋ KeepAlive ์ค์ ์ ํ์ง ์์ผ๋ฉด ๊ณ์ ์ ์งํ๋ค๊ณ ํ์ง๋ง, ์ต๋ํ 2์๊ฐ๊น์ง ์ค์ ํ ์ ์๋ ๊ฑธ๋ณด๋ HTTP ์๋ฒ์์ ๋ฌด๊ธฐํ์ผ๋ก ์ ์งํ๊ณ ์์ง ์๋ ๋ฏํ๋ค. (ํ์ฌ KeepAlive ์ค์ ์ ON์) ์ด๋ ์์ค์์ ์ปค๋ฅ์ ์ ๋๋์ง๋ ๋ ์์๋ด์ผํ ๋ฏ ํ๋ค.
์ฝ๋๋ฅผ ๋งค์ฐ ์ผ์ถ ๋ณด๋ฉด..keepalive ์ต์ ์ด ์ ์ ๋์ง ์์ผ๋ฉด -1๋ก ์ค์ ํ๋ ๋ฌด๊ธฐํ์ผ๋ก ๋ณด๊ณ ์๋ ๋ฏํ๋ค. (์ ๋ง ๋ง๋ฅ ๋ฌด๊ธฐํ์ด์ง ์๊ฒ ์ง๋ง) ์์ธํ ๋ด์ฉ์ ์ด๊ณณ์ ์ฐธ๊ณ ํด๋ ์ข๋ค.
> If the Keep-Alive header is not present in the response, HttpClient assumes the connection can be kept alive indefinitely.
if (this.reuseStrategy.keepAlive(response, context)) {
long duration = this.keepAliveStrategy.getKeepAliveDuration(response, context);
if (this.log.isDebugEnabled()) {
String s;
if (duration > 0L) {
s = "for " \+ duration + " " \+ TimeUnit.MILLISECONDS;
} else {
s = "indefinitely";
}
this.log.debug("Connection can be kept alive " \+ s);
}
connHolder.setValidFor(duration, TimeUnit.MILLISECONDS);
connHolder.markReusable();
์์ ๊ฐ์ด ๋ฌด๊ธฐํ์ผ๋ก ์ค์ ํด์ฃผ์ง ์๊ณ ๋ช ์์ ์ผ๋ก ์งง์ ์๊ฐ์ ๊ฐ์ ธ๊ฐ๋๋ก ์ปค์คํ ์ผ๋ก KeepAliveStrategy๋ฅผ ์ค์ ํด์ (์ด ์ค์ ํ ์ฐ๊ฒฐ ๋น์ฆ๋์ค ์์ฒด๊ฐ keepalive๋ฅผ ๊ธธ๊ฒ ์ง์ํ ์ ๋๊น์ง ์๋๋ค.) ์ปค๋ฅ์ ํด์ ๋ฅผ ๋น ๋ฅด๊ฒ ์ฒ๋ฆฌํ๊ฒ๋ ์ฒ๋ฆฌํด์คฌ๋ค. (๋ด ์๊ธฐ..KeepAlive ์ค์ ์ด ๋น๋ฒํ๊ฒ ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์ ๋ ์ฑ๋ฅ ํฅ์์ ํค ํฌ์ธํธ๊ฐ ๋์ง๋ง ์ญ์ผ๋ก ๊ทธ๋ ์ง ์์ ๋ ๋ฆฌ์์ค๋ฅผ ๋ฌผ๊ณ ์๊ธฐ์ ๊ทธ๋ ์ง ์์ ๋๋ ์๋ค.)
HttpClient์์ ์ฌ์ฉํ๊ณ ์๋ ConnectionKeepAliveStrategy๋ฅผ ๊ตฌํํด๋ณด์. ๊ด๋ จํ connectionmanegement ์ํ์น ํํ ๋ฆฌ์ผ์ ๋ด๋ ์ข๋ค. ํน์ ํ๊ฒ ํธ์คํธ๋ง Keep-Alive timeout์ ๋ณด๋ค ์งง๊ฒ ๊ฐ์ ธ๊ฐ๊ฒ๋ ์ค์ ํด์ค๋ค.
public class HttpKeepAliveStrategy implements ConnectionKeepAliveStrategy {
private static final String KEEP_ALIVE_TARGET_HOST_NAME = "https://target.host.name";
@Override
public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
// Honor 'keep-alive' header
HeaderElementIterator it = new BasicHeaderElementIterator(
response.headerIterator(HTTP.CONN_KEEP_ALIVE));
while (it.hasNext()) {
HeaderElement he = it.nextElement();
String param = he.getName();
String value = he.getValue();
if (value != null && param.equalsIgnoreCase("timeout")) {
try {
return Long.parseLong(value) * 1000;
} catch (NumberFormatException ignore) {
}
}
}
HttpHost target = (HttpHost) context.getAttribute(HttpClientContext.HTTP_TARGET_HOST);
if (KEEP_ALIVE_TARGET_HOST_NAME.equalsIgnoreCase(target.getHostName())) {
return 5 * 1000;
} else {
return 30 * 1000;
}
}
}
์ฐธ๊ณ URL
'server' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
locust (0) | 2021.04.20 |
---|---|
๋ฉํฐ๋ชจ๋์ ํ ๋ฐฉ์ผ๋ก ์ ์ฉ๋๋ application.yml (0) | 2020.06.08 |
tcpdump mtr (0) | 2020.05.15 |
๋ชจ๋ API ์๋ํฌ์ธํธ์ ๊ณตํต ํ๋ผ๋ฏธํฐ๊ฐ ํ์ํ๋ค. (0) | 2020.04.30 |
์ด์งธ์ ์ํฐํฐ๊ฐ ๊ณ์ ์ ๋ฐ์ดํธ ๋๋๊ฐ.. (0) | 2019.06.28 |
๋๊ธ