NDC 참관기: 실시간 HTTP 양방향 통신

수요일(2012-04-25) 오후에 있었던 이승재 군의 발표.

발표 자료는 http://ricanet.com/new/view.php?id=blog/120425 에서.

HTTP Protocol의 한계

http는 request/response protocol이다. 이로 인해서 클라이언트 쪽의 이벤트는 서버 쪽에 쉽게 전달할 수 있지만, 서버 쪽의 이벤트는 클라이언트가 요청하기 전에는 전달할 수 없다.

그런데 현재의 웹 쪽 트렌드를 보자면, twitter나 facebook, google mail (or talk) 같은 경우 실시간으로 메시지를 보낸다. 어떻게 하는걸까?

이를 극복하기 위한 기법들

기본적으로 꼼수다. 프로토콜의 한계 때문에.

Polling

웹 브라우저에서 주기적으로 요청을 보낸다. (클라이언트 쪽 타이머 이용) 문제:

  • 트래픽이 많다 / 서버 쪽 부하가 걸린다
  • 지연 시간이 크다; 이벤트-클라이언트 요청 시간 차이 때문에. 그렇다고지연 시간을 줄이면 트래픽/서버 부하가 더 커진다.

Long-polling

클라이언트가 미리 요청을 보내고, 서버는 이벤트가 생기는 순간까지 기다렸다가 이를 모아서 (이미 온 요청에) 응답을 보낸다. Facebook 메신저 구현이 이를 이용한다. 문제:

  • 구현 복잡도. 서버가 요청이 이미 와 있는 경우와 그렇지 않은 경우를 구분해서 처리해야하는 등.
  • 지연 시간; 응답을 보낸 후 클라이언트가 다시 요청을 보내올 때까지의 시차.

Hidden iframe

페이지에 숨겨 놓은 iframe을 통해서 메시지를 계속 흘려 보낸다. (서버가 응답을 끝내지 않는다) 그래서 http streaming이라고 부르기도 한다. Gmail messenger(=google talk)에서 사용하는 방법이다.

문제:

  • 응답이 끝나지 않기 때문에 클라이언트 쪽 웹 브라우저에 메모리 릭이 생긴다.
  • 프록시 / 보안 프로그램이 응답이 완전히 끝나야만 이를 넘겨주는 경우가 있다.

Browser plugin

Flash, ActiveX 등을 이용. 사실 상 TCP 소켓처럼 쓸 수 있다. 호환성 문제가 너무 커서.

WebSocket (html5)

javascript 단에서 진짜 소켓을 쓸 수 있다. 표준화가 아직이라 (protocol은 결정되었지만, API가 아직 unstable). 기존 웹브라우저와의 호환성 문제.

WebIRC (=IRC web-bridge for smartphones) 만들기

Long-polling이 호환성이 좋고 (최소한 iOS, android를 지원해야 했음), 구현이 재밌어 보여서(…) 이를 구현함.

프로토콜

  • InitLog: 각 채널 최근 로그 k 줄을 요청
  • UpdateLog(last): 각 채널에서_내가 마지막으로 받은 로그 ID가 last_일 때 그 이후 로그를 요청

서버 구현 이슈

HTTP 핸들러가 새로운 내용이 없으면 대기하는 것. vs. Event listener가 새로운 내용이 왔을 때 대기 중인 스레드(의 요청)를 깨우는 것 사이의 레이스 컨디션. ((내 생각, 그리고 최치선 군의 의견을 조합하자면, 저건 pthread condvar 류의 동기화 도구를 사용하면 해결 될듯 함. 치선 군이 실 서비스에서 사용하고 있는 추천 구현체는 gevent의 Queue (monkey-patching하는).))

node.js 류를 사용하면 오히려 쉬웠을지도 모르지만 이미 python으로 구현.

Webserver Architecture

동시에 살아있는 연결이 많아서,

  • 커넥션 당 1 스레드 때문에 메모리 병목
  • 고전적인 웹 서버의 경우 더 중요한 페이지 뷰보다 동시 접속 수가 문제
  • Gevent로 쉽게 해결
  • Long-polling에 맞춰서 구현했더니 stateless 프로토콜이 되어 네트워크 단절에 강해졌다.
  • 채팅 보내는 것이 네트워크 불안정엔 약했음. 이걸 극복하려니 사실상 TCP 류의 프로토콜을 HTTP 위에 재구현하는 형태가 되어버리게 되서…

Middlewares

앞에서 언급한 방법들엔 정답이 없다. 각 방법의 장단점이 다름.

orbited2, socket.io 같은 미들웨어가 있다. 그렇지만 정작 제작 시점에 사용하려던 orbited 사이트가 내려가 있어서 long-polling을 직접 구현.

Orbited

orbited.js + application.js — orbited server — application server

위의 형태로 구성. Web-router + firewall의 역할. Legacy TCP 응용프로그램 서버인 경우에도 쉽게 통신할 수 있다.

socket.io

nopde.js 기반. 메시지 단위 전송을 지원한다.

확인해야 할 사항

  • 연결 당 서버 리소스 소모량
  • 연결이 불안정하면 어떻게 되는가?
  • 웹 브라우저를 껐다켜도 괜찮은가?

웹-게임 연동

이런 기술을 쓰면 웹 게임에서도 네트워크 제약(http 문제)이 *거의* 없어진다.

WoW 전정실, 아이온, 마비의 거래소, 넥슨 홈이나 스팀의 업적 시스템 구현이라거나, 게임 웹 채팅, 친구 게임 참여 알리기, 우편 도착 알림 등의 실시간 기능이 가능해질듯.

결론(?): 취미 프로젝트 좋아요.