오늘 우리 서비스중이던 프로세스의 모든 스레드가 행이 걸리는 문제가 발생 했었어.


release 빌드된 바이너리가 리모트 장비에서 도는 상황에서 발생한 문제라,


스택 덤프 뜨고 분석하는데 까지 사이시간동안 회사 선임하고 문제 원인이 뭘까 논의를 했었는데,


일단 둘다 IOCP 내부 구현 코드를 본적은 없고 듣고 읽은 내용이 전부라 막 소설을 쓰고 있었어.


근데 의외의 논쟁거리가 하나 생겼는데, 아래와 같은 내용이야.



해당 시점까지 수집된 미량 정보 : 통신용 스레드 풀 내의 모든 스레드가 행이 걸린 상태. recv용 코드 근처 어딘가에 문제가 있다.



가설 : 연결되어있던 클라이언트 중, TCP 패킷을 일정량 보내겠다고 약속 한 후,

버그 혹은 고의로 패킷을 보내지 않아 서버측의 스레드가 recv 대기에 계속해서 물려있는 상태가 아닐까?



주장 1. IOCP는 코드 작성자에게, 절대적인 비동기 환경을 제공한다. 


Queued 된 데이터는 이미 해당 프로세스에 소속된 메모리에 복사가 완료된 상태다.


해당 프로세스에 소속된 그 어떤 스레드도 receive/send를 위해 대기를 하지 않는다.

(단, 접속과 데이터 recv 시작을 위한 대기는 있을 수 있다.)


실제 NIC buffer로부터 user buffer까지의 복사 과정은 OS가 수행한다.


OS가 수행했다는 의미는, OS에 소켓처리를 위한 별도의 스레드가 존재한다는 말과 동치이며,


결국 하고싶은 말은, IOCP를 사용 할 경우, 프로세스 소속으로 표기되는 그 어떤 스레드도 recv 상황 중 행이 걸릴 수 없다는 말이다.




주장 2. 앞선 주장의 대부분 내용에 동의 하지만, 


특정 프로세스를 위해 커널레이어에 스레드가 생겼다 없어졌다 한다는 부분이 납득이 되지 않는다.


CreateIoCompletionPort initialize 과정에서 생성되는 thread들이 io 수행 주체가 되지 않을까 싶다.


CreateIoCompletionPort initialize 과정에서 생성되는 thread는 해당 프로세스 소속이다.


스택 트레이스에서 발견된 스레드의 상태는 IOCP로부터 비롯될 가능성이 있다.




위와같이 두가지 소설로 논쟁이 붙었는데,



뭐 결국 덤프 확인해보니, 사용한 라이브러리에 포함되어 있던 lock부분이 문제였고.. 라이브러리 버전 업그레이드로 허무하게 문제가 종결됨..


근데 앞에서 여러가지로 소설을 썼던 내용이, 아무래도 궁금한거지...




앞선 설명이 좀 길어서, 간단히 다시 요약을 좀 해보면,


IOCP의 개념이 어떻게 되었건 간에, NIC 버퍼에서 유저 프로세스 버퍼로 데이터를 옮기는 행위를 하는 주체가 있을거잖아?


이 주체가 결과적으로 스레드일까? 그리고 이 스레드는 특정 프로세스 소속 스레드일까? 아니면 OS 커널에서 관리하는 스레드일까?


이런게 좀 알고싶어져서..


그리고 추가로, TCP 클라이언트가 장난을 치고있는 상황에서

(예를들어 three way handshake중에 ACK/SIN 패킷만 안보낸다던가, 앞에서 잠깐 언급한것처럼 1300바이트 보낼께 해놓고 250바이트만 보내고 나머지 바이트는 고의로 전송을 하지 않는다던가)


스레드가 행이 걸린다고 하면, 이 행걸린 스레드는 해당 프로세스 소속일까? 아니면 OS 소속 스레드일까?


아는사람 있는가?