Connection reset by peer 에러에 의해 소켓이 끊길 때

5,649 views
Skip to first unread message

Sunghyuk Gong

unread,
Jan 11, 2018, 8:08:47 AM1/11/18
to Netty Korean User Group
안녕하세요? vertx의 sockjs를 이용해 실시간 스트리밍 서버를 만들어보는 도중 궁금증이 있어 질문 올리게 되었습니다.
다름아니라 스트림 하는 데이터가 꽤 많은 상황에서 connection reset by peer 에러가 발생하면 vertx의 NetSocketImpl에서는 큐에 쌓인 것들을 차례로 write, flush 하고 후속처리를 하는것으로 보입니다.
그런데 이 경우 이미 끊긴 소켓을 향해 flush 하느라 대략 아래와 같은 메세지가 수만에서 수십만개 정도가 떨어지는것 같습니다(아마 큐에 쌓인 메세지 개수 혹은 크기에 따라 다른것 같습니다).
아래 stack trace를 따라가보면 NioEventLoop으로 전달된 flush 명령의 작동과정인것 같은데.. vertx로 wrapping된 소켓단에서는 제어할 수 있는 부분이 없어보였습니다.
혹시 제가 상황 파악을 제대로 한 것이 맞을까요? 만약 그렇지 않다면 이게 어떤 상황인것인지.. 혹 해결방법이 있을지 궁금합니다.

2018-01-11 09:10:25.865 ERROR 19082 --- [vert.x-eventloop-thread-3] io.vertx.core.net.impl.ConnectionBase    : java.io.IOException: 연결이 상대편에 의해 끊어짐
2018-01-11 09:10:25.865 ERROR 19082 --- [vert.x-eventloop-thread-3] c.d.s.r.publisher.front.VerticleImpl    : SockJsSocket(172.51.2.195:57369) ExceptionHandler : 연결이 상대편에 의해 끊어짐

java.io.IOException: 연결이 상대편에 의해 끊어짐
        at sun.nio.ch.FileDispatcherImpl.writev0(Native Method)
        at sun.nio.ch.SocketDispatcher.writev(SocketDispatcher.java:51)
        at sun.nio.ch.IOUtil.write(IOUtil.java:148)
        at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:504)
        at io.netty.channel.socket.nio.NioSocketChannel.doWrite(NioSocketChannel.java:433)
        at io.netty.channel.AbstractChannel$AbstractUnsafe.flush0(AbstractChannel.java:875)
        at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.forceFlush(AbstractNioChannel.java:368)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:639)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459)
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
        at java.lang.Thread.run(Thread.java:748)


읽어주셔서 감사합니다!

Trustin Lee (trustin)

unread,
Jan 11, 2018, 8:18:42 AM1/11/18
to nett...@googlegroups.com, Netty Korean User Group
> 다름아니라 스트림 하는 데이터가 꽤 많은 상황에서 connection reset by peer 에러가 발생하면 vertx의 NetSocketImpl에서는 큐에 쌓인 것들을 차례로 write, flush 하고 후속처리를 하는것으로 보입니다. 그런데 이 경우 이미 끊긴 소켓을 향해 flush 하느라 대략 아래와 같은 메세지가 수만에서 수십만개 정도가 떨어지는것 같습니다(아마 큐에 쌓인 메세지 개수 혹은 크기에 따라 다른것 같습니다).
아래 stack trace를 따라가보면 NioEventLoop으로 전달된 flush 명령의 작동과정인것 같은데.. vertx로 wrapping된 소켓단에서는 제어할 수 있는 부분이 없어보였습니다.

이 경우, vert.x에서는 큐에 쌓인 것들을 네티 채널에 write 하는 것이 아니라 바로 실패시켜야 하는 것이 아닐런지요?

물론 네티에서도 소켓의 상태를 추적하고 마지막에 발생했던 예외 객체를 재사용한다거나나 하여 즉시 실패시킨다거나 하는 식으로 불필요한 시스템 콜이나 IOException의 instantiation을 줄일 수 있겠습니다만 그러한 최적화는 vert.x 나 Armeria 등의 좀 더 높은 추상 레벨에서 이루어지는 쪽이 좋지 않을까 생각합니다. (로우 레벨에 가까운 프레임워크로서 추상화의 구멍이 적은 쪽이 좋다고 생각하므로)

유저 어플리케이션 레벨에서라면 스트림할 때 버퍼에 쌓아 두는 write의 수를 줄이고, 각 write의 크기를 늘린다거나 하는 식으로 우회하는 방법이 있겠습니다. 예: 16바이트씩 1만번 쓰던 것은 1만 바이트씩 16번 써서 예외가 1만번 발생하던 것을 16번으로 줄이기

이희승 드림
--
이 메일은 Google 그룹스 'Netty Korean User Group' 그룹에 가입한 분들에게 전송되는 메시지입니다.
이 그룹에서 탈퇴하고 더 이상 이메일을 받지 않으려면 netty-ko+u...@googlegroups.com에 이메일을 보내세요.
웹에서 이 토론을 보려면 https://groups.google.com/d/msgid/netty-ko/46c57130-52d4-44c5-82b8-416ea16a2dfe%40googlegroups.com을(를) 방문하세요.
더 많은 옵션을 보려면 https://groups.google.com/d/optout을(를) 방문하세요.

Sunghyuk Gong

unread,
Jan 11, 2018, 8:31:16 PM1/11/18
to Netty Korean User Group
답변 감사합니다. 제 생각에도 vert.x에서 제어하는 쪽이 맞다고 생각해 vert.x의 google groups에 질문을 올려두었습니다. 그것이 의도된 동작이라면 제가 구현 방법을 바꿔야 하는 것이겠지요..
말씀해주신 버퍼 크기를 조절하는 방법도 시도해보아야겠네요. 
조언 감사합니다!

2018년 1월 11일 목요일 오후 10시 18분 42초 UTC+9, 이희승 (Trustin Lee) 님의 말:
Reply all
Reply to author
Forward
0 new messages