1.Env:
- os: CentOS Linux выпуск 7.6.1810 (Core)
- веб-сервер: undertow v2.0.20.Final
- springBootVersion: 2.1.5.RELEASE
- java процесс обслуживания: oss
# undertow config:
server:
undertow:
io-threads: 4
worker-threads: 32
buffer-size: 16384
direct-buffers: true
2.Как возникла проблема, двусторонняя
- Продолжайте запрашивать разные ресурсы, такие как изображения или видео
- Многократно запрашивать один ресурс (без запроса кеша)
3. Производительность, связанная с проблемой:
при возникновении проблемы , jstack как это:
"XNIO-1 task-32" #69 prio=5 os_prio=0 tid=0x0000000001c8e800 nid=0x1e10 runnable [0x00007f0a20dc1000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.PollArrayWrapper.poll0(Native Method)
at sun.nio.ch.PollArrayWrapper.poll(PollArrayWrapper.java:115)
at sun.nio.ch.PollSelectorImpl.doSelect(PollSelectorImpl.java:87)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
- locked <0x00000006cf91e858> (a sun.nio.ch.Util$3)
- locked <0x00000006cf91e848> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000006cf91e5f0> (a sun.nio.ch.PollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:101)
at org.xnio.nio.SelectorUtils.await(SelectorUtils.java:46)
at org.xnio.nio.NioSocketConduit.awaitWritable(NioSocketConduit.java:263)
at org.xnio.conduits.AbstractSinkConduit.awaitWritable(AbstractSinkConduit.java:66)
at io.undertow.conduits.ChunkedStreamSinkConduit.awaitWritable(ChunkedStreamSinkConduit.java:379)
at org.xnio.conduits.ConduitStreamSinkChannel.awaitWritable(ConduitStreamSinkChannel.java:134)
at io.undertow.channels.DetachableStreamSinkChannel.awaitWritable(DetachableStreamSinkChannel.java:87)
at io.undertow.server.HttpServerExchange$WriteDispatchChannel.awaitWritable(HttpServerExchange.java:2039)
at io.undertow.servlet.spec.ServletOutputStreamImpl.writeBufferBlocking(ServletOutputStreamImpl.java:577)
at io.undertow.servlet.spec.ServletOutputStreamImpl.write(ServletOutputStreamImpl.java:150)
at org.springframework.security.web.util.OnCommittedResponseWrapper$SaveContextServletOutputStream.write(OnCommittedResponseWrapper.java:639)
at org.springframework.util.StreamUtils.copy(StreamUtils.java:143)
at com.berry.oss.service.impl.ObjectServiceImpl.handlerResponse(ObjectServiceImpl.java:732)
at com.berry.oss.service.impl.ObjectServiceImpl.getObject(ObjectServiceImpl.java:336)
at com.berry.oss.service.impl.ObjectServiceImpl$$FastClassBySpringCGLIB$$6c092705.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684)
at com.berry.oss.service.impl.ObjectServiceImpl$$EnhancerBySpringCGLIB$$1b34ff28.getObject(<generated>)
at com.berry.oss.api.ObjectController.getObject(ObjectController.java:165)
at com.berry.oss.api.ObjectController$$FastClassBySpringCGLIB$$bbd00513.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88)
at com.berry.oss.aop.StatisticsAspect.getObjectStatistics(StatisticsAspect.java:39)
at sun.reflect.GeneratedMethodAccessor108.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
...
netstat как это:
[root@localhost backend]# netstat -nalt |grep 8077
tcp6 0 0 :::8077 :::* LISTEN
tcp6 1 174696 192.168.2.195:8077 172.16.1.10:49588 CLOSE_WAIT
tcp6 1 188280 192.168.2.195:8077 172.16.1.10:49576 CLOSE_WAIT
tcp6 1 235768 192.168.2.195:8077 172.16.1.10:49544 CLOSE_WAIT
tcp6 1 213280 192.168.2.195:8077 172.16.1.10:44406 CLOSE_WAIT
tcp6 1 184320 192.168.2.195:8077 172.16.1.10:49560 CLOSE_WAIT
tcp6 1 192752 192.168.2.195:8077 172.16.1.10:49562 CLOSE_WAIT
tcp6 1 201440 192.168.2.195:8077 172.16.1.10:46424 CLOSE_WAIT
tcp6 1 144840 192.168.2.195:8077 172.16.1.10:46426 CLOSE_WAIT
tcp6 1 189432 192.168.2.195:8077 172.16.1.10:46576 CLOSE_WAIT
tcp6 1 290664 192.168.2.195:8077 172.16.1.10:49556 CLOSE_WAIT
tcp6 1 212472 192.168.2.195:8077 172.16.1.10:49558 CLOSE_WAIT
tcp6 1 248416 192.168.2.195:8077 172.16.1.10:44410 CLOSE_WAIT
tcp6 1 202464 192.168.2.195:8077 172.16.1.10:49582 CLOSE_WAIT
tcp6 1 235512 192.168.2.195:8077 172.16.1.10:44374 CLOSE_WAIT
tcp6 1 268432 192.168.2.195:8077 172.16.1.10:49568 CLOSE_WAIT
tcp6 1 214984 192.168.2.195:8077 172.16.1.10:49532 CLOSE_WAIT
tcp6 1 299904 192.168.2.195:8077 172.16.1.10:49552 CLOSE_WAIT
tcp6 1 310040 192.168.2.195:8077 172.16.1.10:49566 CLOSE_WAIT
tcp6 1 333080 192.168.2.195:8077 172.16.1.10:49540 CLOSE_WAIT
tcp6 1 213536 192.168.2.195:8077 172.16.1.10:44380 CLOSE_WAIT
tcp6 1 339000 192.168.2.195:8077 172.16.1.10:49584 CLOSE_WAIT
tcp6 1 289768 192.168.2.195:8077 172.16.1.10:49546 CLOSE_WAIT
tcp6 1 315280 192.168.2.195:8077 172.16.1.10:49538 CLOSE_WAIT
tcp6 1 398752 192.168.2.195:8077 172.16.1.10:49530 CLOSE_WAIT
tcp6 1 243304 192.168.2.195:8077 172.16.1.10:49574 CLOSE_WAIT
tcp6 1 182616 192.168.2.195:8077 172.16.1.10:44414 CLOSE_WAIT
tcp6 1 326352 192.168.2.195:8077 172.16.1.10:49572 CLOSE_WAIT
tcp6 0 0 192.168.2.195:8077 172.16.1.10:49590 ESTABLISHED
tcp6 1 245776 192.168.2.195:8077 172.16.1.10:49580 CLOSE_WAIT
tcp6 1 267920 192.168.2.195:8077 172.16.1.10:44412 CLOSE_WAIT
tcp6 1 191432 192.168.2.195:8077 172.16.1.10:49550 CLOSE_WAIT
tcp6 1 229208 192.168.2.195:8077 172.16.1.10:44404 CLOSE_WAIT
tcp6 1 207360 192.168.2.195:8077 172.16.1.10:44408 CLOSE_WAIT
[root@localhost backend]# netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
CLOSE_WAIT 38
ESTABLISHED 101
FIN_WAIT2 1
TIME_WAIT 16
Многие соединения остаются в состоянии CLOSE_WAIT
, соединение CLOSE_WAIT
не будет освобождено, пока не будет выполнено активное уничтожение. ..
Я попытался
- Достигнут ли максимально допустимый размер кэша сокета? Я использую команду
cat /proc/sys/net/ipv4/tcp_wmem
, чтобы получить максимальное значение: 4194304 (4M), поскольку мы можем видеть, что значение Send-Q состояния соединения CLOSE_WAIT
никогда не достигает этого! - Почему netstat существует так много
CLOSE_WAIT
соединений где-то отдыхать забыл закрыть? Я проверил процесс Java (oss), нашел метод ключа ( код github ):
private void handlerResponse(String bucket, String objectPath, HttpServletResponse response, WebRequest request, ObjectInfo objectInfo, Boolean download) throws IOException {
ObjectResource object = null;
try {
if (download != null && download) {
object = dataService.getObject(bucket, objectInfo.getFileId());
if (object == null || object.getInputStream() == null) {
throw new XmlResponseException(new NotFound());
}
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
StreamUtils.copy(object.getInputStream(), response.getOutputStream());
response.flushBuffer();
return;
}
long lastModified = objectInfo.getUpdateTime().getTime();
String eTag = "\"" + DigestUtils.md5DigestAsHex(objectPath.getBytes()) + "\"";
if (request.checkNotModified(eTag, lastModified)) {
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
} else {
object = dataService.getObject(bucket, objectInfo.getFileId());
if (object == null) {
throw new XmlResponseException(new NotFound());
}
String contentType = StringUtils.getContentType(object.getFileName());
response.setContentType(contentType);
response.setHeader(HttpHeaders.ETAG, eTag);
ZonedDateTime expiresDate = ZonedDateTime.now().with(LocalTime.MAX);
String expires = expiresDate.format(DateTimeFormatter.RFC_1123_DATE_TIME);
response.setHeader(HttpHeaders.EXPIRES, expires);
StreamUtils.copy(object.getInputStream(), response.getOutputStream());
response.flushBuffer();
}
} catch (Exception e) {
logger.error("Exception catch, msg:{}", e.getMessage());
} finally {
if (object != null && object.getInputStream() != null) {
object.getInputStream().close();
}
response.getOutputStream().close();
}
}
подтверждается, что ресурс закрыт !!
Ошибка Undertow? Утечка соединения? Никогда не знаешь ....
Нужна твоя помощь
Мой код неверен? Как найти проблему?
Спасибо