iocp reordering 문제

3권에서 새로 도입된 네트웍 및 멀티플레이어 프로그로그래밍 섹션을 위한 게시판입니다.

Moderator: 류광

Locked
비회원

iocp reordering 문제

Post by 비회원 »

iocp 패킷 수신 완료에 대한 의문점이 있습니다.
수신 버퍼를 10개 정도 생성하고 worker thread 4개 생성했을 경우

WSARecv 에 대한 데이터 복사는 순서 보장을 받는 것으로 알고 있습니다.
그러나 완료에 대한 순서는 보장 받지 않는다고 들었습니다.
(http://blog.naver.com/goldenwf?Redirect ... 0046343964)

그런데, windows7 에서 수신 순서 테스트를 해보니 iocp 큐에 넣은 순서와 완료 순서가
동일하게 나오는 것입니다. (초당 5mb, 30분 테스트)
정말 수신 완료 순서에 대한 보장을 받지 못하는지. os 따라 다른 것인지 궁금합니다.

보장 받지 못한다면 reorder 문제에 대해 깔끔하게 처리할 수 있는 방법 조언 부탁드립니다.
늦은 밤인데 잠을 이룰 수가 없네요.
비회원

Post by 비회원 »

이른 아침이네요. mw2하느라 밤샘을...

os에 따라 다른게 아니고 io completion port는 윈도우 밖에 없습니다.
mono나 sscli와 같은 애들은 그냥 async로 에뮬레이션하는 거구요.

어떻게 테스트하셨는지 모르겠으나, 예전에 제가 해당 작업을 했을 때
C10K 테스트를 했을 때 많은 부분이 인덱스 대로 완료가 안되더라구요.

윈도우7은 내부처리가 좋아진걸까요.

제가 할때는 일단 완료 루틴 데이터에 시퀀스를 넣고 완료되면 이 데이터를
리스트나 배열같은 목록에 넣어 두었다가 시퀀스의 인덱스를 조사해서 이
순서가 맞다면 읽기나 쓰기가 성공했다고 판단했습니다. 순서가 다르면
맞는 순서의 데이터가 완료될때까지 목록에 넣어두고 나중에 다른게 완료
되면 판정했구요. 어쨋튼 완료 순서는 보장안하지만 처리한 것은
io오류가 나지 않는한은 다 올테니까요.

웹서핑도 이걸로 끝내고, 게임으로 지친 몸 조깅이나 다녀와야겠네요.
비회원

Post by 비회원 »

완료의 순서가 바뀌는 일은 없습니다...

tcp는 stream입니다...
zupet
Posts: 2764
Joined: 2003-05-13 03:34
Location: NCSOFT LE팀

Re: iocp reordering 문제

Post by zupet »

비회원 wrote:보장 받지 못한다면 reorder 문제에 대해 깔끔하게 처리할 수 있는 방법 조언 부탁드립니다.
늦은 밤인데 잠을 이룰 수가 없네요.
수신 버퍼 구조체에 변수를 하나 만들어서 recv 순번에 따른 값을 넣어주면 어떨까요? 소켓당 시리얼을 하나씩 만들면 서버가 죽을때까지 다 쓸일은 없을테고 완료를 받은다음 이 번호를 보고 빈 번호가 있으면 잠시 큐에 넣어뒀다 다음 완료가 오면 합치는 방식을 쓰면 될 것 같습니다.
비회원

네... 감사합니다.

Post by 비회원 »

iocp 수신 완료 순서에 대해선 보장 받지 못하는게 맞는 것 같습니다.
제가 테스트를 허술하게 한 것 같군요.
버퍼 하나만 썼을 경우는 당연히 보장 받겠지만 여러개를 사용했을 경우는 안되는 것 같습니다.
몇몇 분들 조언대로 한번 구현해 봐야겠습니다. 답변주신 분들 감사합니다.

아래는 microsoft iocp echo server 예제 코멘트입니다.
해당 예제에서 조차 수신 완료 순서 보장이 안된다는 말이 나옵니다.

// The important thing to remember with IOCP is that the completion events
// may occur out of order; however, the buffers are guaranteed to be filled
// in the order posted. For our echo server this can cause problems as
// receive N+1 may complete before receive N. We can't echo back N+1 before
// echoing N. There are two approaches possible. First, we could surmise
// that since receive N+1 has completed then we can safely echo back receive
// N and N+1 at that time (to maintain the data ordering). To do this properly
// you'll have to call WSAGetOverlappedResult on receive N in order to find
// out how many bytes were received to echo it back. The second approach
// (which is implemented in this sample) is to keep a list of receive
// buffers that completed out of order. This list is maintained in the
// per-socket data structure. When receive N+1 completes, it will notice that
// receive N has not completed. The buffer is then queued in the out of
// order send list. Once receive N completes, its buffer is queued -- the
// queue is ordered in the same order that the receive operations are.
// Another routine (DoSends) goes through this list and sends those buffers
// that are available and in order. If any gaps are detected no further buffers
// are sent (as we will wait for that receive to complete and insert its
// buffer into the list so that the next call to DoSends will correctly
// send the buffers in the right order).
chadr
Posts: 980
Joined: 2003-06-01 12:28
Location: 모대학
Contact:

Post by chadr »

비회원 wrote:완료의 순서가 바뀌는 일은 없습니다...

tcp는 stream입니다...
여기서는 iopc에 대해서 이야기를 하는 것이지 tcp에 대해서 이야기 하는것은 아닙니다.
iocp를 udp에서도 쓸수 있습니다.
비회원

Post by 비회원 »

iocp라는 자체가 tcp를 활용하게 되면 버퍼에 recv순서대로 들어오는데
완료가 순서가 바뀐다? 있을 수가 없는 일이지요...

iocp가 완료통지를 순서대로 안해주는게 아니고
스레드 컨택스트 스위칭등의 이유로 리턴을 늦게 하는 것일 겁니다.

그래서 1번 , 2번쓰레드 랜덤으로 리턴되어서 '순서가 틀려서 온 것 처럼' 되니
Packet의 순서가 중요하시면 수신요청은 WorkerThread 맨 밑에 한번씩만 하세요.
(순서가 중요하지 않아도 이 방법이 진리입니다.)
zupet
Posts: 2764
Joined: 2003-05-13 03:34
Location: NCSOFT LE팀

Post by zupet »

비회원 wrote:그래서 1번 , 2번쓰레드 랜덤으로 리턴되어서 '순서가 틀려서 온 것 처럼' 되니
Packet의 순서가 중요하시면 수신요청은 WorkerThread 맨 밑에 한번씩만 하세요.
(순서가 중요하지 않아도 이 방법이 진리입니다.)
직접 해보진 않았지만 WSARecv() 를 중복 호출하는 것이 받기 성능향상에 도움이 된다는 얘기를 서버하시는 분에게 들었습니다. 물론 처리가 어렵다는 얘기도 덧붙여 주었는데 중복 WSARecv() 호출이 Gbps 에서는 확실히 차이가 난다고 하네요. 혹시 직접 실험해보신분 계신가요?
비회원

Post by 비회원 »

네 단순히 tcp 스택만 따지고 본다면 완료 순서는 논할 여지가 없습니다.
iocp 에서 다중버퍼를 사용할 때 수신 통보 순서가 보장 되지 않는다고 질문드린 겁니다.
그래서 1번 , 2번쓰레드 랜덤으로 리턴되어서 '순서가 틀려서 온 것 처럼' 되니
Packet의 순서가 중요하시면 수신요청은 WorkerThread 맨 밑에 한번씩만 하세요.
(순서가 중요하지 않아도 이 방법이 진리입니다.)
컨텍스트 스위칭 때문에 통보 순서가 보장되지 않는다는 의견에 매우 동감합니다.
그런데 수신 요청을 workerthread 맨 밑에 한번씩만 하는 것으로 순서 보장을 받을 수 있나요?
잘 이해가 안가는데... 부연 설명 부탁드립니다.
현재는 별도 수신큐를 만들어서 순서를 맞추어 나가는 방식으로 구현 진행중입니다.
비회원

Post by 비회원 »

WSARecv는 접속할때 한번, worker thread 제일 밑에 한번이죠...
그러므로 worker thread 제일 밑에 WSARecv가 호출되지 않는다면?
패킷은 안받으며 GQCS 통지도 안받습니다...

GQCS와 WSARecv사이에 처리시간은 워커와 로직쓰레드도 분리합니다..
물론 처리시간이 빠르고 별다른게 없으면 워커쓰레드에서 다 해도 됩니다.

알아서 소켓별로 직렬화가 되죠... 따로 수신 정렬이라든지 할필요 없습니다.
속도도 충분히 빠릅니다.


그리고 다중 버퍼의 경우 그냥 형식대로 받기위해 버퍼를 여러개의 버퍼를 합쳐서 쓰는 정도의 차이? 라고
알고 있습니다. 흠... 써본적이 없어서 잘 모르겠네요...
chadr
Posts: 980
Joined: 2003-06-01 12:28
Location: 모대학
Contact:

Post by chadr »

iocp는 기본적으로 많은 입출력 요청을 뿌려놓은 다음에 여러스레드에서 경쟁하여 통보가 가능한 스레드가 먼저 통보를 해달라고 하는 방식입니다. 물론 유저메모리 공간을 직접제공하여 중복적인 데이터 복사가 적에 일어나는 장점도 있지만 이건 논외로 합시다.

iocp를 사용하기 위해서 GQCS를 호출하게 됩니다. 그런데 여기서 입출력 순서를 보장하지 않는다는건 GQCS에서는 소켓 핸들을 넘겨서 해당 소켓의 입출력이 완료ㅤㄷㅚㅆ는지 보는게 아니라 완료된 데이터가 있으면 그것의 메모리 주소를 넘겨주게 되어있습니다. 서버에서는 이 데이터가 어떤 소켓에서 완료가 되었는지 알아야만 하므로 완료된 데이터에 소켓 핸들과 같은 것을 같이 넣어서 통보받게 됩니다.

이때 순서를 보장 못한다는 것입니다. 소켓으로 가는 것은 당연히 직렬화 됩니다. 받는것도 마찬가지입니다. 보낸 순으로 보내고 받는 순으로 받습니다.

단지 한개의 랜카드로 같은 시간에 동시에 다른 목적지로 데이터가 갈수 없으며 tcp의 내부 구현에 따라 흐름제어가 발생할 때 흐름제어로 인해 전송이 일시적으로 불가능한 소켓이 있으면 이를 제외하고 다른 소켓으로 먼저 데이터를 전송후 완료 통지를 주기 때문에 GQCS를 호출했을때 여러 소켓으로 순서대로 데이터 전송요청을 해도 순서대로 통보가 오지 않는다는 말입니다.

또한 만약에 recv의 경우를 보자면 iocp내부 스레드에서는 1번, 2번 2개의 recv요청을 완료하였습니다. 그리고 각각의 유저 스레드에서 GQCS를 호출 한 후 recv를 호출한 순서와 같게 전송 완료 통지를 받았습니다. 그런데 받은 데이터로 뭔가를 처리 하기 전에 스레드가 스위칭 되버렸습니다. 원래는 1번, 2번 데이터를 순서대로 GQCS에서 잘 통보 받았지만 스위칭으로 인해 처리 순서는 2번 ,1번이 되버렸습니다. 이렇게 되면 곤란하게 되는 것입니다. 보내는거야 그냥 보낸거 통보 받고 버퍼를 지워주면 되지만 받는건 순서가 매우 중요하므로 처리가 어렵다는 것입니다. 물론 GQCS를 호출하기 전과 데이터 처리 후를 동기화 객체로 보호한다면 될겁니다. 하지만 이러면 iocp를 쓰는 이유가 없어지지요.. 이렇게 굳이 하자면 요청 순서대로 번호를 매겨서 직접 ordering을 해줘야합니다. 이게 동기화 객체보다 비용이 쌉니다.

recv시에는 이런점이 문제기 됩니다.

통보 순서가 보장되지 않는다는 말은 이렇게 이해하시면 되구요..

같은 소켓으로 데이터를 보내고 받는건 이미 알고 계신 tcp 지식과 마찬가지로 순서는 보장됩니다.

recv도 send와 같이 요청개수를 많이 해놓으면 성능상 매우 이득입니다. 랜카드에서는 데이터가 쭉쭉 들어오는데 recv하나만 해놓고 스위칭하느라 시간 잡아먹고 받은데이터 처리하느라 시간 잡아먹는 동안 랜카드로 들어오는 데이터를 못가져가면 tcp에서 흐름제어가 발생하고 그만큼 랜카드는 놀게 됩니다. 랜카드도 일종의 작은 컴퓨터입니다. 따라서 좋은 랜카드는 cpu의 간섭을 적게 받고 스스로 데이터 전송을 할 수 잇습니다. 3d에서 그래픽카드를 쉬지 못하게 혹사하는 것 같이 서버에서도 랜카드를 쉬지 못하게 계속 일을 시켜야만 서버의 성능이 올라가게 됩니다.

정리하자면..

iocp에서 순서가 보장되지 않는 다는 말은 여러개의 목적지(소켓)으로 데이터를 전송 할 때 1,2,3,4 번 소켓으로 순서대로 데이터를 전송한다고 해서 GQCS 호출시 1,2,3,4번 소켓 순으로 완료 통지가 안온다는 말입니다. 하지만 같은 소켓으로 전송하는건 순서가 보장됩니다.(송수신 다 마찬가지입니다.) 단 수신시 문제가 되는 것은 GQCS 호출 직후 스위칭이 발생하면 데이터가 꼬이게 되고 이를 방지하기 위해서 동기화객체로 감싸면 iocp를 사용하는 이유가 없어지게 됩니다. 따라서 ordering을 하기 위해서는 번호를 매기는게 낫습니다.
비회원

Post by 비회원 »

chadr wrote: recv도 send와 같이 요청개수를 많이 해놓으면 성능상 매우 이득입니다. 랜카드에서는 데이터가 쭉쭉 들어오는데 recv하나만 해놓고 스위칭하느라 시간 잡아먹고 받은데이터 처리하느라 시간 잡아먹는 동안 랜카드로 들어오는 데이터를 못가져가면 tcp에서 흐름제어가 발생하고 그만큼 랜카드는 놀게 됩니다. 랜카드도 일종의 작은 컴퓨터입니다. 따라서 좋은 랜카드는 cpu의 간섭을 적게 받고 스스로 데이터 전송을 할 수 잇습니다. 3d에서 그래픽카드를 쉬지 못하게 혹사하는 것 같이 서버에서도 랜카드를 쉬지 못하게 계속 일을 시켜야만 서버의 성능이 올라가게 됩니다.
처리시간은 이미 다년간의 노하우로 해결된지 오래입니다...

그리고 특히 게임서버는 특히 전송량이 많지 않은데 구지 WSARecv를 여러개 걸 이유가 있는지요...?
비회원

Post by 비회원 »

패킷량이 적은 모델에서는 싱글 버퍼로 사용하면 이런 머리아픈 문제는 없을 것 같습니다.
단, 비디오 스트리밍 또는 릴레이 기능을 하는 Gigabit 서버 환경을 고려해 볼 때
다중 버퍼는 시도해 볼만 하고 성능상 좀 더 유리하지 않을까 생각합니다.
chadr
Posts: 980
Joined: 2003-06-01 12:28
Location: 모대학
Contact:

Post by chadr »

비회원 wrote:
chadr wrote: recv도 send와 같이 요청개수를 많이 해놓으면 성능상 매우 이득입니다. 랜카드에서는 데이터가 쭉쭉 들어오는데 recv하나만 해놓고 스위칭하느라 시간 잡아먹고 받은데이터 처리하느라 시간 잡아먹는 동안 랜카드로 들어오는 데이터를 못가져가면 tcp에서 흐름제어가 발생하고 그만큼 랜카드는 놀게 됩니다. 랜카드도 일종의 작은 컴퓨터입니다. 따라서 좋은 랜카드는 cpu의 간섭을 적게 받고 스스로 데이터 전송을 할 수 잇습니다. 3d에서 그래픽카드를 쉬지 못하게 혹사하는 것 같이 서버에서도 랜카드를 쉬지 못하게 계속 일을 시켜야만 서버의 성능이 올라가게 됩니다.
처리시간은 이미 다년간의 노하우로 해결된지 오래입니다...

그리고 특히 게임서버는 특히 전송량이 많지 않은데 구지 WSARecv를 여러개 걸 이유가 있는지요...?
처리 시간을 단축은 되겠지만 물리적인 시간이 0이 되는건 아닙니다. 처리 시간이 신경 쓰지 않을정도로
줄어들었다면 굳이 머리아프게 IOCP로 구현할 필요도 없습니다. 유닉스 계열에서는 fork쓰면 안정성도 올라가고
구현도 쉽습니다. 그리고 윈도우에서도 그냥 select나 event select 쓰면 더 간편합니다.

물론 당연히 여러개를 걸 필요가 없는 곳에서는 안거는게 구현도 쉽고 더 좋습니다.(위에 말씀드린대로 순서를 매겨줘야하는게 부담이라면 부담이지요.)
저는 게임서버에 국한되지 않는 좀더 일반적인 이야기를 했습니다. 전송량이 많은 곳에서는 써주는게 더 좋지요.

하지만 비싼 돈 주고 회선을 대여 했는데 가능한 많이 뽑아 써줘야지 금전적으로 이득입니다.
어차피 trade off 관계이므로 적절한 곳에서 적절하게 사용해주면 그게 맞지 않겠습니까?:)
Locked