netty(4.0.28) 대량의 전문을 전송하면 전송이 중간에 멈추는 현상이 발생합니다.

969 views
Skip to first unread message

필그림

unread,
Jun 19, 2015, 7:54:07 AM6/19/15
to nett...@googlegroups.com
안녕하세요. 필그림입니다.

100메가 파일은 적당한 크기로 잘라서 전문(전문크기는 4kbyte 정도됩니다.)을 생성한 후에
서버쪽으로 쉬지 않고 전송하면 서버쪽에서 어느 정도 받다고 데이터를 받지 못합니다.
서버쪽 문제인줄 알았는데 클라이언트에서 데이터를 보내지 못하는 현상이 발생합니다.

흥미로운게 클라이언트에서 데이터를 모두 보내게 되면
한방에 서버로 전송이 되어 처리가 된다는 것입니다.

참고로 클라이언트에서 ctx.writeAndFlush 메소드를 이용해서 전송하였습니다.
그리고 400k 보내고 간단한 더미 메세지 주고 받고 다시 400k 보내는 식으로 하면
이런 현상은 발생하지 않습니다.

flush 메소드를 호출하게 하기 위해
idleStateHandler를 이용하여 readIdleEvent를 발생시켜 ctx.flush() 메소드를 호출하게 했는데
readeridleEvent가 발생하지 않고 한방에 서버로 전송이 된 후에 확 발생하게 되어 의도되로 처리되지 않더군요.

현재로는 적당한 크기의 데이터를 보내고 잠시 쉬거나(eventloop 안에서 sleep 하는 것은 추천하지 않아서 약간 주저되지만요)
적당한 크기의 데이터를 write하고 이후 하나의 메세지는 writeFlush하는 식으로 한번 시도해 보려고도 합니다.

어떻게 처리하는 게 좋을지 경험이나 가이드 부탁 드립니다.
(현재로는 더미메세지를 주고받고는 할 수는 없는 상태이고 순전히 보내는 쪽에서 문제없이 보내도록 해야 하는 상황입니다.)
감사합니다.

이희승 (Trustin Lee)

unread,
Jun 19, 2015, 8:43:18 AM6/19/15
to nett...@googlegroups.com
안녕하세요.
 
자세한 구현을 봐야 알겠습니다만 클라이언트 측의 채널 핸들러의 메소드 내에서 끊임없이 전부 메시지를 보내고 계신가요? 그렇다면 write/writeAndFlush() 를 아무리 많이 하여도 핸들러에서 네티로 컨트롤이 넘어가지 않았기 때문에 큐에 쌓이기만 하고 실제 전송은 핸들러 메소드가 리턴된 후에 시작되게 됩니다.
 
그 경우가 아니라면 좀 더 자세히 알아야 어째서 그런 문제가 발생하는 지 알 수 있을 것 같습니다.
 
이희승 드림
 
--
이 메일은 Google 그룹스 'Netty Korean User Group' 그룹에 가입한 분들에게 전송되는 메시지입니다.
이 그룹에서 탈퇴하고 더 이상 이메일을 받지 않으려면 netty-ko+u...@googlegroups.com에 이메일을 보내세요.
더 많은 옵션을 보려면 https://groups.google.com/d/optout을(를) 방문하세요.
 

권석훈

unread,
Jun 19, 2015, 9:48:38 AM6/19/15
to nett...@googlegroups.com
안녕하세요. 희승님
말씀하신 대로 그런 경우라고 여겨집니다.

그럼 그런 경우에 네티로 컨트롤을 어떻게 넘겨야 하나요?

감사합니다.


2015년 6월 19일 오후 9:43, 이희승 (Trustin Lee) <t...@motd.kr>님이 작성:

이희승 (Trustin Lee)

unread,
Jun 19, 2015, 10:36:35 AM6/19/15
to nett...@googlegroups.com
그런 경우에는 보통 다음과 같이 합니다.
 
1. 핸들러 내에서 데이터를 쓸 때 isWritable() 을 확인합니다. isWritable() 은 쓰기 버퍼에 쌓인 데이터가 많아지면 false 를 리턴하고, 다시 줄어들면 true를 리턴합니다.
 
boolean wrote = false;
while(ch.isWritable()) {
    ctx.write(...);
    wrote = true;
}
if (wrote) {
    ctx.flush();
}
 
2. 핸들러의 channelWritabilityChanged() 에서 1 에서 멈췄던 쓰기를 계속합니다.
 
public void channelWritabilityChanged(ctx) {
    boolean wrote = false;
    while (ch.isWritable()) {
        ctx.write(...);
        wrote = true;
    }
    if (wrote) {
        ctx.flush();
    }
}
 
보시다시피 1과 2의 쓰기 로직이 동일하므로, 별도 메소드로 추출하여 재사용하시면 되겠습니다.
 
지금까지 설명한 작업을 다소 단순화하기 위해 ChunkedWriteHandler 와 ChunkedInput 이 제공되므로 적용 가능한 지 확인해 보시는 것도 좋겠습니다.

권석훈

unread,
Jun 19, 2015, 11:25:40 AM6/19/15
to nett...@googlegroups.com
감사합니다. 희승님.

질문이 있습니다.
 
1번 로직을 보면 보낼 수 있는 메세지갯수가 100개 라고 하면
2번 로직을 통해서 보낼 수 있는 것도 100개 정도가 될 듯 싶은데요...

더 많은 데이터를 쓰고 싶은데 어떻게 해야 할까요?
channelWritabilityChanged 메소드는 계속 recurrsive하게 호출이 되는 건가요?

writabilityChanged 이니까 그럴 듯 도 싶은데요...

ChunkedWriteHandler 와 ChunkedInput 은 얼핏 보았는데...
약간 복잡해 보여요.. T.T

좀더 살펴보기는 하겠습니다.

감사합니다.



2015년 6월 19일 오후 11:36, 이희승 (Trustin Lee) <t...@motd.kr>님이 작성:

이희승 (Trustin Lee)

unread,
Jun 19, 2015, 11:43:48 AM6/19/15
to nett...@googlegroups.com
isWritable() 이 false 를 리턴하게 되면 루프를 빠져나오게 되고 결과적으로는 제어권이 핸들러에서 네티로 넘어오게 됩니다. 이후 네티가 write() 요청을 처리하여 쌓여 있는 데이터의 양이 줄게 되면 네티가 channelWritabilityChanged() 를 호출하게 되고.. (데이터가 모두 소진될 때까지 반복)
 
엄밀히 말하면 재귀적인 것은 아니고 무한 반복되는 스테이트머신에 가깝겠습니다.

Sokhoon Kwon

unread,
Jun 19, 2015, 6:42:33 PM6/19/15
to nett...@googlegroups.com
감사합니다

필그림 드림

Outlook에서 보냄




권석훈

unread,
Jun 21, 2015, 3:29:51 AM6/21/15
to nett...@googlegroups.com


안녕하세요. 희승님
말씀해 주신 대로 해서 위 현상은 어떻게 극복할 지 알게 되었습니다.
처리하다보니 세가지 의문을 생겼습니다.

파일을 블록단위로(파일을 적당히 자른 걸 의미합니다.) 보낼 때 한블록을 또 적당한 크기로 전문을 생성해서 보내는데요.
이때  블록단위로 여러 전문을 한번에 전송을 합니다. 

첫번째 질문
아직 위와 같은 현상은 나타나지 않고 잘 처리됩니다. 만약에 블록의 크면 위 현상이 발생할 수도 있다고 생각이 됩니다.
이때 알려주신 방법으로 해결할 수도 있구요. 하지만 SO_SNDBUF 을 어느 정도 조정하면 위 현상이 발생하지 않고도
처리할 수 있지 않을까 생각하는데요. 
while(ctx.isWritable()) 이 루프를 빠져나오는 조건은 어떻게 되나요? 만약에 SO_SNDBUF 사이즈와 직접적인 
관련이 있다면 적당한 크기로 조정해도 위 문제를 해결할 수 있지 않을까 싶습니다.
(물론 파일 전체를 한방에 보낼 때는 적용할 수 없겠지만요.)


두번째로 
어느 정도 크기의  전문을 연속으로 보낼 때 전문은 write 로 전송하고 마지막에 Unpooled.EMPTY_BUFFER를 전송하는 식으로 하는게 좋은 습관인가요? (위의 현상이 발생하지 않은 상태에서요.)

세번째로
SO_SNDBUF 사이즈는 
linux에 설정된 /proc/sys/net/ipv4/tcp_wmem 값보다 커서는 안되는 거지요?

감사합니다.




2015년 6월 20일 오전 7:42, Sokhoon Kwon <lloy...@gmail.com>님이 작성:
Reply all
Reply to author
Forward
0 new messages