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.
skip
,$near
dan$where
berisi kueri) yang jauh lebih efisien dalam beban CPU, bandwidth jaringan, dan memungkinkan aplikasi penskalaan server.Dari pengalaman saya, menggunakan banyak klien sambil berbagi banyak koleksi di Meteor pada dasarnya tidak bisa dijalankan, mulai versi 0.7.0.1. Saya akan mencoba menjelaskan mengapa.
Seperti yang dijelaskan dalam posting di atas dan juga di https://github.com/meteor/meteor/issues/1821 , server meteor harus menyimpan salinan data yang diterbitkan untuk setiap klien di kotak gabungan . Inilah yang memungkinkan keajaiban Meteor terjadi, tetapi juga menghasilkan database bersama yang besar yang berulang kali disimpan dalam memori proses node. Bahkan ketika menggunakan kemungkinan pengoptimalan untuk koleksi statis seperti di ( Apakah ada cara untuk memberi tahu meteor bahwa koleksi itu statis (tidak akan pernah berubah)? ), Kami mengalami masalah besar dengan penggunaan CPU dan Memori dari proses Node.
Dalam kasus kami, kami menerbitkan koleksi 15 ribu dokumen untuk setiap klien yang benar-benar statis. Masalahnya adalah bahwa menyalin dokumen-dokumen ini ke kotak penggabungan klien (dalam memori) setelah koneksi pada dasarnya membawa proses Node ke 100% CPU selama hampir satu detik, dan menghasilkan penggunaan memori tambahan yang besar. Ini secara inheren tidak dapat diskalakan, karena setiap klien yang terhubung akan membuat server bertekuk lutut (dan koneksi simultan akan memblokir satu sama lain) dan penggunaan memori akan meningkat secara linier dalam jumlah klien. Dalam kasus kami, setiap klien menyebabkan penggunaan memori tambahan ~ 60MB , meskipun data mentah yang ditransfer hanya sekitar 5MB.
Dalam kasus kami, karena koleksi itu statis, kami menyelesaikan masalah ini dengan mengirim semua dokumen sebagai
.json
file, yang di-gzip oleh nginx, dan memuatnya ke dalam koleksi anonim, menghasilkan hanya transfer data ~ 1MB tanpa CPU tambahan atau memori dalam proses node dan waktu buka yang lebih cepat. Semua operasi atas koleksi ini dilakukan dengan menggunakan_id
s dari publikasi yang jauh lebih kecil di server, memungkinkan untuk mempertahankan sebagian besar manfaat Meteor. Ini memungkinkan aplikasi untuk menskalakan lebih banyak klien. Selain itu, karena sebagian besar aplikasi kami hanya-baca, kami semakin meningkatkan skalabilitas dengan menjalankan beberapa instance Meteor di belakang nginx dengan load balancing (meskipun dengan satu Mongo), karena setiap instance Node adalah single-threaded.Namun, masalah berbagi koleksi yang besar dan dapat ditulisi di antara banyak klien merupakan masalah teknik yang perlu diselesaikan oleh Meteor. Mungkin ada cara yang lebih baik daripada menyimpan salinan segalanya untuk setiap klien, tetapi itu membutuhkan pemikiran serius sebagai masalah sistem terdistribusi. Masalah saat ini dari penggunaan CPU dan memori yang masif tidak akan skala.
sumber
Eksperimen yang dapat Anda gunakan untuk menjawab pertanyaan ini:
meteor create --example todos
Untuk tips tentang cara menggunakan WKI, lihat artikel ini . Agak ketinggalan zaman, tetapi sebagian besar masih valid, terutama untuk pertanyaan ini.
sumber
Ini masih satu tahun sekarang dan oleh karena itu saya pikir pengetahuan pra- "Meteor 1.0", jadi banyak hal mungkin telah berubah lagi? Saya masih menyelidiki ini. http://meteorhacks.com/does-meteor-scale.html mengarah ke "Bagaimana mengukur Meteor?" artikel http://meteorhacks.com/how-to-scale-meteor.html
sumber