Jak oszczędzać podczas współpracy w czasie rzeczywistym

10

Chcę, aby wielu użytkowników edytowało ten sam dokument. Problem, z którym się spotykam, polega na tym, że gdy nowy użytkownik dołącza, może zobaczyć nieaktualny dokument. Jak upewnić się, że nowi użytkownicy otrzymują najnowsze zmiany?

Niektóre rozwiązania, o których myślałem:

  • Oszczędzaj na każdej zmianie. Nie podoba mi się to rozwiązanie, ponieważ spowoduje spowolnienie interfejsu użytkownika i obciążenie bazy danych.

  • Gdy dołącza nowy użytkownik, uruchom zapisywanie na wszystkich innych klientach. Po zapisaniu innych klientów załaduj dokument. Z tym może być nadal niespójność.

Wszelkie inne sugestie byłyby pomocne.

AKTUALIZACJA: Po zapoznaniu się z sugerowanym rozwiązaniem API Google Realtime dowiedziałem się, że:

  1. Użytkownicy Twojej aplikacji muszą mieć Dysk Google i dać ci dostęp do swojego dysku . Może to w najlepszym wypadku stanowić niezręczny interfejs użytkownika lub uniemożliwić użytkownikom, którzy nie mają Dysku Google, korzystanie z funkcji czasu rzeczywistego.

  2. Wszystkie ustawienia udostępniania dokonane po Twojej stronie muszą zostać zreplikowane dla dokumentu Google.

AKTUALIZACJA 2: Aby osiągnąć cel, wybrałem Firebase firmy Google

deweloper
źródło
Dlaczego istnieje różnica między nowym użytkownikiem a już aktywnymi użytkownikami edytującymi / przeglądającymi ten sam dokument?
Andy,
@Andy Obecnie nadaję przez gniazda wszystkie zmiany, których dokonują użytkownicy. Te zmiany aktualizują interfejs użytkownika dla użytkowników, którzy mają otwarte przeglądarki, ale nie są natychmiast zapisywane w bazie danych. Mam więc sytuację, gdy dołącza nowy użytkownik, ładuje dokument z bazy danych i nie widzi wszystkich ostatnich zmian, które nie zostały jeszcze zapisane.
dev.e.loper
1
jeśli już wysyłasz zmiany i chcesz pozostawić to samo, co teraz, możesz poprosić jednego z klientów o wysłanie ostatniego widoku do nowego klienta lub możesz mieć jednego klienta wirtualnego na serwerze, który otrzymuje wszystkie zmiany, a gdy nowy klient dołącza wysyła najnowsze zobacz to.
Dainius

Odpowiedzi:

14

dysk Google

Jeśli próbujesz stworzyć własną wersję dokumentów Google, sugeruję przyjrzeć się interfejsem API Google Realtime . Firma Google niedawno wydała to z zamiarem umożliwienia innym programistom korzystania z tych samych narzędzi, które zrobili, aby umożliwić współpracę w czasie rzeczywistym. Pozwoli ci to zaoszczędzić czas na rozwoju i szybciej uzyskać działający produkt.

Możesz łatwo pobrać dane znajdujące się w dokumencie i wepchnąć je do swojej bazy danych w regularnych odstępach czasu lub sprawić, by sama baza danych była „uczestnikiem” wymiany, po prostu słuchając i rejestrując wszystkie zmiany. Pozwala również użytkownikowi zdefiniować własne struktury danych, które następnie można wykorzystać w interfejsie API w czasie rzeczywistym, więc możesz dowolnie je rozszerzać według własnego uznania.

Dysk inny niż Google

Według badań Google Drive nie wchodzi w grę. W porządku, ale będzie trudniej i być może nie będzie działać, w zależności od tego, ile włożysz.

Oto ogólna strategia , której użyłbym do rozwiązania tego problemu:

  1. Niech serwer będzie multiplekserem komunikacyjnym. Każda osoba rozmawia z serwerem, a serwer wysyła te informacje do wszystkich innych. W ten sposób serwer zawsze ma najbardziej aktualny widok dokumentu.

  2. Znajdź algorytm / moduł innej firmy do rozwiązywania konfliktów. Rozwiązywanie konfliktów jest trudne i wciąż nie jest idealne. Samo to może z łatwością zwiększyć zakres projektu, który jest zdecydowanie zbyt duży. Jeśli nie możesz użyć algorytmu innej firmy, sugeruję, abyś zezwolił tylko jednemu użytkownikowi na edycję obszaru czasu, aby użytkownik musiał uzyskać blokadę przed edycją obszaru, inaczej ryzykujesz zniszczeniem pracy innych użytkowników, co bardzo się zestarzeje, bardzo szybko.

  3. Gdy nowy użytkownik dołączy, przekaż mu najnowszy dokument i automatycznie zacznij strumieniować do niego polecenia. Serwer ma najnowszy widok, dzięki czemu może go automatycznie wydzielić.

  4. Kopia zapasowa bazy danych w określonych odstępach czasu. Zdecyduj, jak często chcesz tworzyć kopie zapasowe (co 5 minut, a może co 50 zmian). Pozwala to zachować pożądaną kopię zapasową.

Problemy: To nie jest idealne rozwiązanie, więc oto kilka problemów, które możesz napotkać.

  1. Przepustowość serwera może ograniczać wydajność

  2. Zbyt wiele osób czytających / piszących może przeciążać serwer

  3. Ludzie mogą stracić synchronizację, jeśli wiadomość zostanie utracona, więc możesz chcieć upewnić się, że synchronizujesz w regularnych punktach. Oznacza to ponowne wysłanie całej wiadomości, co może być kosztowne, ale w przeciwnym razie ludzie mogą nie mieć tego samego dokumentu i go nie znać.

Ampt
źródło
Tak, zmiany są transmitowane do wszystkich klientów i mają swoją (mam taką samą) wersję w przeglądarce. Wygląda na to, że mówienie o tym, że aktualizowanie dokumentu przy każdej akcji jest dobrym rozwiązaniem?
dev.e.loper
Lub przynajmniej mają regularne ramy czasowe synchronizacji, w których bieżący stan dokumentu jest przesyłany w tle, aby upewnić się, że wszyscy są na tej samej stronie. Jak często zależeć będzie od tego, jak szybko ludzie będą zmieniać dokument. W ten sposób masz już ustaloną metodę wysyłania do nowych osób, a także możliwość upewnienia się, że nigdy nie będzie zbytnio rozbieżna.
Ampt
1
+1. Nie utrudniaj życia. Google robi to dobrze bez konieczności wymyślania nowego koła.
Neil
Czy Google Realtime zapisuje się na Dysku Google? Chcę zapisać w mojej bazie danych, a nie na Dysku Google.
dev.e.loper
@ dev.e.loper dodał dla ciebie trochę informacji na ten temat.
Ampt
3

Polecam 1 trwałą kopię dokumentu na serwerze. Kiedy klient łączy się z serwerem, wydajesz UPDATEkomendę (polecenia) temu klientowi ze wszystkimi zmianami.

Zaktualizuj WorkFlow

Użytkownik powoduje zmianę wyzwalającą -> Klient wysyła UPDATEdo serwera -> Serwer wysyła UPDATEdo klientów

Żywe wyzwalacze

  1. Użytkownik klika Zapisz
  2. Użytkownik wykonuje określone zadanie
    • Kończy edycję komórki
    • Kończy edycję zdania / akapitu / linii
  3. Użytkownik klika Cofnij
  4. Użytkownik naciska klawisz Return
  5. Użytkownik wpisuje klucz (oszczędzaj na każdej zmianie)

Zaktualizuj implementację

Sugerowałbym możliwość odtworzenia dokumentu za pomocą szeregu UPDATEpoleceń, aby serwer przechowywał każdą AKTUALIZACJĘ, a gdy nowy klient się łączy, można wysłać mu serię aktualizacji, a on sam może ponownie utworzyć dokument do wyświetlenia użytkownik. Alternatywnie możesz mieć SAVEosobne polecenie, a UPDATE to tymczasowe zmiany, których można użyć dla UNDOżądań, i ZAPISZ faktycznie zapisz je, aby zostało ponownie otwarte, jeśli serwer zostanie zamknięty lub wszyscy klienci się rozłączą.

Korey Hinton
źródło
2
Co z rozwiązywaniem konfliktów? Co zrobić, jeśli dwie osoby jednocześnie edytują ten sam obszar tekstu? Wydaje się to również obciążać DB, czego OP chciał uniknąć. Może to być opłacalne ze względu na to, czego potrzebuje.
Ampt
@Apt Zrobiłem arkusz kalkulacyjny przy użyciu tego modelu, a w przypadku konfliktów każde konkretne aktualizowane zadanie zostało całkowicie zastąpione najnowszą wersją. Tak więc ostatnia osoba, która zakończy edycję komórki, całkowicie zastąpi poprzednio zaktualizowaną, bez scalania.
Korey Hinton
1
Więc jedno zdanie zastąpiłoby inne, gdyby to był, powiedzmy, dokument słowny?
Ampt
@Am tak, alternatywnie możesz wprowadzić sposób blokowania tego, nad czym pracujemy, ale wybrałem łatwą drogę.
Korey Hinton
3

1) Zajrzyj na Knockout.js

Podąża za wzorcem MVVM i automatycznie wysyła powiadomienia do Widoku na podstawie zmian w Modelu. Na przykład spójrz na ich obserwowalną tablicę, aby uzyskać nieco więcej informacji na temat tego, jak to robią.

2) Połącz to z SignalR i powinieneś teraz mieć możliwość wysyłania powiadomień do innych użytkowników pracujących nad dokumentem. Z ich strony:

SignalR zapewnia również bardzo prosty interfejs API wysokiego poziomu do wykonywania RPC między serwerami (wywoływanie funkcji JavaScript w przeglądarkach klientów z kodu .NET po stronie serwera) w aplikacji ASP.NET, a także dodawanie przydatnych haków do zarządzania połączeniami , np. łączenie / rozłączanie zdarzeń, grupowanie połączeń, autoryzacja.

Musisz więc mieć kilka haczyków na poziomie modelu w Knockout.js, aby wykonywać niektóre wywołania SignalR za każdym razem, gdy nastąpi zmiana. Pozostali klienci otrzymają powiadomienie od SignalR, a następnie wywołają odpowiednią zmianę w swojej kopii Modelu, co spowoduje powrót do ich Widoku.

Jest to interesująca kombinacja dwóch ram, i powinieneś być w stanie wyszukać i zebrać więcej informacji, aby obsłużyć dane szczegółowe.

Na przykład ten przykładowy projekt kodu dotyczy w szczególności adresów, Co Working UIs and Continuous Clientsktóre wydają się dokładnie tym, co próbujesz zrobić.

Aplikacje internetowe New Age mogą potrzebować zaoferować użytkownikom nowe doświadczenia - i powinny odpowiednio obsługiwać scenariusze współpracy i ciągłego klienta. Wiąże się to z zapewnieniem, że interfejs użytkownika poprawnie synchronizuje się między urządzeniami i użytkownikami, aby zapewnić utrzymanie stanu aplikacji i interfejsu użytkownika „tak jak jest”.

Ten post na blogu wydaje się być punktem wyjścia do serii postów na blogu omawiających użycie dwóch pakietów i kontrastuje to z tradycyjnym podejściem do platformy ASP.NET. Może zapewnić pewne punkty do rozważenia podczas projektowania witryny.

Ten blogu wydaje się być trochę bardziej podstawowe i dostarcza podstaw do łączenia dwóch pakietów.

Ujawnienie: Nie jestem powiązany z żadnym z powyższych linków, ani też nie zagłębiłem się w ich treść, aby zobaczyć, czy jest to poprawne lub poprawne.


źródło
2

Rozwiązaniem jest transformacja operacyjna (OT). Jeśli o tym nie słyszałeś, OT jest klasą algorytmów, które wykonują współbieżność w czasie rzeczywistym dla wielu witryn. OT jest jak git w czasie rzeczywistym. Działa z dowolnym opóźnieniem (od zera do przedłużonego urlopu). Umożliwia użytkownikom dokonywanie bieżących, równoczesnych edycji przy niskiej przepustowości. OT zapewnia ostateczną spójność między wieloma użytkownikami bez ponownych prób, bez błędów i bez nadpisywania danych.

Ale wdrożenie OT jest trudnym zadaniem i czasochłonnym. Możesz więc skorzystać z zewnętrznej biblioteki, takiej jak http://sharejs.org/ .

aj_
źródło
1
Google Realtime API robi OT youtu.be/hv14PTbkIs0?t=14m20s Robią to zarówno na kliencie, jak i na serwerze. Nie udało mi się uzyskać jasnej odpowiedzi po przeczytaniu dokumentów ShareJS, ale zakładam, że ShareJS działa OT na kliencie i serwerze?
dev.e.loper
1

Zależy to głównie od rodzaju dokumentów i sposobu współpracy użytkowników.

Chciałbym jednak:

  1. pozwól wszystkim klientom wysyłać niezapisane zmiany na serwer co jakiś czas (zależy od tego, jak użytkownicy pracują z dokumentami).
  2. serwer przechowuje delty w sesji użytkownika (nawet dla grubego klienta potrzebujesz czegoś takiego jak sesja)
  3. inni klienci edytujący / przeglądający ten sam dokument otrzymują te tymczasowe zmiany lub przynajmniej wskazówkę, że tak może być.

Zalety:

  • brak aktualizacji DB, chyba że ktoś kliknie „zapisz”
  • kopia zapasowa na wypadek awarii klienta (na okres sesji)
  • Twój serwer decyduje, w jaki sposób i jakie dane przekazać do którego klienta (np. możesz szybko uruchomić tę funkcję za pomocą notatki, a później wdrożyć bardziej wyrafinowane scalanie i wyróżnianie)

Niedogodności:

  • nie „w czasie rzeczywistym” - np. wysyłasz co 30 sekund, ale ktoś pisze 3 zdania w tym czasie.
  • większy ruch w sieci - w zależności od dokumentów i współpracy
  • ewentualnie duże sesje
  • prawdopodobnie duży wysiłek obliczeniowy, jeśli wielu użytkowników współpracuje i wprowadza wiele zmian
Andy
źródło
1

Zasadniczo pytasz, jak radzić sobie ze współdzielonym stanem zmiennym. Oszczędzanie jest łatwą częścią; ale jak radzisz sobie z wieloma osobami edytującymi to samo w tym samym czasie? Chcesz, aby wszyscy użytkownicy przeglądali ten sam dokument podczas synchronizacji jednoczesnych edycji, wszystko w czasie rzeczywistym.

Jak zapewne się zebraliście, jest to trudny problem! Istnieje kilka pragmatycznych rozwiązań:

  1. Zmodyfikuj wymagania aplikacji, aby nie dopuszczać prawdziwej jednoczesnej edycji. Edycje można łączyć jak w systemach kontroli źródła, a wyniki są przekazywane do każdego klienta. Możesz zbudować to sam, ale byłoby to gorsze doświadczenie użytkownika.
  2. Outsourcing synchronizacji mutacji stanu do rozwiązania typu open source, które integruje się z istniejącą technologią. ShareDB jest aktualnym liderem w tej dziedzinie. Opiera się na transformacji operacyjnej i jest wykorzystywany w co najmniej jednym systemie produkcyjnym. Zapobiegnie to problemowi związanemu z zapisywaniem, ale nie pomoże żadna z dodatkowych funkcji UX obowiązkowych dla dowolnej aplikacji współpracującej.
  3. Użyj gotowej platformy, takiej jak Convergence (zastrzeżenie: jestem założycielem), aby poradzić sobie z wszystkimi trudnymi zagadnieniami. Dostaniesz również dodatkowe narzędzia do współpracy w czasie rzeczywistym, takie jak śledzenie kursora / myszy, wybory i czat, aby szybko uzyskać lepszą współpracę. Zobacz to pytanie, aby uzyskać dobry przegląd wszystkich istniejących narzędzi.
Alalonde
źródło