Gerçek zamanlı ağır websockets tabanlı bir web uygulaması nasıl mimarilir?


17

Gerçek zamanlı bir Tek Sayfa Uygulaması geliştirme sürecinde, kullanıcılarımı güncel verilerle güçlendirmek için aşamalı olarak websockets kullandım. Bu aşamada, uygulama yapımın çok çoğunu yok ettiğimi fark ettim ve bu fenomene bir çözüm bulamadım.

Özelliklere girmeden önce, biraz bağlam:

  • Webapp bir gerçek zamanlı SPA;
  • Arka uç Ruby on Rails'de. Gerçek zamanlı olaylar Ruby tarafından bir Redis anahtarına aktarılır, daha sonra bir mikro düğüm sunucusu bunu geri çeker ve Socket'a iter.
  • Ön Uç AngularJS'de ve doğrudan Düğümdeki socket.io sunucusuna bağlanır.

Sunucu tarafında, gerçek zamanlı olarak, kaynakların her biri eklenmiş olarak açık bir denetleyici / model tabanlı ayrımı vardı. Bu klasik MVC tasarımı , websockets aracılığıyla kullanıcılarıma itmeye başladığımda tamamen parçalanmış veya en azından atlanmıştı. Artık tüm uygulamamın daha fazla veya daha az yapılandırılmış veri aktığı tek bir kanalım var . Ve stresli buluyorum.

Ön tarafta, ana endişe iş mantığının tekrarlanmasıdır. Kullanıcı sayfayı yüklediğinde, klasik AJAX çağrılarıyla modellerimi yüklemek zorundayım. Ama aynı zamanda gerçek zamanlı veri taşkınlarıyla başa çıkmak zorundayım ve müşteri tarafı modellerimin tutarlılığını korumak için kendimi müşteri tarafı iş mantığımın çoğunu kopyalarken buluyorum.

Bazı araştırmalardan sonra, iyi bir yazı, makale, kitap veya bir kaç modern konuyu akılda tutarak modern bir web uygulamasının mimarisini nasıl tasarlayabileceği ve tasarlayacağı hakkında tavsiyeler verecek herhangi bir şey bulamıyorum:

  • Sunucudan kullanıcıya gönderilen veriler nasıl yapılandırılır?
    • Yalnızca "bu kaynak güncellendi ve bir AJAX çağrısı yoluyla yeniden yüklemelisiniz" gibi olayları göndermeli miyim yoksa güncellenmiş verileri aktarmalı ve ilk AJAX çağrıları aracılığıyla yüklenen önceki verileri değiştirmeli miyim?
    • Gönderilen verilere tutarlı ve ölçeklenebilir bir iskelet nasıl tanımlanır? bu bir model güncelleme mesajı mı yoksa "blahblahblah ile ilgili bir hata oluştu" mesajı mı
  • Arka uçtaki herhangi bir yerden her şey hakkında veri nasıl gönderilmez?
  • Hem sunucu hem de istemci tarafında iş mantığı çoğaltması nasıl azaltılır?

Rails'in SPA'nız için en iyi seçenek olduğundan emin misiniz? Raylar harika, ama monolit uygulamasını hedefliyor ... endişe ayrımı ile modüler bir arka uç isteyebilirsiniz ... İhtiyaçlarınıza bağlı olarak, gerçek zamanlı bir SPA için alternatif Ruby çerçevelerini düşünürdüm.
Myst

1
Rails en iyi seçenek olduğundan emin değilim, ama en azından arka uç üzerinde yerinde yığını ile çok memnunum (muhtemelen bu belirli çerçeve ile iyi olduğum için). Buradaki endişem, SPA'nın teknoloji agnostik bir bakış açısıyla nasıl tasarlanacağı hakkında daha fazla. Ayrıca tek bir projede dil, çerçeve ve kütüphane sayısını çoğaltmak da istemiyorum.
Philippe Durix

Bağlantılı karşılaştırmada sorunlar olabilir, ancak mevcut ActiveRecord uygulamasında bir zayıflık ortaya çıkarmaktadır. Plezi.io hakkında önyargılı olabilirim , ancak karşılaştırmanın daha sonraki sonuçlarında belirtildiği gibi , kümelenmeden ve Redis'ten (test edilmedi) bile önemli performans iyileştirmeleri sağlar. Sanırım node.js'den daha iyi performans gösterdi ... İşler değişene kadar plezi.io kullanırdım.
Myst

Yanıtlar:


10

Sunucudan kullanıcıya gönderilen veriler nasıl yapılandırılır?

Mesajlaşma düzenini kullanın . Zaten bir mesajlaşma protokolü kullanıyorsunuz, ama değişiklikleri mesaj olarak yapılandırmak ... özellikle olaylar. Sunucu tarafı değiştiğinde, bu iş olaylarıyla sonuçlanır. Senaryonuzda, müşteri görüşleriniz bu olaylarla ilgilenir. Olaylar, bu değişiklikle ilgili tüm verileri içermelidir (mutlaka tüm görüntüleme verilerini içermez). Müşteri sayfası daha sonra koruduğu görünüm bölümlerini olay verileriyle güncellemelidir.

Örneğin, bir hisse senedi senedi güncelliyorsanız ve AAPL değiştiyse, tüm hisse senedi fiyatlarını veya hatta AAPL ile ilgili tüm verileri (ad, açıklama vb.) Aşağı itmek istemezsiniz. Sadece AAPL'yi, deltayı ve yeni fiyatı itersiniz. İstemcide, görünümde yalnızca bu hisse senedi fiyatını güncellersiniz.

Yalnızca "bu kaynak güncellendi ve bir AJAX çağrısı yoluyla yeniden yüklemelisiniz" gibi olayları göndermeli miyim yoksa güncellenmiş verileri aktarmalı ve ilk AJAX çağrıları aracılığıyla yüklenen önceki verileri değiştirmeli miyim?

Ben de söyleyemem. Etkinliği gönderiyorsanız devam edin ve etkinlikle ilgili verileri gönderin (tüm nesnenin verilerini değil). Olduğu olay için bir isim verin. (Adlandırma ve o olayla ilgili hangi veriler sistemin mekanik çalışmalarının kapsamı dışındadır. Bunun, iş mantığının nasıl modelleneceği ile daha fazla ilgilidir.) Görüntüleme güncelleyicilerinizin her bir olayın nasıl çevrileceğini bilmesi gerekir hassas bir görünüm değişikliği (yani yalnızca nelerin değiştiğini güncelleyin).

Gönderilen verilere tutarlı ve ölçeklenebilir bir iskelet nasıl tanımlanır? bu bir model güncelleme mesajı mı yoksa "blahblahblah ile ilgili bir hata oluştu" mesajı mı

Bunun büyük, açık uçlu bir soru olduğunu söyleyebilirim, diğer birkaç soruya bölünmeli ve ayrı olarak gönderilmelidir.

Genel olarak, arka uç sisteminiz, işinizde önemli olaylar için etkinlikler oluşturmalı ve göndermelidir. Bunlar harici yemlerden veya arka uçtaki aktiviteden gelebilir.

Arka uçtaki herhangi bir yerden her şey hakkında veri nasıl gönderilmez?

Yayınlama / abone olma düzenini kullanın . SPA'nız gerçek zamanlı güncellemeler almakla ilgilenen yeni bir sayfa yüklediğinde, sayfa yalnızca kullanabileceği olaylara abone olmalı ve bu olaylar geldiğinde görünüm güncelleme mantığını çağırmalıdır. Muhtemelen pub / alt mantığına ihtiyacınız olacaktır. ağ yükünü azaltmak için sunucuya. Websocket pub / sub için kütüphaneler var, ancak Rails ekosisteminde ne olduğundan emin değilim.

Hem sunucu hem de istemci tarafında iş mantığı çoğaltması nasıl azaltılır?

Hem istemci hem de sunucudaki görünüm verilerini güncellemek zorunda olduğunuz anlaşılıyor. Sanırım gerçek zamanlı istemciyi başlatmak için bir anlık görüntünüz olması için sunucu tarafı görünüm verilerine ihtiyacınız var. İki dil / platform (Ruby ve Javascript) olduğu için, görünüm güncelleme mantığının her ikisine de yazılması gerekir. (Kendi sorunları olan) nakli dışında, bunun için bir yol göremiyorum.

Teknik nokta: Veri işleme (görünümü güncelleme) iş mantığı değildir. Kullanım örneği doğrulamasını kullanmak istiyorsanız, istemcinin doğrulamaları iyi kullanıcı deneyimi için gerekli olduğundan, ancak sonuçta sunucu tarafından güvenilemediğinden bu kaçınılmaz görünmektedir.


İşte böyle bir şeyi iyi yapılandırılmış görüyorum.

Müşteri Görüşleri:

  • Bir görünüm anlık görüntüsü ve görünümün son görülen olay numarasını ister
    • Bu, görünümün önceden doldurulmasını sağlar, böylece istemci sıfırdan oluşturmak zorunda kalmaz.
    • Basitlik için HTTP GET üzerinden olabilir
  • Web soketi bağlantısı kurar ve görünümün son etkinlik numarasından başlayarak belirli etkinliklere abone olur.
  • Web soketi üzerinden olayları alır ve olay türüne / verilerine göre görünümünü günceller.

İstemci Komutları:

  • Veri değişikliği iste (HTTP PUT / POST / DELETE)
    • Yanıt sadece başarı veya başarısızlık + hatadır
    • (Değişiklik tarafından oluşturulan etkinlikler websocket üzerinden gelir ve görünüm güncellemesini tetikler.)

Sunucu tarafı aslında sınırlı sorumlulukları olan birkaç bileşene ayrılabilir. Yalnızca gelen istekleri işleyen ve etkinlikler oluşturan bir. Bir diğeri istemci aboneliklerini yönetebilir, olayları dinleyebilir (işlem sırasında) ve uygun olayları abonelere iletebilir. Olayları dinleyen ve sunucu tarafı görünümlerini güncelleyen bir üçüncünüz olabilir - belki bu, aboneler olayları almadan önce bile olabilir.

Tarif ettiğim bir tür CQRS + Mesajlaşma ve karşılaştığınız sorunları ele almak için tipik bir stratejidir.

Olay Kaynak Oluşturma'yı bu açıklamaya getirmedim , çünkü almak istediğiniz bir şey olup olmadığından veya buna ihtiyacınız olup olmadığından emin değilim. Ancak, ilgili bir örüntüdür.


Bu konuda çok ilerledim ve verdiğiniz işaretçiler çok faydalı oldu. Cevabı kabul ettim çünkü hepsini kullanmasam bile birçok tavsiyeyi kullandım. Başka bir cevapta izlediğim yolu anlatacağım.
Philippe Durix

4

Özellikle arka uçta birkaç ay çalıştıktan sonra, platformun karşılaştığı sorunları ele almak için buradaki bazı önerileri kullanabildim.

Arka ucun yeniden düşünülmesindeki temel amaç, CRUD'ye olabildiğince sert olmaktı. Birçok rotaya dağılmış olan tüm eylemler, mesajlar ve istekler oluşturulan, güncellenen, okunan veya silinen kaynaklara yeniden gruplandırıldı . Şimdi açık gibi görünüyor, ancak bu dikkatlice uygulamak için çok zor bir düşünme yolu oldu.

Her şey kaynaklarda organize edildikten sonra, modellere gerçek zamanlı mesajlar ekleyebildim.

  • Oluşturma yeni delikli bir mesajı tetikler;
  • Güncelleme, yalnızca güncellenmiş özniteliklere (UUID) sahip bir iletiyi tetikler;
  • Silme, bir silme mesajını tetikler.

Dinlenme API'sinde, tüm oluşturma, güncelleme, silme yöntemleri yalnızca bir başlık yanıtı, başarının veya başarısızlığın HTTP kodunu bildirme ve gerçek veriler web soketleri üzerinden gönderilir.

Ön uçta, her kaynak, başlatma sırasında HTTP üzerinden yükleyen belirli bir bileşen tarafından işlenir, ardından güncelleştirmelere abone olur ve zaman içinde durumlarını korur. Daha sonra görünümler, kaynakları görüntülemek ve bu bileşenler üzerinde aynı bileşenlerle eylemler gerçekleştirmek için bu bileşenlere bağlanır.


CQRS + Messaging ve Event Sourcing okumalarını çok ilginç buldum, ancak sorunum için biraz karmaşık olduğunu ve merkezi bir veritabanına veri aktarmanın pahalı bir lüks olduğu yoğun uygulamalara daha fazla adapte olduğunu hissettim. Ama kesinlikle bu yaklaşımı aklımda tutacağım.

Bu durumda, uygulamanın birkaç eşzamanlı müşterisi olacak ve veritabanına çok güvenerek partiyi aldım. En çok değişen modeller, saniyede birkaç yüz güncellemeyi işlemeye güvendiğim Redis'te saklanır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.