기존에 지속적인 갱신을 위해서 Polling이라고 불리는 일정 간격으로 서버에 요청을 보내서 바뀐 내용을 조회하는 방식을 많이 사용했지만 리얼타임수준으로 구현하려면 간격을 줄여야 하기 때문에 불필요한 요청이 많이 필요했고 실제 리얼타임이라고 하기도 어려웠습니다. 반면에 Comet은 Ajax Push라고도 알려져 있는데(최근에는 거의 Comet으로 통칭되는듯 합니다.) 특정 기술에 대한 이름이라기 보다는 HTTP상에서 Push를 하는 방식을 가리키는 의미로 사용됩니다.
세부구현은 다양하게 있지만 대표적으로는 Long Polling와 Streaming 방식이 있다고 할수 있습니다. 위 그림을 보면 쉽게 이해할 수 있는데 Polling이 요청을 보내면 응답을 바로 받는 대신에 Long Polling은 클라이언트가 요청을 보내면 서버에서 이벤트가 발생할 때까지(데이터가 갱신된다거나 하는 등) 응답을 하지 않고 가지고 있다고 이벤트가 발생하면 응답을 하고 클라이언트는 바로 다시 요청을 보내는 방식입니다. 스트리밍은 요청을 최초 한번 보내면 chunk데이터를 통해서 이벤트가 있을때마다 계속 클라이언트에 데이터를 보내줍니다.
일반적으로 서블릿 컨테이너는 요청당 쓰레드가 생기는 방식이기 때문에 위와같이 구현을 하면 서버가 클라이언트의 요청을 계속 유지하고 있기 때문에 서비스로 제공하기에 그리 적합하지는 않은 것으로 알고 있습니다. Play Framework는 Servlet을 사용하지 않고 있습니다. Play가 서블릿을 사용하지 않는 부분에 대해서는 Play의 창시자인 Guillaume Bort가 쓴 Why there is no servlets in Play과 Ike의 Can The Play Framework Play Nice With Others?에 좀 자세히 나와있습니다. Play가 Comet에 좀 더 적합한 아키텍쳐를 가지고 있는 지는 저도 파악중이라 따로 설명은 하지 않겠습니다.
Play-Push
Comet을 구현할 방법에 대해서 고민을 하다가 Leif Singer가 작성한 Play-Push라는 잘 된 데모를 찾게 되었고 굳이 따로 예제를 만들 필요가 없을듯 해서 그대로 사용하려고 합니다. Play-Push는 Elias Klughammer가 Cappuccino X Tornado라는 Tornado웹서버상에서 Cappuccino로 채팅애플리케이션을 만든 것을 보고 비슷하게 Play로 구현한 것입니다.
위 영상은 Cappuccino X Tornado의 영상이기는 하지만 Play-Push도 거의 동일하게 구현되어 있습니다.(배경화면을 공유하는 것만 현재 빠져있는것 같습니다.)
Play-Push에서 채팅서비스를 Long Polling을 사용해서 구현하였는데 해당 부분은 /app/controllers/Messages.java에 구현되어 있습니다.
public static void since(Long timestamp) {
List<Message> ms = Message.find("ts > ?", timestamp).fetch();
if ( ms.size() > 0 ) {
renderJSON(ms);
}
suspend(50);
}
위 소스가 Long Polling을 처리해 주는 부분입니다. timestamp(일반적으로 디비를 사용한다면 시퀀스아이디가 되겠죠)를 파라미터로 받아서 Message에 파라미터로 받은 timestamp보다 최신값이 있는지 검사하고 있으면 결과를 렌더링해서 리턴하고 없으면 suspend(50)을 실행하여 50밀리세컨드 후에 다시 실행하게 됩니다. 클라이언트로 보낼 데이터가 있을때까지 suspend를 이용해서 응답하지 않은 상태로 계속 반복해서 확인을 하는 구조입니다. 클라이언트 부분은 Cappuccino로 구현되어 있기 때문에 보기 어려우면 그리 어렵지 않습니다. Ajax로 서버측에 since를 호출하면서 파라미터로 timestamp를 넘겨주고 Ajax callback에서 결과를 돌려받은뒤 다시 Ajax 를 호출하는 방식으로 구현하기만 하면 됩니다.
이렇게 구현되면 Ajax요청이 발생하고 새로운 Message(혹은 새로운 데이터)가 생기기 전까지는 계속 기다리고 있는 상태가 되고 새로운 데이터가 생기면 바로(실제로는 50밀리세컨의 갭이 존재하지만 신경쓸정도는 아닌듯 합니다.) 클라이언트로 응답이 보내지고 클라이언트는 다시 새 Ajax요청을 보내고 응답을 기다리고 있는 상태가 됩니다. (HTTP 모니터링 툴을 보면 응답을 받은 뒤에 새 요청이 날라가고 계속 대기상태에 있는 것을 확인할 수 있습니다.)
play framework을 회사에서 사용하신건가요?? 아니면 개인적으로?? 궁금해서요.
개인적으로 사용해 본겁니다. 정확히는 아는 분들하고 Scala를 공부하면서 머 만들어보느라고 사용해 보았습니다. ㅎㅎ
안녕하세요. comet기술에 관해 검색을 하다 오게되었는데요 궁금한게 있어서 질문드립니다.
http://10bay.co.kr <- 옥션 사이트를 보면 현재 가격과 남은 시간이 실시간으로 변하는데요
이러한 효과를 구현하는 효과적인 사이트를 구현할면
현재나와 있는 기술중에 어떤게 좋은지 해서여
저가 알아본 comet기능이 들어간 공개 옥션으로는 2개가 잇는데요
http://www.ibm.com/developerworks/kr/library/tutorial/wa-aj-comet/section2.html
http://www.jarvana.com/jarvana/view/org/cometd/cometd-demo/1.1.1/cometd-demo-1.1.1.war!/auction/index.html
cometd라는 툴로 돌아가는 프로그램입니다. 주소는 아래와 같구요
http://www.cometd.org/
일단 말씀하신 10bay.co.kr은 코멧은 아닌 것으로 보이고 ajax polling을 매초마도 요청하는 방식으로 보입니다. 기존의 대부분 옥션들은 코멧보다는 폴링을 많이 쓰고 있던 것으로 알고 있습니다.
사실 폴링으로도 대부분의 니즈는 해결 가능하고 그 이상에 실시간에 대한 필요성이나 혹은 트래픽의 낭비를 줄이기 위해서 코멧을 사용할 수 있습니다. comet은 사실 특정기술이 아닌 많은 기술들의 셋이라고 할 수 있는데요. 하고자 하는 것은 다 비슷하기 때문에 그보다는 서버쪽 기술에 의존될듯 합니다. 클라이언트쪽의 부하를 서버쪽으로 가져온 것이기 때문에 롱풀링이든 푸쉬든 서버쪽에서 어느기술을 지원가능하고 또 부하를 감당해 낼수 있는가가 더 중요한 요소가 아닐까 싶습니다.