Niepotrzebne wycieczki do serwera?

0

Mamy serwer bazy danych, serwer aplikacji, i klienta, standardzik. Serwer aplikacji korzysta z Lucene do szybkiego wyszukiwania. W indeksie leza sobie id i na podstawie zapytan dostajemy liste id, wykonujemy zapytanie do bazy i dostajemy obiekty (oczywiscie stronicowanie itp jest, ale nie o tym tutaj). Te wyniki wysylane sa do aplikacji klienckiej, i tam pokazywane w stronach.
Teraz uzytkownik ma liste z boku z wynikami, klika na cos na liscie, i w glownej formie pokazuje sie ten obiekt, z ktorym moze robic fiku miku, np go usunac. No i usuwamy. W tym momencie wywolywana jest EJB ktory usuwa z bazy obiekt o takim id, a lista jest akutalizowana. Piknie, tylko troszke wolno mi sie to wydawalo.
No i co sie okazuje - gdy jest usuwane, zaraz po nim wykonywane jest nastepne wywolanie EJB (innego tym razem) ktory ponawia wyszukiwanie. Te wyniki sa pokazywane znowu na liscie, przy czym lista jest pomniejszona o poprzedni element (czyli jak bylo 10, 1 usuniety, to pokazane jest pozostale 9).
To wszystko wymaga wycieczki do serwera, ktory moze byc daleko, a serwer aplikacji i bazy danych tez sa najczesciej (u nas) osobne. Czyli troszke moze to potrwac.
Alternatywa jest po prostu wywalic dany obiekt z listy ktora ma klient jak uda sie usunac z bazy - bez ponawiania wyszukiwania. Zaproponowalem takie male usprawnienie, ale spadla na mnie fala krytyki. Podstawowy zarzut to taki ze Lucene i jej indeks sa super szybkie i przeciez nie ma problemow z wydajnoscia. Nie przemawia to ze sprawdzalismy to na liscie z 3 wynikami, indeks ma 10kb a nie 3gb, i ze wszystko jest lokalnie - i tak bylo widac wyrazne migniecie ekranu na podmianie listy i ulamek sekundy (moim zdaniem za dlugo) poczekac.

Teraz moje pytanie do Was - jak byscie postapili w takim przypadku? Ktore rozwiazanie by byscie wybrali i dlaczego? Moze jest jakis bardzo wazny powod dlaczego opcja ktora akutlanie mamy jest jedyna sluszna, jednak nie przychodzi mi do glowy i nikt nie potrafil takiego przywolac.

Wg mnie sytuacja jest taka - robimy wycieczke na serwer tylko po to aby dowiedziec sie tego co juz sie dowiedzielismy jak user kliknac 'Usun' i metoda usuniecia z bazy wrocila bez bledu - ze ten obiekt nie powinien byc na liscie.

Rozumiem ze przedwczesna optymalizacja to zuo, ale to nie znaczy ze trzeba byc glupim i pizgac na kowboja byle dzielalo, bezmyslnie.

Przepraszam ze tak dlugo i prosze o opinie ;d

0

Przerzuć się na pisanie gier. Wtedy za podejście nr jeden wyleciałbyś z roboty, a za podejście nr 2 miałbyś awans. ;)

0

A co w sytuacji kiedy twój ekran bedzie zawierał dwie listy typu master-slave i usuniecie obiektu master będzie usuwało wiele obiektów slave...

0

No wlasnie - co wtedy? A co ma niby byc? Tak trudno wziac slavy i usunac je z ich listy?
Czysto teoretycznie, bo nie mamy i nie bedziemy mieli takiej sytuacji, lista bedzie zawsze jedna z masterami. Wynika to ze specyfikacji aplikacji. (Tak tak zaraz ktos sie rzuci ze nigdy nie mow nigdy, wiem, wiem. Ale i tak nie widze problemu).

0

Prima Aprilis?

To zalezy od charakterystyki systemu. Jesli glownym przypadkiem uzycia jest pobieranie listy i przegladanie juz istniejacych obiektow, IMO, mozna by sie pokusic o dodanie wspomnianej optymalizacji.
Natomiast jesli przewiduje sie czeste modyfikacje takiej listy (tj. dodawanie/usuwanie obiektow), to pojawia sie problem synchronizacji bazy danych z aktualnym stanem po stronie klienta.
Zakladajac przypadek: kilku klientow, w tym samym czasie, modyfikuje liste obiektow. Pozostali beda musieli "recznie" odswiezyc dane, zeby zobaczyc zmiany, wprowadzone przez innych. W przeciwnym razie beda probowali odwolac sie do obiektow, ktore juz nie istnieja (tutaj pojawia sie inna kwestia, tj. obslugi tego typu bledu) albo w ogole nie beda wiedziec, ze istnieja nowe obiekty. Tak wiec "wycieczka do serwera" i tak bedzie potrzebna.

0

Obiekty dodawane nie zmianiaja listy, poniewaz trzeba by sprawdzic czy nowy obiekt spelnia kryteria wyszukiwania, a latwo to sie da zrobic tylko dla * - w przeciwnym wypadku musisz zaimplementowac to co robi Lucene. Podobnie edycja obiektu - nie zmiena listy z dokladnie tego samego powodu. Mozna powiedziec ze wyszukiwanie to tylko punkt startowy.

Co to kilku klientow to dziala to tak, ze wszyscy wpisuje te same kryteria, i dostaja wyniki - jeden usuwa to, inny tamto, inny costam edytuje itp - nie zmienia to listy, dopiero jawne ponowne zapytanie pokaze zmiany wszystkich. Jesli jednoczesnie jeden cos edytuje, inny to samo usuwa, to ten co edytuje dostanie informacje ze edytowal obiekt ktorego juz nie ma, i pytanie co zrobic itp. Podobnie z rownoleglymi updatami - obslugujemy merge, calkiem fajnie to zrobione. Wszystko zaimplementowane uzywajac zadnej magii, tylko zwyklego podejscia optymistic locking z wersjonowaniem obiektu.

Przy okazji, chyba mozna tu zauwazyc niekonsekwencje - dodanie obiektu lub jego edycja nie zmienia wynikow wyszukiwania, natomiast usuniecie ponawia wyszukiwanie i ta liste zmiena - mozliwe ze ponowne zapytanie calkowicie zmieni liste.

To ze mamy taki a nie inne wsparcie dla rownoleglego przetwarzania wynika z designu i tak ma podobno byc i juz. Z aktualizowaniem listy juz napisalem ze trzeba umiec sprawdzic czy nowy / edytowany obiekt spelnia kryteria, a do tego trzeba by miec Lucene na kliencie - pewnie ze sie da, mozna zrobic tymczasowy malutki indeks in-memory z tym jednym obiektem i na nim zrobic zapytanie i mozna sie dowiedziec - ale to nie ma tak dzialac, i juz.

Co do wycieczki - mozliwe ze czasami bedzie potrzebna, ale czy nie lepiej robic to tylko wtedy gdy rzeczywiscie jest? Patrzac po ankiecie (proba baardzo niereprezentatywna 5 osobnikow ;d) wnioskuje ze jednak sie myle i musze przemyslec. Albo po prostu to prawda ze javowcy maja w dup|e takie zagwostki?

0

Rozwiązanie może składać się z takich składników:

  1. Super system do keszowania zapytań.
  2. AJAXowe odświeżanie widoku w kółko co np 5 sekund. Najlepiej zrobić coś stylu Comet - jedno połączenie którego nie zrywasz.
  3. Obliczanie hasha dla każdego wiersza i przesyłanie tylko tych wierszy dla których hasz się zmienił.
  4. Dodanie/ usunięcie/ zedytowanie etc powoduje natychmiastowe odświeżenie. Dodatkowo można zrobić kolejkę zapytań - jeżeli ktoś zbyt dużo naklika naraz, np pousuwa dziesięć rekordów. Przydałby się tutaj mały bufor na zapytania + łączenie zapytań, np łączenie usuwań.

Kopiowanie funkcjonalności strony serwerowej po stronie klienta to wg mnie samobójstwo. Zbyt dużo stresu z synchronizowaniem aktywności i algorytmów.

0

A czym mozesz przyjac do wiadomosci, ze wlasnie nie ma byc takiego odswiezania? Podobno jest to totalnie nieprzejrzyste dla uzytkownikow, nie mnie to oceniac.
Ponadto, skad Ci przyszlo do glowy ze to ma cokolwiek wspolnego z Ajaxem, ze mozemy uzyc Cometa itp itd? Nie wydaje mi sie zebym to gdziekolwiek napisal. A taki Ajax to jeszcze wiecej durnych wyjazdow na serwer, o ktore sie rozchodzi. A strony z obiektami sa wielkie, poniewaz same obiekty sa wielkie - nie po to usprawnialismy to zeby teraz robic polling z 5 sekundowym odstepem. Sam hashCode rowniez nie wystarcza, powinienes o tym wiedziec.

No nic, wypada mi przeprosic kolegow w poniedzialek bo sie mylilem.

0

Podejście numer 2 to pisanie własnego cache po stronie klienta. Niby fajne i nawet sam czasami stosuję, ale dwie pułapki:

  • dość skomplikowana operacja wyświetlania jeżeli masz kilka zależnych od siebie list. Można rozwiązać za pomocą jakiegoś współdzielonego obiektu z danymi po dtronie aplikacji klienta tak by wszystkie komponenty korzystały z tego samego zbioru obiektów.
  • dość duża losowość przy ponownym wyszukiwaniu.

Żeby to w miarę do ludzi działało, z punktu widzenia klienta, to trzeba by było pokombinować z aktualizacjami w tle. Zatem po stronie klienta w momencie gdy klikasz "Usuń" to obiekt jest usuwany z UI, a w lokalnym repozytorium danych jest oznaczany do odstrzelenia. Jednocześnie chodzi sobie wątek, który wysyła informację na serwer, że obiekt został usunięty. Cała operacja komunikacji zostaje przeniesiona w tło tak, że użytkownik nie musi czekać na jej zakończenie. Podobnie z edycją.
Popatrz jak jest zrobiony git i jego metoda aktualizacji repozytorium "głównego" (czyli umownego miejsca z którego można pobrać aktualny kod np. githuba czy czegoś takiego). Najpierw commit do repo lokalnego, a potem push do głównego.

Co do mania w dupie sprawy związanej z wydajnością, to javowców rozleniwiły interfejsy webowe, które i tak wymuszają wycieczki do serwera.

0
::. napisał(a)

Przy okazji, chyba mozna tu zauwazyc niekonsekwencje - dodanie obiektu lub jego edycja nie zmienia wynikow wyszukiwania, natomiast usuniecie ponawia wyszukiwanie i ta liste zmiena - mozliwe ze ponowne zapytanie calkowicie zmieni liste.

Rozumiem, ze i tak istnieje jakies prawdopodobienstwo, ze klient bedzie operowal na nieaktualnej liscie, jesli w miedzyczasie on lub inni dodadza obiekty i w koncu i tak bedzie musial recznie siegnac do serwera? W takim razie, w chwili obecnej, jedynym argumentem przemawiajacym za odswiezaniem listy podczas usuwania, jest czestotliwosc tej operacji.
Jesli usuwanie bedzie wystepowac odpowiednio czesto (czesciej niz inne operacje), moze sie okazac, ze klient bedzie sie przewalal przez sterte ostrzezen o nieistniejacych obiektach. W przeciwnym razie, odswiezanie listy tylko w przypadku usuwania i tak nie wniesie nic nowego.

Poza tym, trzeba by okreslic jaki jest cel wyszukiwania. Bo jesli klient A dostaje zbior obiektow spelniajacych kryteria "do usuniecia", a klient B w tym samym czasie modyfikuje element z tego zbioru, moze sie okazac, ze A posle do piachu niewinny obiekt. Chyba, ze system przewiduje taka okolicznosc (wersjonowanie?).

0

Dokladnie, obsluguje wersjonowanie. Gdy klienci A i B dostana object X jako wynik, A zmienia go ze juz (potencjanie) nie spelnia kryteriow, gdy B bedzie chcial go usunac dostanie komunikat ze obiekt jest 'out-of-date', dostaje mozliwosc wziecia swojej wersji, wersji z bazy, lub merge.

1 użytkowników online, w tym zalogowanych: 0, gości: 1