D2CampusFest / 3rd

27 stars 4 forks source link

[Trevi] Asynchronous I/O #25

Open tommy-th opened 8 years ago

tommy-th commented 8 years ago

프로젝트 주소 : https://github.com/Yoseob/Trevi

현재 저희가 개발하고 있는 웹 어플리케이션 서버는 non-blocking I/O model로 이를 비동기로 처리하였습니다. 이러한 비동기 동작을 위해 Swift에서 제공하는 GCD를 사용하였습니다. (https://github.com/apple/swift-corelibs-libdispatch) 프로젝트가 GCD에 종속되는 것을 방지하고, 좀 더 효율적인 동작을 위해 현재 GCD를 사용하지 않고 비동기 동작을 구현하려고 합니다. 하지만 비동기 소켓에 대해 제가 배울 수 있는 자료가 너무 없어서 혹시 이에 대해 잘 알고 계시는 분이 있다면 접근 방향이나 참고 자료에 대해 조언을 구합니다. 또한 커널영역에서 사용자가 호출한 system call이 종료시점을 어떻게 감지하여 사용자에게 알려주는지와 시스템에서 처리방식이 multiplexing과 비교하여 어떻게 다른지 궁금합니다. (현재 타겟 OS는 OS X 와 Ubuntu 14.04, 15.10 입니다.)

kbu1564 commented 8 years ago

@JangTaeHwan "커널영역에서 사용자가 호출한 system call이 종료시점을 어떻게 감지하여 사용자에게 알려주는지와 시스템에서 처리방식이 multiplexing과 비교하여 어떻게 다른지 궁금합니다." 해당 부분이 무엇을 말씀하시고자 하는지 내용이 조금 부족한 것 같습니다.

조금만 더 자세히 적어 주실 수 있으신 가요? 질문 내용이 흥미있어 하는 분야라 관심이 가네요. :)

tommy-th commented 8 years ago

예를들어 multiplexing에서 select와 poll같은 경우 시스템에서 사용자가 등록한 File desctiptor들을 순차적으로 루프를 돌면서 readable / writable한지를 판단하여 어플리케이션에 알려주는 것으로 알고 있습니다. 그리고 multiplexing 방법은 사용자 영역에서는 blocking을 방지할 수 있지만 시스템 영역에서는 blocking이 발생한다고 알고 있습니다. 이와 반대로 비동기 방식에서는 어떻게 사용자가 등록한 File descriptor들의 readable / writable 한지를 판단하는지와 시스템에서 blocking 방지하는지 혹은 방지한다면 어떻게 방지하는지에 대해 알고 싶습니다.

jafffy commented 8 years ago

제가 검색해본 결과, linux에서는 POSIX aio, Windows에선 IOCP를 쓰는 것이 답인 것 같네요.

image <Figure 1. Simplified matrix of basic Linux I/O models>

위 matrix는 http://www.ibm.com/developerworks/linux/library/l-async/ 링크에서 가져왔습니다. IOCP에 대한 내용은 : http://tinyclouds.org/iocp-links.html 에서 봤습니다.

저도 검색만 해보고 던지는 무책임한(?) 댓글이긴 한데, 이걸 시작으로 파보시면 원하시는 답이 나올 것 같네요.

혹시 더 알게 되시면 저도 알려주세요:)

jafffy commented 8 years ago

https://en.wikipedia.org/wiki/Epoll

epoll 이라는 것도 있더군요. 참고하시면 좋을 것 같네요.

kbu1564 commented 8 years ago

@JangTaeHwan 예전 2.26? 2.4? 그 이전 버전이였던 것으로 기억을 합니다. 정말 옛날 버전의 커널에는 Polling 방식만을 지원하였기에, 윈도우 처럼 네트워크 관련 이벤트에 대한 비동기 IO 요청의 결과값을 콜백 함수로 받을 것인지 등을 설정하는 것과 다르게 관리 중인 소켓을 모두 한번씩 훓어야 하는 문제점이 있었습니다. 그래서 비효율적이라 말도 나왔었고, 정말 한참 옛날에는 c10k_problem 이라 해서 단일 머신의 서버로 동접자수 10k 명을 버티도록 하는 문제에 대한 논의도 kldp에서 오가고 그랬었습니다.

하지만 커널버전이 업데이트 되어감에 따라 커널 컨트리뷰터 분들께서 Epoll이라는 방식을 제안하고 채택받아 커널의 메인 버전에 포함되어 지게되었습니다. 현재 저희가 작성중인 리눅스 서버 또한 EPOLL방식에 쓰레드풀을 이용한 멀티스레드 방식을 설계 중에 있습니다.

EPOLL방식은 기존에 이벤트 발생 감지를 위해 모든 소켓을 다 일일히 검사해야하는 문제점을 보안하고자 Event가 발생한 소켓만을 따로 그룹화(FD_SET) 시켜줌으로써 풀링 방식에 비교해야하는 소켓의 검사 개수를 줄여주는 식으로 동작하게 됩니다.

돌아다니다 보니 커널의 POLL과 EPOLL의 성능 비교글이 존재하여 링크를 포함시켜 봅니다. 참고 : http://www.xmailserver.org/linux-patches/nio-improve.html img_0075

jafffy commented 8 years ago

찾아보니 epoll은 O(1) 으로 동작하는군요. ㄷㄷ하네요. http://kovyrin.net/2006/04/13/epoll-asynchronous-network-programming/

tyburn117 commented 8 years ago

링크를 보고 이해한 GCD는 swift에서 이벤트 기반으로 어떠한 작업을 이루어 질 수 있게 해주는거 같던데 (성공, 실패시에 따라 각자 함수를 실행) 제가 정확하게 이해하고 있는 것인지 모르겠고, swift 프로그래밍 경험이 없어 무책임하게 들리겠지만.. 이해한 것이 맞다는 가정하에 제가 아는 한 답변을 해보겠습니다.

GCD종속을 피하는것이 큰 목적이라면 직접 Event-queue를 만들어 처리하는 방법도 있을 것 같아요. 이것저것 발생할 수 있는 경우를 다 고려하면 결국 GCD처럼 만들어 질 것 같지만.. 그리고

관련된 자료를 찾다가 이런것을 찾았습니다 — swift에 관련된 멋진 frameworks : https://github.com/Wolg/awesome-swift — 위 사이트에 찾은 것

GCD를 대체할 것을 찾으신다면 위를 참고하시면 될 것 같아요.

tyburn117 commented 8 years ago

그리고 이슈에 관련되지 않은 질문인데, Trevi에서도 혹시 JS의 Promise을 지원하는 가요? 예를 들어, 프로그래밍을 하다보면 어쩔 수 없이 여러번 Async 함수를 호출해야 할 때가 있는데, 3개의 Async함수를 호출 해야 하고, 3개의 함수의 성공을 모두 보장받아야 할 경우 3개의 함수를 각각 Success함수에 중첩으로 넣으면서 해결할 수 있지만 이건 앞에 함수가 성공되어야 그 다음 함수를 호출할 수 있는 성능적 이슈 문제가 생깁니다. 그래서 JS같은 경우 Promise라고 함수가 3개 모두 거의 동시에 호출하고(날리고), 3개의 함수가 모두 성공 되면 다음 루틴을 실행 할 수 있도록 하는 장치가 마련되어 있는 것으로 알고 있습니다. 개인적인 생각으론 Trevi도 JS의 Promise개념을 넣으면 좋을 것 같아요!

tommy-th commented 8 years ago

정말 많은 분들이 도움을 주셔서 감사합니다. 알려주신 자료들 많은 도움이 될 것같고 저도 이를 토대로 다시 찾아보려 합니다. 그리고 Promise는 제가 처음 들어서 먼저 한 번 알아보도록 하겠습니다.