서버 프로그래밍

22 Dec 2013

design server

설계

동기화 수준과 성능(규모) 수준을 고려해서 작성한다.

  • 완전 비동기나 느슨한 비동기 수준으로 괜찮다면 웹 서버를 사용해도 좋다.
  • 실시간 비동기가 필요하면서 성능이 중요할 경우 직접 서버를 구현하는 편이 좋다.
  • morpg나 fps 정도의 서버라면 stmp(single thread multiple process) 구조로 가도 좋다.
  • mmorpg나 그 이상의 성능을 요구하는 서버라면 task parallelism 기반이면서 scaleable한 서버를 만드는 편이 좋지만 필요한 규모에 따라 적절한 수준으로 적용하면 된다.

결국 어떤 서버를 만들 것인지에 대한 기술 명세를 한 후 그에 맞는 설계/구현을 해야 한다는 것.

비동기

io와 비동기 개념을 공부한다.

  • 간단히 application은 io(file, network 등) 작업을 kernel에게 요청(request)하고, kernel은 해당 요청이 완료(completion)되면 application에게 알려준다.
  • 요청한 후 완료될 때까지 기다리면(blocking) 동기(sync) 작업이라고 하고, 요청해놓고 완료된 사실을 나중에 따로(poll, interrupt) 알게되면 비동기(async) 작업이라고 한다.
  • 여러 클라이언트와 동시에 통신해야 하는 서버를 구현한다고 하면 각 클라이언트와의 연결을 유지하면서 각각에 대한 io 작업(메시지 보내기/받기)를 수행해야 한다.
  • 이 때 io 작업을 동기적으로 처리하면 각 요청이 완료될 때까지 blocking되므로 동시에 여러 작업을 처리하기 위해서는 각각이 blocking되어도 문제 없도록 thread를 여러 개 만들거나, 비동기 io를 사용한다.

당연히 thread를 여러 개 만드는 것은 효율이 좋지 않으므로 효율을 고려한 서버를 구현할 경우에는 비동기 io를 사용한다.

언어

성능(throughput) 수준과 개인의 취향에 따라 사용할 언어를 적절히 선택해주면 된다.

  • javascript가 좋고 logic 부담이 적다면 nodejs는 좋은 선택이 될 것이다.
  • visual studio가 좋지만 c++이 싫다면 c#은 좋은 선택이 될 것이다.
  • 높은 수준의 성능이 요구된다면 c++도 좋은 선택이 될 것이다. 그리고 지옥을 보겠지

공부나 재미를 위한 상황이라면 그냥 본인의 취향에 맞게 선택하면 된다. 그렇지 않고 결과물을 위해서 언어를 선택해야 한다면 신중한 결정이 필요하다. 보통 io와 logic의 부담을 제대로 구별하지 못하고 과도한 최적화를 들먹이며 native를 고집하는 경우가 있는데 본인에게도, 미래의 본인에게도 별로 좋은 선택은 아니다. c++밖에 할 줄 아는 언어가 없어서라는 이유가 있기는 한데 그건 좀...

대부분의 도메인에서는 nodejs나 c# 정도면 충분히 문제를 해결할 수 있다. nodejs나 c# 모두 network library에 대한 기본 내장이 잘 되어 있으므로 약간의 기반 코드 작성 후 logic에 집중할 수 있다.

라이브러리

c++이나 java로 서버를 직접 작성하게 될 경우에는 기반 library를 사용하는 것이 좋다. 개인적으로 c++은 asio가 괜찮고 java는 netty가 괜찮다고 생각한다.

어느 정도 비동기 프로그래밍 패턴이 익숙하다면 예제 코드 좀 보면 어떻게 써먹을 수 있을 지 대충은 이해할 수 있다. 그리고 워낙 저 두 프로젝트는 문서화가 잘 되어 있으니 문서만 읽어도 대부분은 이해된다.

구조

구조는 event model과 queue model 정도로 구분이 가능하다.

  • event model은 메시지를 받은 즉시 처리해서 그 결과를 클라이언트에게 다시 알려주는 방식이고,
  • queue model은 받은 메시지를 queue에 쌓아두고, 서버에서 tick을 돌면서 queue에 있는 메시지를 꺼내 처리하고 그 결과를 클라이언트로 다시 알려주는 방식이다.
  • event model의 경우 stateless/tickless한 요청에 대한 처리를 할 때 유리하고,
  • queue model의 경우 tick 단위로 수행해야 하는 작업이 있을 때 유리하다.

여기서 유리하다는건 최적화가 하기가 좋다거나 코드 작성/유지보수가 쉽다는 소리다.

예를 들어 별로 크지 않은 게임 서버를 만든다면,

  • io thread 한 두어 개 돌려서 message 받아 message queue에 넣고
  • logic thread 한 개가 tick 돌면서 tick 작업도 처리하고 message queue에 들어온 메시지도 처리하는 구조가 될 것이다.

각 thread가 늘어날 때 공유 자원에 대한 동기화 문제도 잘 고민해주어야 한다.

정리

메시지가 뭐고, 소켓이 뭐고, 이것들이 어떻게 관리되고는 그냥 기초 네트워크 프로그래밍 책만 읽어도 잘 소개되어 있는 내용이기 때문에 책을 읽어보면 되겠다. 그 정도의 내용은 TCP/IP 네트워크 프로그래밍 정도에도 잘 나와 있다. poll이니 interrupt이니 이런 내용은 논리회로, ca, os, sysp에도 자주 등장하고, 동기/비동기는 pp/os/sysp에 등장한다. 고로 수업만 잘 들어도 대충 기반 개념을 다 배우는 셈.

뭐 그게 잘 안 되었다고 하더라도 인터넷에 잘 정리된 문서가 많고 여기 풀씨에도 관련 글이 많으니 진입하는데 별로 어려움은 없다. 다만 실질적으로 어떻게 코딩을 하느냐는 직접 해보면서 감을 잡는 것과 남이 작성하는 것을 읽고 공부하는 것인데, 전자는 그냥 해보면 되고, 후자의 경우 github에 널리고 널린게 서버 프로그램이니 그걸 보고 공부하면 된다.

comments powered by Disqus