Bagaimana cara facebook, gmail mengirim notifikasi waktu nyata?


269

Saya telah membaca beberapa posting tentang topik ini dan jawabannya adalah komet, membalikkan ajax, streaming http, server push, dll.

Bagaimana cara kerja notifikasi surat masuk di Gmail?

Bagaimana GMail Chat dapat membuat permintaan AJAX tanpa interaksi klien?

Saya ingin tahu apakah ada referensi kode yang dapat saya ikuti untuk menulis contoh yang sangat sederhana. Banyak posting atau situs web hanya berbicara tentang teknologi. Sulit untuk menemukan kode sampel yang lengkap. Selain itu, tampaknya banyak metode yang dapat digunakan untuk mengimplementasikan komet, mis. IFrame Tersembunyi, XMLHttpRequest. Menurut pendapat saya, menggunakan XMLHttpRequest adalah pilihan yang lebih baik. Apa pendapat Anda tentang pro dan kontra dari berbagai metode? Manakah yang digunakan Gmail?

Saya tahu itu perlu dilakukan baik di sisi server dan sisi klien. Apakah ada kode sampel PHP dan Javascript?

Jawaban:


428

Cara Facebook melakukan ini cukup menarik.

Metode umum untuk melakukan pemberitahuan semacam itu adalah dengan menyurvei skrip di server (menggunakan AJAX) pada interval tertentu (mungkin setiap beberapa detik), untuk memeriksa apakah sesuatu telah terjadi. Namun, ini bisa sangat intensif jaringan, dan Anda sering membuat permintaan yang tidak berguna, karena tidak ada yang terjadi.

Cara Facebook melakukannya menggunakan pendekatan komet, alih-alih polling pada suatu interval, begitu satu polling selesai, ia mengeluarkan yang lain. Namun, setiap permintaan ke skrip di server memiliki batas waktu yang sangat lama, dan server hanya menanggapi permintaan setelah sesuatu terjadi. Anda dapat melihat ini terjadi jika Anda membuka tab Firebug's Console saat berada di Facebook, dengan permintaan untuk skrip mungkin memerlukan waktu beberapa menit. Benar-benar cerdik, karena metode ini langsung mengurangi jumlah permintaan, dan seberapa sering Anda harus mengirimnya. Anda sekarang secara efektif memiliki kerangka acara yang memungkinkan server untuk 'memecat' acara.

Di balik ini, dalam hal konten aktual yang dikembalikan dari jajak pendapat itu, itu adalah respons JSON, dengan apa yang tampak sebagai daftar acara, dan info tentangnya. Ini diperkecil, jadi agak sulit dibaca.

Dalam hal teknologi aktual, AJAX adalah cara untuk pergi ke sini, karena Anda dapat mengontrol batas waktu permintaan, dan banyak hal lainnya. Saya akan merekomendasikan (Stack overflow klise di sini) menggunakan jQuery untuk melakukan AJAX, itu akan mengambil banyak masalah lintas-kompabilitas. Dalam hal PHP, Anda hanya bisa polling tabel database log peristiwa dalam skrip PHP Anda, dan hanya kembali ke klien ketika sesuatu terjadi? Saya berharap ada banyak cara untuk mengimplementasikan ini.

Menerapkan:

Sisi server:

Tampaknya ada beberapa implementasi pustaka komet di PHP, tetapi jujur ​​saja, itu sangat sederhana, sesuatu yang mungkin seperti kodesemu berikut:

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

echo json_encode(get_events());
  • Fungsi has_event_happened hanya akan memeriksa jika ada sesuatu yang terjadi di tabel acara atau sesuatu, dan kemudian fungsi get_events akan mengembalikan daftar baris baru di tabel? Tergantung pada konteks masalah sebenarnya.

  • Jangan lupa untuk mengubah waktu eksekusi PHP max Anda, jika tidak maka akan habis lebih awal!

Sisi klien:

Lihatlah plugin jQuery untuk melakukan interaksi Comet:

Yang mengatakan, plugin tampaknya menambah sedikit kompleksitas, sebenarnya sangat sederhana pada klien, mungkin (dengan jQuery) sesuatu seperti:

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
});

Semuanya sangat tergantung pada bagaimana arsitektur yang ada disatukan.


2
Ini penjelasan yang sangat bagus dan terperinci. Terima kasih. Apakah Anda memiliki kode sampel untuk salah satu dari banyak cara untuk mengimplementasikannya?
Billy

45
Saya pikir pelabelan PHP sebagai bahasa / platform yang tidak skala dengan baik belum tentu benar. Ini dapat digunakan untuk mengembangkan sistem skala yang sangat besar. Lihatlah facebook. Jika pengembang melakukannya dengan benar, maka itu akan skala, jika tidak, maka tidak akan. Menggunakan platform web tertentu bukan jaminan skalabilitas. Oh, dan juga, pertanyaannya memang menanyakan PHP.
Alistair Evans

5
@Kazar: "Facebook menggunakan PHP" agak menyesatkan - terakhir saya dengar, mereka mengembangkan HipHop untuk tujuan konversi PHP ke C ++, karena PHP tidak berkinerja cukup baik.
cao

14
@ cHao: Ini poin yang adil, namun jawaban ini ditulis pada tahun 2009, sebelum facebook mulai menggunakan hiphop. Pada saat itu facebook masih menggunakan sistem skala sangat besar menggunakan php itu sendiri.
Alistair Evans

6
Jadi tekniknya adalah menjaga koneksi tetap terbuka yang akan membuat server dalam tekanan konstan. Jumlah khas koneksi konkuren untuk server web rata-rata adalah sekitar 200, tetapi jumlah pengguna Facebook yang online secara bersamaan jauh lebih besar. Bagaimana mereka melakukannya?
Paul

43

Memperbarui

Ketika saya terus menerima upvotes tentang ini, saya pikir masuk akal untuk mengingat bahwa jawaban ini adalah 4 tahun. Web telah berkembang dengan sangat cepat, jadi harap perhatikan jawaban ini.


Saya memiliki masalah yang sama baru-baru ini dan meneliti tentang masalah ini.

Solusi yang diberikan disebut polling panjang, dan untuk menggunakannya dengan benar, Anda harus yakin bahwa permintaan AJAX Anda memiliki batas waktu "besar" dan untuk selalu membuat permintaan ini setelah akhir saat ini (batas waktu, kesalahan atau kesuksesan).

Polling Panjang - Klien

Di sini, untuk menjaga agar kode tetap pendek, saya akan menggunakan 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);

}

Penting untuk diingat bahwa (dari jQuery docs ):

Di jQuery 1.4.x dan di bawah ini, objek XMLHttpRequest akan berada dalam keadaan tidak valid jika permintaan habis; mengakses objek apa pun yang anggota dapat melemparkan pengecualian. Hanya di Firefox 3.0+, permintaan skrip dan JSONP tidak dapat dibatalkan dengan batas waktu; skrip akan berjalan bahkan jika itu tiba setelah periode waktu habis.

Polling Panjang - Server

Itu tidak dalam bahasa tertentu, tetapi akan menjadi sesuatu seperti ini:

function handleRequest () {  

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

     return events();

} 

Di sini, hasTimedOutakan memastikan kode Anda tidak menunggu selamanya, dan anythingHappened, akan memeriksa apakah ada peristiwa yang terjadi. The sleepadalah untuk melepaskan thread Anda untuk melakukan hal-hal lain sementara tidak ada yang terjadi. The eventsakan kembali kamus peristiwa (atau struktur data lainnya Anda dapat memilih) dalam format JSON (atau lainnya yang Anda suka).

Itu pasti memecahkan masalah, tetapi, jika Anda khawatir tentang skalabilitas dan kinerja seperti ketika saya meneliti, Anda mungkin mempertimbangkan solusi lain yang saya temukan.

Larutan

Gunakan soket!

Di sisi klien, untuk menghindari masalah kompatibilitas, gunakan socket.io . Mencoba menggunakan soket secara langsung, dan memiliki solusi fallbacks untuk solusi lain ketika soket tidak tersedia.

Di sisi server, buat server menggunakan NodeJS (contoh di sini ). Klien akan berlangganan saluran ini (pengamat) yang dibuat dengan server. Setiap kali pemberitahuan harus dikirim, itu diterbitkan di saluran ini dan pelanggan (klien) akan diberi tahu.

Jika Anda tidak menyukai solusi ini, coba APE ( Ajax Push Engine ).

Semoga saya bisa membantu.


apakah menurut Anda 1 adalah pengganti yang lain atau apakah perlu kedua teknologi pada proyek yang sama?
tq

Jika maksud Anda APE dan NodeJS, Anda dapat memilih salah satunya. jika Anda maksud permintaan AJAX berkala dan yang saya sarankan, solusi saya dapat mundur ke ajax ketika tidak memiliki dukungan socket (lihat socket.io docs). Dalam kedua kasus, Anda hanya perlu satu solusi.
Walter Macambira

Hai Walter, saya ingin menggunakan saran Anda di salah satu situs saya. Apakah Anda tahu di mana saya bisa mendapatkan server Sockets? Terima kasih!
Progo

1
Anda bisa menerapkannya. Node membuatnya sangat sederhana.
Walter Macambira

Bagaimana cara mendeteksi hasTimedOut()?
Mobasher Fasihy

18

Menurut tayangan slide tentang sistem Messaging Facebook, Facebook menggunakan teknologi komet untuk "mendorong" pesan ke browser web. Server komet Facebook dibangun di server web Erlang bersumber terbuka mochiweb.

Pada gambar di bawah, frasa "saluran cluster" berarti "server komet".

Ikhtisar sistem

Banyak situs web besar lainnya membangun server komet mereka sendiri, karena ada perbedaan antara kebutuhan setiap perusahaan. Tetapi membangun server comet Anda sendiri di server open source comet adalah pendekatan yang baik.

Anda dapat mencoba icomet , server komet C1000K C ++ yang dibuat dengan libevent. icomet juga menyediakan perpustakaan JavaScript, mudah digunakan sesederhana:

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 mendukung berbagai Peramban dan OS, termasuk Safari (iOS, Mac), IEs (Windows), Firefox, Chrome, dll.


Gambar ini menggambarkan skenario dengan sangat baik. Akan lebih bagus jika contoh tindakan diberikan. Misalnya apa yang terjadi ketika seseorang membuka (memulai) kotak obrolan dengan seorang teman? Bagaimana facebook menyetel ke percakapan khusus ini dan mendorong pesan untuk keduanya berakhir? (hanya tebakan: Saya hanya bisa membayangkan bahwa program aplikasi membuka soket dan mengikat kedua alamat klien dan kemudian terus mendengarkan dan menulis setiap kali pesan ditulis di dalam kotak)
edam

5

Facebook menggunakan MQTT bukan HTTP. Push lebih baik daripada polling. Melalui HTTP kita perlu polling server terus menerus tetapi melalui server MQTT mendorong pesan ke klien.

Perbandingan antara MQTT dan HTTP: http://www.youtube.com/watch?v=-KNPXPmx88E

Catatan: jawaban saya paling cocok untuk perangkat seluler.


3
Selain itu, google menggunakan layanan GCM untuk android, itu dapat digunakan oleh pengembang untuk menerapkan layanan pesan push. developer.android.com/google/gcm/index.html Terima jika Anda menemukan jawabannya bermanfaat.
abhi

5

Salah satu masalah penting dengan polling panjang adalah penanganan kesalahan. Ada dua jenis kesalahan:

  1. Permintaan mungkin akan habis dalam hal ini klien harus segera membangun kembali koneksi. Ini adalah peristiwa normal dalam pemungutan suara panjang ketika tidak ada pesan yang datang.

  2. Kesalahan jaringan atau kesalahan eksekusi. Ini adalah kesalahan aktual yang harus diterima klien dengan anggun dan menunggu server kembali online.

Masalah utama adalah bahwa jika penangan kesalahan Anda membangun kembali koneksi segera juga untuk kesalahan tipe 2, klien akan DOS server.

Kedua jawaban dengan contoh kode ketinggalan ini.

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.