Jawaban singkatnya adalah bahwa hanya data baru yang dikirim melalui jaringan. Begini cara kerjanya.
Ada tiga bagian penting dari server Meteor yang mengelola langganan: fungsi publikasi , yang mendefinisikan logika untuk data apa yang disediakan langganan; yang sopir Mongo , yang jam tangan database untuk perubahan; dan kotak gabungan , yang menggabungkan semua langganan aktif klien dan mengirimkannya melalui jaringan ke klien.
Publikasikan fungsi
Setiap kali klien Meteor berlangganan koleksi, server menjalankan
fungsi publikasi . Tugas fungsi publikasi adalah mencari tahu kumpulan dokumen yang harus dimiliki kliennya dan mengirim setiap properti dokumen ke dalam kotak gabungan. Ini berjalan sekali untuk setiap klien baru yang berlangganan. Anda dapat meletakkan JavaScript apa pun yang Anda inginkan dalam fungsi terbitkan, seperti penggunaan kontrol akses yang rumit secara sewenang-wenang this.userId
. Fungsi terbitkan mengirimkan data ke kotak gabungan dengan memanggil this.added
, this.changed
dan
this.removed
. Lihat
dokumentasi publikasi lengkap untuk lebih jelasnya.
Sebagian besar fungsi publikasi tidak harus dipusingkan dengan level rendah
added
, changed
dan removed
API. Jika mempublikasikan kembali fungsi kursor Mongo, server Meteor otomatis menghubungkan output dari driver Mongo ( insert
, update
, dan removed
callback) ke input dari kotak merge ( this.added
, this.changed
dan this.removed
). Cukup rapi bahwa Anda dapat melakukan semua pemeriksaan izin di depan dalam fungsi publikasi dan kemudian langsung menghubungkan driver database ke kotak gabungan tanpa ada kode pengguna yang menghalangi. Dan saat penerbitan otomatis diaktifkan, meskipun sedikit ini disembunyikan: server secara otomatis menyiapkan kueri untuk semua dokumen di setiap koleksi dan memasukkannya ke dalam kotak gabungan.
Di sisi lain, Anda tidak terbatas pada kueri database penerbitan. Misalnya, Anda dapat menulis fungsi publikasi yang membaca posisi GPS dari perangkat di dalam Meteor.setInterval
, atau mengumpulkan REST API lama dari layanan web lain. Dalam kasus tersebut, Anda akan memancarkan perubahan ke kotak merge dengan memanggil tingkat rendah added
, changed
dan removed
DDP API.
Pengemudi Mongo
Tugas pengemudi Mongo adalah mengawasi database Mongo untuk melihat perubahan pada kueri langsung. Pertanyaan ini terus berjalan dan kembali update sebagai perubahan hasil dengan menelepon added
, removed
dan changed
callback.
Mongo bukanlah database waktu nyata. Jadi pengemudi jajak pendapat. Itu menyimpan salinan dalam memori dari hasil kueri terakhir untuk setiap kueri langsung yang aktif. Pada setiap siklus polling, membandingkan hasil baru dengan hasil disimpan sebelumnya, menghitung set minimum added
, removed
dan changed
peristiwa yang menggambarkan perbedaan. Jika beberapa penelepon mendaftarkan callback untuk kueri langsung yang sama, pengemudi hanya akan melihat satu salinan kueri, memanggil setiap callback terdaftar dengan hasil yang sama.
Setiap kali server memperbarui koleksi, driver menghitung ulang setiap kueri langsung pada koleksi itu (Versi Meteor yang akan datang akan mengekspos API penskalaan untuk membatasi kueri langsung mana yang dihitung ulang saat pembaruan.) Pengemudi juga memeriksa setiap kueri langsung pada timer 10 detik ke menangkap update database out-of-band yang melewati server Meteor.
Kotak gabungan
Tugas kotak gabungan adalah menggabungkan hasil ( added
, changed
dan removed
panggilan) dari semua fungsi publikasi aktif klien ke dalam aliran data tunggal. Ada satu kotak gabungan untuk setiap klien yang terhubung. Ini menyimpan salinan lengkap dari cache minimongo klien.
Dalam contoh Anda dengan hanya satu langganan, kotak gabungan pada dasarnya adalah pass-through. Tetapi aplikasi yang lebih kompleks dapat memiliki banyak langganan yang mungkin tumpang tindih. Jika dua langganan menyetel atribut yang sama pada dokumen yang sama, kotak gabungan memutuskan nilai mana yang diprioritaskan dan hanya mengirimkannya ke klien. Kami belum mengekspos API untuk menyetel prioritas langganan. Untuk saat ini, prioritas ditentukan oleh urutan langganan klien ke kumpulan data. Langganan pertama yang dibuat klien memiliki prioritas tertinggi, langganan kedua adalah tertinggi berikutnya, dan seterusnya.
Karena kotak gabungan menyimpan status klien, kotak ini dapat mengirim jumlah data minimum untuk menjaga setiap klien tetap up-to-date, apa pun fungsi publikasi yang memberinya makan.
Apa yang terjadi pada pembaruan
Jadi sekarang kami telah menyiapkan panggung untuk skenario Anda.
Kami memiliki 1.000 klien yang terhubung. Masing-masing berlangganan ke kueri Mongo langsung yang sama ( Somestuff.find({})
). Karena kueri sama untuk setiap klien, driver hanya menjalankan satu kueri langsung. Ada 1.000 kotak gabungan aktif. Dan masing-masing klien mempublikasikan fungsi mendaftarkan added
, changed
dan
removed
pada kueri hidup yang feed ke dalam salah satu kotak merge. Tidak ada lagi yang terhubung ke kotak gabungan.
Pertama, pengemudi Mongo. Ketika salah satu klien memasukkan dokumen baru ke Somestuff
dalamnya, itu memicu penghitungan ulang. Driver Mongo menjalankan kembali kueri untuk semua dokumen di Somestuff
, membandingkan hasil dengan hasil sebelumnya di memori, menemukan bahwa ada satu dokumen baru, dan memanggil masing-masing dari 1.000 insert
callback terdaftar .
Selanjutnya, fungsi publikasi. Sangat sedikit yang terjadi di sini: masing-masing dari 1.000 insert
panggilan balik mendorong data ke kotak gabungan dengan memanggil added
.
Akhirnya, setiap kotak gabungan memeriksa atribut baru ini terhadap salinan dalam memori dari cache kliennya. Dalam setiap kasus, ia menemukan bahwa nilai belum ada di klien dan tidak membayangi nilai yang sudah ada. Jadi kotak gabungan memancarkan DATA
pesan DDP pada sambungan SockJS ke kliennya dan memperbarui salinan dalam memori sisi servernya.
Total biaya CPU adalah biaya untuk membedakan satu kueri Mongo, ditambah biaya 1.000 kotak gabungan untuk memeriksa status klien mereka dan membuat muatan pesan DDP baru. Satu-satunya data yang mengalir melalui kabel adalah objek JSON tunggal yang dikirim ke masing-masing 1.000 klien, sesuai dengan dokumen baru dalam database, ditambah satu pesan RPC ke server dari klien yang membuat penyisipan asli.
Optimasi
Inilah yang telah kami rencanakan.
Pengemudi Mongo yang lebih efisien. Kami
mengoptimalkan driver
di 0.5.1 untuk hanya menjalankan satu pengamat per kueri berbeda.
Tidak setiap perubahan DB harus memicu penghitungan ulang kueri. Kami dapat membuat beberapa peningkatan otomatis, tetapi pendekatan terbaik adalah API yang memungkinkan pengembang menentukan kueri mana yang perlu dijalankan ulang. Misalnya, jelas bagi pengembang bahwa memasukkan pesan ke dalam satu ruang obrolan seharusnya tidak membatalkan kueri langsung untuk pesan di ruang kedua.
Driver Mongo, fungsi terbitkan, dan kotak penggabungan tidak perlu dijalankan dalam proses yang sama, atau bahkan di mesin yang sama. Beberapa aplikasi menjalankan kueri langsung yang kompleks dan membutuhkan lebih banyak CPU untuk mengawasi database. Yang lain hanya memiliki beberapa kueri berbeda (bayangkan mesin blog), tetapi mungkin banyak klien yang terhubung - ini membutuhkan lebih banyak CPU untuk kotak gabungan. Memisahkan komponen-komponen ini akan memungkinkan kita menskalakan setiap bagian secara independen.
Banyak database mendukung pemicu yang diaktifkan saat baris diperbarui dan menyediakan baris lama dan baru. Dengan fitur itu, driver database bisa mendaftarkan pemicu daripada melakukan polling untuk perubahan.