멀티쓰레드 네트워크 프로그램에서 쓰레드간 통신용 queue 상태와 네트워크 이벤트를 동시에 모니터링 하는 방법?
하하.. 제목이 좀 뭐하군요.
제목만 갖고는 상황이 이해가 안가시죠? ^^;;
상황은 이렇습니다.
제가 만들고 있는 프로그램은 멀티 쓰레드 기반 네트워크 서버입니다.
epoll을 이용해서 네트워크를 모니터링하다가 요청이 들어오면 이를 파싱해서 작업할 쓰레드로 이를 넘김니다.
그럼 worker 쓰레드가 이 요청을 받아서 작업을 하고, 완료되면 다시 네트워크 처리 쓰레드로 응답을 넘겨주게 되는 것이지요.
네트워크 쓰레도와 worker 쓰레드간 요청과 응답을 넘겨주는 방법은, queue를 사용하는데요. 흔히 하는 방식대로 queue에 push, pop하는데, 쓰레드간 안정성을 위해 queue에는 내부적으로 pthread의 mutex가 들어가 있고요. pop 하는 측에서는 push가 되면 그 즉시 처리하기 위해 pthread의 condition을 이용해서 push됐음을 알려주는 구조입니다. (일반적으로 쓰이는 멀티쓰레드용 queue의 구조입니다.)
근데 문제는 이것입니다. 네트워크 모니터링 쓰레드는 네트워크 이벤트를 체크하기 위해 epoll을 이용해서 epoll_wait 상태이기 때문에 쓰레드간 연결된 queue에 worker 쓰레드에 의해 응답이 push되더라도 이 사실을 감지 할 수 없다는 것이지요.
그렇다고, 네트워크 상태와 queue 상태를 non-blocking으로 무한 loop을 돌며 상태를 체크하는 방식은 비효율적이므로 이 방법을 사용하는 것은 좀 거시기 합니다.
다른 방법으로, 무한 loop 사이에 짧은 sleep 을 주면 되지 않겠냐고 생각할 수도 있지만, 제가 작성한 프로그램은 client입장에서 응답 속도가 0.1ms 미만이여야 하기 때문에 sleep을 이용하는 것도 문제가 있습니다.
네트워크 상태와 쓰레드간 통신을 위한 queue를 동시에 모니터링 할 수 있는 방법이 있나요?
보통 어떻게 구현하나요? queue 대신에 pipe를 사용해 볼까 생각도 해봤는데, pipe는 한번에 기록할 수 있는 사이즈도 작은 편인듯 하고, 커널 영역으로 복사가 이루어지기 때문에 성능에도 별로 좋지 않을 듯 하다는 생각이 드네요.
중도적으로, 기본 queue 구조에 pipe의 fd를 이용한 이벤트 알림을 이용해 볼까 생각도 해봤습니다. (아마 다른 좋은 대안이 없다면 이 방법으로 구현 할 듯 하네요.)
고수님들의 훌륭한 답변이 무척 기다려 집니다. 저 좀 도와줘세요~
제생각엔,소켓은
제생각엔,
소켓은 읽기와 쓰기간은 상호 비동기이므로 각각 별개로 처리해 보는게 어떨까요.
즉, 리턴큐로부터 데이터를 읽어 소켓 FD 에 쓰는 쓰레드를 별도로 두는것이죠.
마찬가지로 상태변수를 이용해 쓰레드를 깨우고.
추가로, worker 쓰레드는 pooling 개념으로 여러개를 두어 관리하는것이 어떨련지.
1. reading
sock fd -> read data from thread1 -> push request queue -> worker thread
2. writing
worker thread -> push response queue -> read data from thread2 -> write fd
위의 구조에서 가령
위의 구조에서
가령 fd 3에서 요청이 들어와서 worker thread가 작업중일때, fd 3의 접속가 종료되고, 새로운 접속이 fd 3을 갖게 되면, worker thread가 작업을 완료 한 후, write thread가 보내지 말아야할 응답을 새로운 fd 3으로 보내는 문제가 있습니다.
이 문제를 어떻게 회피 할 까요?
writer 쓰레드를
writer 쓰레드를 별도로 운영하는 경우에 socket 관리를 단순히 socket descriptor로만 하지 않고, 별도 자료 구조를 만들어서 관리하면 되지 않을까요? 그래서 reader <-> worker <-> writer 사이에 전달되는 socket identifier는 별도 자료 구조의 index를 넘겨주는 겁니다. 물론 reader와 write가 이 자료 구조에 접근할때는 mutex로 동기화를 시켜야 하구요.
======================
BLOG : http://superkkt.com
======================
BLOG : http://superkkt.com
저도 SaNha님 말씀처럼
저도 SaNha님 말씀처럼 reader 1개, writer 1개, worker 2~4개로 비슷한 시스템을 개발한적이 있습니다. 그런데 이런 형태로 하는 경우에 socket I/O의 예외처리는 어떻게 하시나요?
block socket을 사용한다면 reader/writer와 peer 사이의 연결에 문제가 생기는 경우 전체 worker가 block되는 문제가 발생할 가능성이 있을테고요. non-block socket을 사용한다면 위 문제는 해결할 수 있지만 추가적인 buffer도 필요하고 여러모로 구현이 복잡해질테구요.
저는 이런 경우 예상 client의 수가 많지 않으면 일정을 핑계로 worker가 socket을 직접 처리하도록 하고 있습니다만.. 항상 고민되는 부분입니다.
다른 분들은 이런 경우 어떻게 하시는지요?
-PS-
ssehoony님, 질문 내용과 좀 동떨어진 댓글 같아서 죄송합니다.
======================
BLOG : http://superkkt.com
======================
BLOG : http://superkkt.com
댓글 달기