Kısa cevap, kabloya yalnızca yeni verilerin gönderilmesidir. İşte nasıl çalıştığı.
Meteor sunucusunun abonelikleri yöneten üç önemli bölümü vardır: aboneliğin sağladığı verilerin mantığını tanımlayan yayınlama işlevi ; Mongo sürücü değişiklikleri veritabanı saatler; ve bir müşterinin tüm aktif aboneliklerini birleştiren ve bunları ağ üzerinden müşteriye gönderen birleştirme kutusu .
İşlevleri yayınla
Bir Meteor istemcisi bir koleksiyona her abone olduğunda, sunucu bir yayınlama işlevi çalıştırır
. Yayınlama işlevinin görevi, istemcinin sahip olması gereken belge setini bulmak ve her belge özelliğini birleştirme kutusuna göndermektir. Her yeni abone olan müşteri için bir kez çalışır. Kullanarak rastgele karmaşık erişim kontrolü gibi yayınlama işlevine istediğiniz herhangi bir JavaScript koyabilirsiniz this.userId
. Yayınlama işlevi this.added
, this.changed
ve
çağırarak verileri birleştirme kutusuna gönderir this.removed
. Daha
fazla ayrıntı için yayın belgelerinin tamamına bakın.
Yayımlamak Çoğu fonksiyon düşük seviyede boğuşulmamasıdır gerekmez
added
, changed
ve removed
de, API. Bir fonksiyon döner bir Mongo imleç yayınlarsanız, Meteor sunucusu otomatik Mongo sürücü (çıktısını bağlayan insert
, update
ve removed
birleştirme kutusunun girişine geri aramalar) ( this.added
, this.changed
ve this.removed
). Bir yayınlama işlevinde tüm izin kontrollerini önceden yapabilmeniz ve ardından herhangi bir kullanıcı kodu olmadan veritabanı sürücüsünü doğrudan birleştirme kutusuna bağlayabilmeniz oldukça güzel. Ve otomatik yayın açıldığında, bu küçük kısım bile gizlenir: sunucu, her koleksiyondaki tüm belgeler için otomatik olarak bir sorgu oluşturur ve bunları birleştirme kutusuna iter.
Öte yandan, veritabanı sorgularını yayınlamakla sınırlı değilsiniz. Örneğin, bir cihazdaki bir GPS konumunu okuyan Meteor.setInterval
veya başka bir web hizmetinden eski bir REST API'sini sorgulayan bir yayınlama işlevi yazabilirsiniz . Bu gibi durumlarda, düşük seviyeli arayarak birleştirme kutusuna değişiklikleri yayarlar ediyorum added
, changed
ve removed
DDP API.
Mongo sürücüsü
Mongo sürücünün işi canlı sorgularına değişiklikler için Mongo veritabanı izlemektir. Bu sorgular sürekli çalışacak ve arayarak sonuçları değişiklik olarak güncellemeleri dönmek added
, removed
ve changed
geri aramalar.
Mongo, gerçek zamanlı bir veritabanı değildir. Yani sürücü anketler. Her etkin canlı sorgu için son sorgu sonucunun bellek içi bir kopyasını tutar. Her yoklama döngüsünde üzerinde, minimum set bilgisayar, önceki kayıtlı sonuçla yeni sonucu karşılaştırır added
, removed
ve changed
farkı açıklamak olaylar. Birden fazla arayan aynı canlı sorgu için geri aramalar kaydederse, sürücü sorgunun yalnızca bir kopyasını izler ve her kayıtlı geri aramayı aynı sonuçla arar.
Sunucu bir koleksiyonu her güncellediğinde, sürücü o koleksiyondaki her canlı sorguyu yeniden hesaplar (Meteor'un gelecekteki sürümleri, hangi canlı sorguların güncelleme sırasında yeniden hesaplanacağını sınırlamak için bir ölçeklendirme API'sini ortaya çıkaracaktır.) Sürücü ayrıca her bir canlı sorguyu 10 saniyelik bir zamanlayıcıda yoklar. Meteor sunucusunu atlayan bant dışı veritabanı güncellemelerini yakalamak.
Birleştirme kutusu
İş birleştirme kutusundan sonuçları (birleştirmektir added
, changed
ve removed
tek bir veri akışına bir müşterinin aktif yayımlamak her türlü fonksiyonun aramaları). Bağlı her istemci için bir birleştirme kutusu vardır. Müşterinin minimongo önbelleğinin tam bir kopyasını tutar.
Yalnızca tek bir abonelik içeren örneğinizde, birleştirme kutusu esasen bir geçiştir. Ancak daha karmaşık bir uygulamanın birden çok aboneliği olabilir ve bunlar çakışabilir. İki abonelik aynı belgede aynı özniteliği ayarlarsa, birleştirme kutusu hangi değerin öncelikli olduğuna karar verir ve bunu yalnızca istemciye gönderir. Henüz abonelik önceliğini belirleme API'sini ifşa etmedik. Şimdilik öncelik, müşterinin veri setlerine abone olma sırasına göre belirlenir. Bir müşterinin yaptığı ilk abonelik en yüksek önceliğe sahiptir, ikinci abonelik en yüksek önceliğe sahiptir ve bu böyle devam eder.
Birleştirme kutusu istemcinin durumunu tuttuğu için, yayınlama işlevi ne olursa olsun her müşteriyi güncel tutmak için minimum miktarda veri gönderebilir.
Bir güncellemede ne olur
Şimdi senaryonuz için sahneyi hazırladık.
1.000 bağlantılı müşterimiz var. Her biri aynı canlı Mongo sorgusuna ( Somestuff.find({})
) abone olur . Sorgu her istemci için aynı olduğundan, sürücü yalnızca bir canlı sorgu çalıştırıyor. 1.000 aktif birleştirme kutusu vardır. Ve her müşterinin yayınlama işlevi added
, bir changed
, ve
removed
birleştirme kutularından birine beslenen canlı sorguda kaydedildi. Birleştirme kutularına başka hiçbir şey bağlı değildir.
Önce Mongo sürücüsü. İstemcilerden biri içine yeni bir belge eklediğinde Somestuff
, bir yeniden hesaplamayı tetikler. Mongo sürücüsü içindeki tüm belgeler için sorguyu yeniden çalıştırır, Somestuff
sonucu bellekteki bir önceki sonuçla karşılaştırır, bir yeni belge olduğunu bulur ve 1.000 kayıtlı insert
geri aramadan her birini çağırır .
Ardından, yayınlama işlevleri. Burada çok az şey oluyor: 1.000 insert
geri aramadan her biri, verileri arayarak birleştirme kutusuna aktarıyor added
.
Son olarak, her bir birleştirme kutusu, bu yeni öznitelikleri, istemcisinin önbelleğinin bellek içi kopyasına göre kontrol eder. Her durumda, değerlerin henüz istemcide olmadığını ve mevcut bir değeri gölgelemediğini bulur. Dolayısıyla, birleştirme kutusu DATA
, SockJS bağlantısında istemcisine bir DDP mesajı gönderir ve sunucu tarafındaki bellek içi kopyasını günceller.
Toplam CPU maliyeti, bir Mongo sorgusunu ayırt etmenin maliyeti artı müşterilerinin durumunu kontrol eden ve yeni bir DDP ileti yükü oluşturan 1.000 birleştirme kutusunun maliyetidir. Kablo üzerinden akan tek veri, veritabanındaki yeni belgeye karşılık gelen 1.000 istemcinin her birine gönderilen tek bir JSON nesnesidir ve ayrıca orijinal eklemeyi yapan istemciden sunucuya bir RPC mesajıdır .
Optimizasyonlar
İşte kesinlikle planladığımız şey.
Daha verimli Mongo sürücüsü. Sürücüyü
, her bir sorgu için yalnızca tek bir gözlemci çalıştırmak için 0.5.1'de optimize ettik
.
Her DB değişikliğinin bir sorgunun yeniden hesaplanmasını tetiklemesi gerekmez. Bazı otomatik iyileştirmeler yapabiliriz, ancak en iyi yaklaşım, geliştiricinin hangi sorguların yeniden çalıştırılması gerektiğini belirlemesini sağlayan bir API'dir. Örneğin, bir geliştirici için bir sohbet odasına mesaj eklemenin, ikinci bir odadaki mesajlar için canlı bir sorguyu geçersiz kılmaması gerektiği açıktır.
Mongo sürücüsü, yayınlama işlevi ve birleştirme kutusunun aynı işlemde hatta aynı makinede çalışması gerekmez. Bazı uygulamalar karmaşık canlı sorgular çalıştırır ve veritabanını izlemek için daha fazla CPU'ya ihtiyaç duyar. Diğerlerinin yalnızca birkaç farklı sorgusu vardır (bir blog motoru hayal edin), ancak muhtemelen birçok bağlı istemci - bunların birleştirme kutuları için daha fazla CPU'ya ihtiyacı var. Bu bileşenleri ayırmak, her bir parçayı bağımsız olarak ölçeklendirmemizi sağlayacaktır.
Birçok veritabanı, bir satır güncellendiğinde tetiklenen tetikleyicileri destekler ve eski ve yeni satırları sağlar. Bu özellikle, bir veritabanı sürücüsü değişiklikleri sorgulamak yerine bir tetikleyici kaydedebilir.