페이스 북, gmail은 실시간 알림을 어떻게 보내나요?


269

이 주제에 대한 게시물을 읽었으며 답변은 혜성, 역 아약스, http 스트리밍, 서버 푸시 등입니다.

Gmail에서 수신 메일 알림은 어떻게 작동합니까?

Gmail 채팅은 어떻게 클라이언트 상호 작용없이 AJAX 요청을 할 수 있습니까?

매우 간단한 예제를 작성하기 위해 수행 할 수있는 코드 참조가 있는지 알고 싶습니다. 많은 게시물이나 웹 사이트가 기술에 대해 이야기합니다. 완전한 샘플 코드를 찾기는 어렵습니다. 또한 혜성을 구현하기 위해 많은 방법을 사용할 수있는 것 같습니다 (예 : Hidden IFrame, XMLHttpRequest). 제 생각에는 XMLHttpRequest를 사용하는 것이 더 좋습니다. 다른 방법의 장단점에 대해 어떻게 생각하십니까? Gmail은 어느 것을 사용합니까?

서버 측과 클라이언트 측 모두 에서이 작업을 수행해야한다는 것을 알고 있습니다. PHP 및 Javascript 샘플 코드가 있습니까?

답변:


428

페이스 북이하는 방식은 꽤 흥미 롭습니다.

이러한 알림을 수행하는 일반적인 방법은 주어진 간격 (아마도 몇 초마다)마다 서버에서 스크립트 (AJAX 사용)를 폴링하여 문제가 발생했는지 확인하는 것입니다. 그러나 이것은 네트워크 집약적 일 수 있으며 아무 일도 일어나지 않기 때문에 종종 무의미한 요청을합니다.

페이스 북이하는 방식은 한 폴링이 완료 되 자마자 다른 폴링을 발행하자마자 간격으로 폴링하는 대신 혜성 접근법을 사용하는 것입니다. 그러나 서버의 스크립트에 대한 각 요청은 시간이 매우 길며, 서버는 요청이 발생한 후에 만 ​​요청에 응답합니다. Facebook에있는 동안 Firebug의 콘솔 탭을 표시하고 스크립트에 대한 요청이 몇 분 정도 걸릴 수 있습니다. 이 방법은 요청 수와 전송 빈도를 즉시 줄이므로 매우 독창적입니다. 이제 서버가 이벤트를 '실행'할 수있는 이벤트 프레임 워크를 갖게되었습니다.

그 뒤에는 해당 설문 조사에서 반환 된 실제 내용과 관련하여 JSON 목록이며 이벤트 목록으로 보이는 내용과 관련 정보가 있습니다. 그래도 축소되었으므로 읽기가 약간 어렵습니다.

실제 기술 측면에서 AJAX는 요청 시간 초과 및 기타 여러 가지를 제어 할 수 있기 때문에 여기로가는 방법입니다. jQuery를 사용하여 AJAX를 수행하는 것이 좋습니다 (Stack overflow cliche here), 많은 호환성 문제가 사라질 것입니다. PHP와 관련하여 PHP 스크립트에서 이벤트 로그 데이터베이스 테이블을 간단히 폴링하고 어떤 일이 발생했을 때만 클라이언트로 돌아갈 수 있습니까? 나는 이것을 구현하는 많은 방법이 있다고 생각합니다.

구현 :

서버 측:

PHP에는 혜성 라이브러리가 몇 가지 구현되어 있지만 솔직히 말하면 다음과 같은 의사 코드와 같이 매우 간단합니다.

while(!has_event_happened()) {
   sleep(5);
}

echo json_encode(get_events());
  • has_event_happened 함수는 이벤트 테이블이나 무언가에 무슨 일이 있었는지 확인한 다음 get_events 함수는 테이블의 새 행 목록을 반환합니까? 실제로 문제의 상황에 따라 다릅니다.

  • PHP 최대 실행 시간을 변경하는 것을 잊지 마십시오. 그렇지 않으면 조기 시간 초과됩니다!

고객 입장에서:

Comet 상호 작용을 수행하기위한 jQuery 플러그인을 살펴보십시오.

즉, 플러그인은 약간의 복잡성을 추가하는 것처럼 보이며 클라이언트에서 매우 간단합니다 (jQuery 사용).

function doPoll() {
   $.get("events.php", {}, function(result) {
      $.each(result.events, function(event) { //iterate over the events
          //do something with your event
      });
      doPoll(); 
      //this effectively causes the poll to run again as
      //soon as the response comes back
   }, 'json'); 
}

$(document).ready(function() {
    $.ajaxSetup({
       timeout: 1000*60//set a global AJAX timeout of a minute
    });
    doPoll(); // do the first poll
});

모든 것은 기존 아키텍처가 어떻게 구성되는지에 달려 있습니다.


2
매우 훌륭하고 자세한 설명입니다. 감사합니다. 그것을 구현하는 많은 방법 중 하나에 대한 샘플 코드가 있습니까?
Billy

45
나는 잘 확장되지 않는 언어 / 플랫폼으로 PHP를 레이블링하는 것이 반드시 사실이라고 생각하지 않습니다. 매우 큰 규모의 시스템을 개발하는 데 사용할 수 있습니다. 페이스 북을보세요. 개발자가 올바르게 수행하면 확장되지 않고 확장되지 않습니다. 특정 웹 플랫폼을 사용한다고해서 확장 성이 보장되는 것은 아닙니다. 아, 그리고 질문은 PHP를 요구했습니다.
Alistair Evans

5
@Kazar : "Facebook은 PHP를 사용합니다"는 약간 오해의 소지가 있습니다. PHP가 제대로 작동하지 않아 PHP를 C ++로 변환하는 목적으로 HipHop을 개발했습니다.
cHao

14
@ cHao : 이것은 공정한 요점이지만,이 답변은 2009 년 페이스 북이 힙합을 사용하기 전에 작성되었습니다. 당시 페이스 북은 여전히 ​​자체 PHP를 사용하는 매우 큰 규모의 시스템이었습니다.
Alistair Evans

6
따라서이 기술은 서버를 일정한 스트레스 상태로 유지하는 연결을 지속적으로 열어 두는 것입니다. 일반적인 웹 서버의 일반적인 동시 연결 수는 약 200 명이지만 동시에 온라인 상태 인 Facebook 사용자의 수는 훨씬 더 큽니다. 그들은 어떻게합니까?
Paul

43

최신 정보

이에 대한지지를 계속 받으면서이 답변이 4 살이라는 것을 기억하는 것이 합리적이라고 생각합니다. 웹은 정말 ​​빠른 속도로 성장 했으므로이 답변에 유의하십시오.


나는 최근에 같은 문제가 있었고 그 주제에 대해 연구했습니다.

제공된 솔루션을 롱 폴링이라고하며,이를 올바르게 사용하려면 AJAX 요청에 "대형"시간 초과가 있는지 확인하고 현재 종료 (시간 초과, 오류 또는 성공) 후에 항상이 요청을 작성해야합니다.

긴 폴링-클라이언트

여기서는 코드를 짧게 유지하기 위해 jQuery를 사용합니다.

function pollTask() { 

    $.ajax({

        url: '/api/Polling',
        async: true,            // by default, it's async, but...
        dataType: 'json',       // or the dataType you are working with
        timeout: 10000,          // IMPORTANT! this is a 10 seconds timeout
        cache: false

    }).done(function (eventList) {  

       // Handle your data here
       var data;
       for (var eventName in eventList) {

            data = eventList[eventName];
            dispatcher.handle(eventName, data); // handle the `eventName` with `data`

       }

    }).always(pollTask);

}

( jQuery docs에서 ) 를 기억하는 것이 중요합니다 .

jQuery 1.4.x 이하에서 XMLHttpRequest 객체는 요청 시간이 초과되면 유효하지 않은 상태가됩니다. 객체 멤버에 액세스하면 예외가 발생할 수 있습니다. Firefox 3.0 이상에서만 시간 초과로 스크립트 및 JSONP 요청을 취소 할 수 없습니다. 시간 종료 기간이 지난 후에도 스크립트가 실행됩니다.

긴 폴링-서버

특정 언어는 아니지만 다음과 같습니다.

function handleRequest () {  

     while (!anythingHappened() || hasTimedOut()) { sleep(2); }

     return events();

} 

여기에서 hasTimedOut코드가 영원히 기다리지 않도록 anythingHappened하고 이벤트가 발생했는지 확인합니다. 는 sleep아무 일도없는 동안 다른 물건을 할 스레드를 해제하는 것입니다. 은 eventsJSON 형식 (또는 원하는 다른 형식)으로 이벤트 사전 (또는 원하는 다른 데이터 구조)을 반환합니다.

확실히 문제를 해결하지만 연구 할 때와 같이 확장 성과 성능이 걱정된다면 내가 찾은 또 다른 해결책을 고려할 수 있습니다.

해결책

소켓을 사용하십시오!

클라이언트 측에서 호환성 문제를 피하려면 socket.io를 사용 하십시오 . 소켓을 직접 사용하려고 시도하고 소켓을 사용할 수 없을 때 다른 솔루션으로 대체합니다.

서버 측에서 NodeJS를 사용하여 서버를 작성 하십시오 (예 :) . 클라이언트는 서버로 작성된이 채널 (관찰자)을 구독합니다. 알림을 보내야 할 때마다이 채널에 게시되고 아래 첨자 (클라이언트)에게 알립니다.

이 솔루션이 마음에 들지 않으면 APE ( Ajax Push Engine )를 사용해보십시오 .

도움이 되었기를 바랍니다.


1이 다른 것을 대체한다고 생각합니까, 아니면 같은 프로젝트에서 두 기술이 모두 필요하십니까?
tq

APE 및 NodeJS를 의미하는 경우 이들 중 하나를 선택할 수 있습니다. 주기적 AJAX 요청과 내가 제안한 것을 의미하는 경우 소켓 지원이 없으면 내 솔루션이 ajax 요청으로 대체 될 수 있습니다 (socket.io 문서 참조). 두 경우 모두 하나의 솔루션 만 필요합니다.
Walter Macambira

월터, 내 사이트 중 하나에서 귀하의 제안을 사용하고 싶습니다. 소켓 서버를 어디서 구할 수 있는지 알고 있습니까? 감사!
Progo

1
당신은 그것을 구현할 수 있습니다. 노드는 정말 간단합니다.
Walter Macambira

감지하는 방법 hasTimedOut()?
Mobasher Fasihy

18

Facebook의 메시징 시스템에 대한 슬라이드 쇼에 따르면 Facebook은 혜성 기술을 사용하여 웹 브라우저에 메시지를 "밀어 넣습니다". Facebook의 혜성 서버는 오픈 소스 Erlang 웹 서버 mochiweb에 구축됩니다.

아래 그림에서 "채널 클러스터"라는 용어는 "경쟁 서버"를 의미합니다.

시스템 개요

다른 많은 대형 웹 사이트는 회사마다 필요한 차이가 있기 때문에 자체 혜성 서버를 구축합니다. 그러나 오픈 소스 혜성 서버에 자신 만의 혜성 서버를 구축하는 것이 좋습니다.

당신이 시도 할 수 icomet , libevent와 내장 C1000K C ++ 혜성 서버를. icomet은 JavaScript 라이브러리도 제공하므로 다음과 같이 간단하게 사용할 수 있습니다.

var comet = new iComet({
    sign_url: 'http://' + app_host + '/sign?obj=' + obj,
    sub_url: 'http://' + icomet_host + '/sub',
    callback: function(msg){
        // on server push
        alert(msg.content);
    }
});

icomet은 Safari (iOS, Mac), IE (Windows), Firefox, Chrome 등 광범위한 브라우저 및 OS를 지원합니다.


이 이미지는 시나리오를 잘 설명합니다. 실제 사례를 제시하면 좋을 것입니다. 예를 들어 사람이 친구와 채팅 창을 열거 나 시작하면 어떻게됩니까? 페이스 북이 어떻게이 특정 대화에 맞추고 메시지를 양쪽 끝으로 밀어 넣습니까? (그냥 추측 : 응용 프로그램이 소켓을 열고 클라이언트 주소를 바인딩 한 다음 상자에 메시지가 쓰여질 때마다 계속 듣고 쓰기 만한다고 상상할 수 있습니다)
edam

5

Facebook은 HTTP 대신 MQTT를 사용합니다. 폴링보다 푸시가 더 좋습니다. HTTP를 통해 서버를 지속적으로 폴링해야하지만 MQTT 서버를 통해 메시지를 클라이언트에 푸시합니다.

MQTT와 HTTP 비교 : http://www.youtube.com/watch?v=-KNPXPmx88E

참고 : 내 대답은 모바일 장치에 가장 적합합니다.


3
또한 Google은 Android 용 GCM 서비스를 사용하며 개발자가 푸시 메시지 서비스를 구현하는 데 사용할 수 있습니다. developer.android.com/google/gcm/index.html 답변이 유용한 경우 수락하십시오.
abhi

5

긴 폴링의 중요한 문제 중 하나는 오류 처리입니다. 두 가지 유형의 오류가 있습니다.

  1. 요청이 시간 초과 될 수 있으며이 경우 클라이언트는 즉시 연결을 다시 설정해야합니다. 메시지가 도착하지 않았을 때 긴 폴링에서 발생하는 정상적인 이벤트입니다.

  2. 네트워크 오류 또는 실행 오류 이것은 클라이언트가 서버를 다시 온라인 상태로 올바로 수락하고 기다려야하는 실제 오류입니다.

주요 문제는 오류 처리기가 유형 2 오류에 대해서도 즉시 연결을 다시 설정하면 클라이언트가 서버를 DOS한다는 것입니다.

코드 샘플이있는 두 대답은 이것을 놓칩니다.

function longPoll() { 
        var shouldDelay = false;

        $.ajax({
            url: 'poll.php',
            async: true,            // by default, it's async, but...
            dataType: 'json',       // or the dataType you are working with
            timeout: 10000,          // IMPORTANT! this is a 10 seconds timeout
            cache: false

        }).done(function (data, textStatus, jqXHR) {
             // do something with data...

        }).fail(function (jqXHR, textStatus, errorThrown ) {
            shouldDelay = textStatus !== "timeout";

        }).always(function() {
            // in case of network error. throttle otherwise we DOS ourselves. If it was a timeout, its normal operation. go again.
            var delay = shouldDelay ? 10000: 0;
            window.setTimeout(longPoll, delay);
        });
}
longPoll(); //fire first handler
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.