Zapytałem, jakie jest teraz pytanie usunięte przez społeczność na temat SO, dlaczego ktoś miałby używać skryptu javascript Promise.race
, a użytkownik z wysokim przedstawicielem skomentował to:
Jeśli masz dwie usługi, które obliczają pewną wartość, możesz przesłać do nich zapytanie równolegle i użyć tej, która zawsze zwróci najpierw wartość, zamiast zapytania o jedną, czekając na awarię, a następnie sprawdzając drugą.
Znalazłem się na temat redundancji i ogólnie tego przypadku użycia, ale nic nie mogłem znaleźć, a z mojego POV nigdy nie jest dobrym pomysłem, aby po prostu dodać obciążenie do serwera / usługi, jeśli nie zamierzasz użyć odpowiedzi.
programming-practices
Adelina
źródło
źródło
Odpowiedzi:
Twierdziłbym, że jest to bardziej kwestia ekonomiczna. Jest to jednak wezwanie do osądu, które inżynierowie powinni być w stanie wykonać. Dlatego odpowiadam.
Podzielę swoją odpowiedź na cztery części:
Zarządzanie ryzykiem
Czasami więc twój klient nie otrzymuje odpowiedzi z serwera. Zakładam, że nie dzieje się tak z powodu błędu programowego (w przeciwnym razie rozwiązaniem jest naprawa, więc zrób to). Zamiast tego musi to wynikać z sytuacji losowej, na którą nie masz wpływu ...
Ale nie poza twoją wiedzą. Musisz wiedzieć:
Na przykład, jeśli awaria i ponowna próba zdarzają się tylko w około 2% przypadków, prawdopodobnie nie warto tego robić. Jeśli zdarzy się to w 80% przypadków, cóż ... zależy ...
Ile czasu musi czekać klient? A jak to przekłada się na koszty ... Widzisz, masz niewielkie opóźnienie w regularnej aplikacji, to chyba nie jest wielka sprawa. Jeśli jest to znaczące, a masz aplikację czasu rzeczywistego lub grę online, odstraszy to użytkowników i prawdopodobnie lepiej inwestować w więcej lub lepsze serwery. W przeciwnym razie prawdopodobnie możesz umieścić komunikat „ładowanie” lub „czekanie na serwer”. O ile opóźnienie nie jest naprawdę duże (rzędu dziesiątek sekund), może być zbyt duże nawet w przypadku zwykłej aplikacji.
Strategie
Jak powiedziałem powyżej, istnieje więcej niż jeden sposób rozwiązania tego problemu. Zakładam, że masz już implementację pętli try-fail-retry. Zobaczmy więc ...
Zauważ, że mówię, że nadal mogą się nie powieść. Jeśli założymy, że zapytanie do serwera ma 80% szansy na awarię, to równoległe zapytanie do dwóch serwerów ma 64% szansy na niepowodzenie. W związku z tym nadal możesz spróbować ponownie.
Dodatkową zaletą wyboru szybszego serwera i korzystania z niego jest to, że szybszy serwer jest mniej podatny na awarie z powodu problemów z siecią.
Co mi przypomina, jeśli możesz dowiedzieć się, dlaczego żądanie się nie powiedzie, zrób to. Pomoże ci to lepiej zarządzać sytuacją, nawet jeśli nie możesz zapobiec awariom. Na przykład, czy potrzebujesz większej prędkości transferu po stronie serwera?
Trochę więcej:
A kto powiedział, że musisz zrobić tylko jedną z nich? Możesz umieścić komunikat ładowania, wysłać zapytanie do wielu serwerów rozmieszczonych w folderze Wrold, aby wybrać szybciej i używać go tylko odtąd, po ponownym niepowodzeniu w pętli, a każdy z tych serwerów może być klastrem maszyn z równoważeniem obciążenia . Dlaczego nie? Cóż, kosztuje ...
Koszty
Istnieją cztery koszty:
Musisz je zrównoważyć.
Powiedzmy na przykład, że zarabiasz około dolara na zadowolonego użytkownika. Że masz 3000 użytkowników dziennie. Że żądania kończą się niepowodzeniem przez około 50% czasu. I że 2% użytkowników wychodzi bez płacenia, gdy żądanie nie powiedzie się. Oznacza to, że tracisz (3000 * 50% * 2%) 30 dolarów dziennie. Teraz powiedzmy, że opracowanie nowej funkcji będzie kosztować 100 dolarów, a wdrożenie serwerów będzie kosztować 800 dolarów - i zignorowanie kosztów środowiska wykonawczego - oznacza to, że uzyskasz zwrot z inwestycji w ((100 + 800) / 30 ) 30 dni. Teraz możesz sprawdzić swój budżet i zdecydować.
Nie uważaj tych wartości za reprezentatywne dla rzeczywistości, wybrałem je ze względu na matematykę.
Dodatki:
Chodzi o to, że jeśli weźmiesz pod uwagę problem związany z równoważeniem kosztów, możesz oszacować koszt rozważanych strategii i użyć tej analizy do podjęcia decyzji.
Intuicja
Intuicja, jeśli jest wspierana przez doświadczenie. Nie sugeruję przeprowadzania tego rodzaju analiz za każdym razem. Niektóre osoby tak robią i to jest w porządku. Sugeruję, abyście trochę to zrozumieli i wypracowali intuicję.
Ponadto w inżynierii, oprócz wiedzy, którą zdobywamy z faktycznej nauki, uczymy się również w praktyce i opracowujemy wytyczne dotyczące tego, co działa, a co nie. Dlatego często mądrze jest zobaczyć aktualny stan techniki ... chociaż czasami trzeba zobaczyć poza swoim obszarem.
W takim przypadku patrzyłbym na gry wideo online. Mają ekrany ładowania, mają wiele serwerów, wybiorą serwer na podstawie opóźnienia, a nawet mogą zezwolić użytkownikowi na zmianę serwerów. Wiemy, że to działa.
Sugerowałbym to zrobić zamiast marnować ruch sieciowy i czas serwera na każde żądanie, należy również pamiętać, że nawet w przypadku nadmiarowego serwera może wystąpić awaria.
źródło
Jest to do przyjęcia, jeśli czas klienta jest cenniejszy niż czas na serwerze.
Jeśli klient musi być szybki i dokładny. Możesz uzasadnić zapytanie do kilku serwerów. I dobrze jest anulować żądanie, jeśli otrzymana zostanie prawidłowa odpowiedź.
Oczywiście zawsze mądrze jest skonsultować się z właścicielami / menedżerami serwerów.
źródło
Ta technika może zmniejszyć opóźnienia. Czas odpowiedzi serwera nie jest deterministyczny. W skali prawdopodobnie istnieje co najmniej jeden serwer wykazujący słabe czasy odpowiedzi. W związku z tym wszystko, co korzysta z tego serwera, również będzie miało słabe czasy odpowiedzi. Przesyłając do kilku serwerów, zmniejsza się ryzyko rozmowy ze słabo działającym serwerem.
Koszty obejmują dodatkowy ruch w sieci, zmarnowane przetwarzanie serwerów i złożoność aplikacji (sądzono, że można to ukryć w bibliotece). Koszty te można zmniejszyć, anulując nieużywane wnioski lub czekając krótko przed wysłaniem drugiego żądania.
Oto jeden papier , a inny . Pamiętam też, jak czytałem gazetę Google, ich implementację.
źródło
W większości zgadzam się z innymi odpowiedziami, ale uważam, że powinno to być niezwykle rzadkie w praktyce. Chciałem podać znacznie bardziej powszechny i rozsądny przykład tego, kiedy chcesz go użyć
Promise.race()
, coś, z czego zdarzyło mi się korzystać kilka tygodni temu (cóż, odpowiednik Pythona).Załóżmy, że masz długą listę zadań, z których niektóre mogą być uruchamiane równolegle, a niektóre muszą być wykonywane przed innymi. Możesz rozpocząć wszystkie zadania bez żadnych zależności, a następnie poczekać na tej liście za pomocą
Promise.race()
. Po zakończeniu pierwszego zadania możesz rozpocząć dowolne zadania zależne od tego pierwszego zadania iPromise.race()
ponownie na nowej liście w połączeniu z niedokończonymi zadaniami z oryginalnej listy. Powtarzaj, aż wszystkie zadania zostaną wykonane.Uwaga Interfejs API JavaScript nie jest do tego idealnie zaprojektowany. To właściwie absolutne minimum, które działa i musisz dodać sporo kodu kleju. Chodzi mi jednak o to, że takie funkcje
race()
są rzadko używane do nadmiarowości. Są one dostępne przede wszystkim wtedy, gdy naprawdę chcesz uzyskać wyniki wszystkich obietnic, ale nie chcesz czekać na ich spełnienie przed podjęciem kolejnych działań.źródło
new Promise
są wywoływane, i nie są ponownie uruchamiane, gdyPromise.race()
są wywoływane. Niektóre implementacje obietnic są leniwe, ale chętny jest o wiele bardziej powszechny. Możesz przetestować, tworząc obietnicę w konsoli, która loguje się do konsoli. Zobaczysz to od razu. Następnie przekaż tę obietnicęPromise.race()
. Zobaczysz, że nie loguje się ponownie.Oprócz względów technicznych możesz zastosować to podejście, gdy jest ono częścią twojego rzeczywistego modelu biznesowego.
Odmiany tego podejścia są stosunkowo częste w licytowaniu reklam w czasie rzeczywistym . W tym modelu wydawca (dostawca przestrzeni reklamowej) poprosi reklamodawców (dostawców reklam) o licytację za wyświetlenie określonego użytkownika. Zatem dla każdego takiego wyświetlenia zapytaj każdego z subskrybowanych reklamodawców, wysyłając zapytanie ze szczegółami wyświetlenia do punktu końcowego dostarczonego przez każdego reklamodawcę (lub alternatywnie, skrypt dostarczony przez reklamodawcę działający jako punkt końcowy na twoich serwerach), ścigając się wszystkie te żądania do limitu czasu (np. 100 ms), a następnie przyjęcie najwyższej oferty, ignorując pozostałe.
Szczególną odmianą tego, która pomaga skrócić czas oczekiwania klienta, jest umożliwienie wydawcy dopuszczenia minimalnej wartości celu dla oferty, tak że pierwsza oferta reklamodawcy, która przekroczy tę wartość, zostanie natychmiast zaakceptowana (lub, jeśli żadna z ofert nie przekroczy wartość, zostanie pobrana maksymalna). W tym wariancie pierwsze zapytanie przychodzące może wygrać, a drugie odrzucone, nawet jeśli są tak dobre lub nawet lepsze.
źródło