Jak zaprojektować wysoce skalowalne usługi sieciowe w Javie?

15

Tworzę usługi sieciowe, które miałyby 2000 równoczesnych użytkowników. Usługi są oferowane za darmo i dlatego oczekuje się, że uzyskają dużą bazę użytkowników. W przyszłości może być konieczne skalowanie do 50 000 użytkowników.

Jest już kilka innych pytań dotyczących tego problemu, takich jak - /programming/2567254/building-highly-scalable-web-services

Jednak moje wymagania różnią się od powyższego pytania.

Na przykład - Moja aplikacja nie ma interfejsu użytkownika, więc obrazy, CSS, javascript nie stanowią problemu. Jest w Javie, więc sugestie takie jak użycie HipHop do tłumaczenia PHP na kod natywny są bezużyteczne.

Dlatego postanowiłem zadać pytanie osobno.

To jest konfiguracja mojego projektu -

  1. Usługi sieciowe oparte na spoczynku przy użyciu Apache CXF
  2. Hibernacja 3.0 (z odpowiednimi optymalizacjami, takimi jak leniwe ładowanie i niestandardowy HQL do dostrojenia)
  3. Tomcat 6.0
  4. MySql 5.5

Jakie są najlepsze praktyki, aby skalować aplikację Java?

Kshitiz Sharma
źródło
Jeśli ujawniasz usługę REST, użycie odwrotnego proxy, takiego jak Varnish, bardzo by pomogło. Jak świeże muszą być dane? Czy na pewno potrzebujesz relacyjnej bazy danych? Czy możesz podzielić dane na partycje? Przy opisywanym stosie technologii skupiłbym się na upewnieniu się, że jak najmniej żądań rzeczywiście trafi do twojego punktu końcowego. Czy zastanawiałeś się nad zrobieniem tego w pamięci dzięki rozwiązaniom takim jak obsada Hazel / Gigaspaces itp.?
ebaxt,
@ebaxt dzięki za sugestie. Gigaspaces wydaje się być open source. Ale obsada Hazel wygląda interesująco.
Kshitiz Sharma,
1
@ebaxt „Czy na pewno potrzebujesz relacyjnej bazy danych?” Przyjęcie nosql miałoby drastyczne zmiany w architekturze aplikacji. Staramy się ograniczyć złożoność do minimum. Koszt nie jest jednak dla nas czynnikiem. Pozostaniemy więc przy relacyjnym podejściu.
Kshitiz Sharma,
1
Możesz używać Postgres, MySQL lub cokolwiek innego. Co z twoją infrastrukturą? Czy umiesz korzystać z macierzy dyskowych? Czy serwery są hostowane w tej samej lokalizacji? Czy możesz połączyć klaster z pulsem itp.? Czy możesz umieścić je w tej samej podsieci?
edze
1
Też jestem programistą. Ale jeśli twoja relacyjna baza danych jest wąskim gardłem, będziesz miał tendencję do kończyć się tymi pytaniami. Na rynku istnieją bazy danych, niektóre działają lepiej niż inne w niektórych sytuacjach. Ale używają różnych domyślnych poziomów izolacji transakcji i optymistycznej współbieżności vs pesymistycznej współbieżności itp.
edze

Odpowiedzi:

8

W przeszłości zajmowałem się tym problemem, ale nadal uważam, że mam wiele do nauczenia się w terenie. Uważam, że jest to jedno z najciekawszych obszarów rozwoju oprogramowania, oto kilka przemyśleń na ten temat:
MySQL jest wystarczająco uczciwą bazą danych, chyba że pracujesz z ogromną ilością danych, aw tym przypadku możesz rozważyć NoSQL baza danych, ale należy dokładnie sprawdzić, która baza danych NoSQL jest najlepsza dla Twoich potrzeb.

Należy wdrożyć buforowanie w systemie - spróbować buforować jak najwięcej danych tylko do odczytu lub zdefiniować niektóre strategie buforowania - na przykład mieliśmy scenariusz, w którym użytkownik widział „stare dane” jako tak długo, jak ostatnia aktualizacja miała miejsce w ciągu ostatniej godziny.
Rozważyłbym JBoss Cache, a może Infinispan (który bardziej przypomina rozproszoną strukturę danych) lub inne popularne ramy buforowania do tego.
Ponadto, jak wspomniałeś tomcat, zakładam, że pracujesz w jakimś module odpowiadającym na żądania. Spróbuj rozważyć użycie pamięci podręcznej, która istnieje w zakresie danego żądania, może to być nawet prosta HashMap powiązana z lokalnym magazynem wątków .
Mój pomysł tutaj przypomina pamięć podręczną pierwszego poziomu w Hibernacji .

Należy pamiętać, że pliki, transakcje i inne zasoby są drogie pod względem utrzymywania ich w stanie otwartym. Upewnij się, że zamykasz pliki i transakcje tak szybko, jak to możliwe, w przeciwnym razie pojawią się błędy, które będą odtwarzane w dużych konfiguracjach

Ponadto musisz zrozumieć, co 2000 równoczesnych użytkowników - czy to oznacza, że ​​2000 użytkowników uzyskuje dostęp do twojego serwera jednocześnie, czy też korzystają z twojego systemu? Rozróżnij przypadki, w których 2000 użytkowników próbuje otworzyć gniazdo na serwerze, a przypadki, w których tylko 500 jest, a 1500 szuka obecnie rezultatów wypełniania danych wejściowych po stronie klienta.

Powinieneś rozważyć użycie klastrowania - będziesz musiał poradzić sobie z takimi problemami, jak równoważenie obciążenia , sesja lepka (co oznacza, że ​​moduł równoważenia obciążenia przekieruje żądanie do tego samego serwera dla tej samej sesji) i więcej.

Jeśli potrzebujesz kodu synchronizacji - ostrożnie wybierz strategię synchronizacji. Widziałem niektóre systemy, w których zastosowano prostą blokadę, ale ReaderWriterLockmógł poprawić, ponieważ większość dostępu była tylko do odczytu.

Rozważ buforowanie i sprawdzanie poprawności po stronie klienta, jeśli to możliwe, spróbuj zapisywać połączenia do serwera i wysyłać tylko różnice danych, na wypadek gdyby większość odpowiedzi na żądanie z tym samym parametrem się nie zmieniła.
Na przykład w projekcie open source oVirt prosimy o uzyskanie statystyk dotyczących danej maszyny wirtualnej. niektóre dane maszyny wirtualnej rzadko się zmieniają, więc wysyłamy tylko MD5, jeśli dane się zmienią, wartość MD5 również ulega zmianie, wykonujemy żądanie uzyskania pełnych danych, a nie tylko MD5.

Wspomniałem wcześniej o hibernacji - chciałbym ponownie rozważyć użycie go - jeśli chcesz wykonać wiele zapisów i mniej odczytów, Hibernacja może nie być dla Ciebie idealna i powinieneś rozważyć pracę z Spring-JDBC jako opakowanie JDBC.

Mądrze zindeksuj bazę danych i użyj poprawnego schematu db. Zastanów się nad użyciem warstwy procedur przechowywanych, ponieważ są one wstępnie skompilowane i zoptymalizowane.

Chciałbym powiedzieć, że w przeszłości miałem do czynienia z systemem (jednym węzłem) na mysql (głównie dostęp tylko do odczytu) z jboss 4.2.1 i udało mi się osiągnąć 2000 równoczesnych użytkownicy
(nie uzyskując natychmiastowego dostępu do otwierania 2000 gniazd na naszym serwerze), ale używając / przeglądając nasz system, używając JBoss Cache i wstępnie ładując do pamięci podręcznej niektóre najczęściej używane dane lub dane, które zdaliśmy sobie sprawę, będą „gorące i popularne „ale nasze rozwiązanie było dobre dla naszej architektury i naszych przepływów,
więc, jak mówię, w tych przypadkach -
Jest więcej wskazówek i wskazówek, ale tak naprawdę zależy to od architektury i przepływów, które musisz mieć w systemie. Powodzenia!


źródło
Zgadzam się, z wyjątkiem przechowywanych procesów, nie używaj przechowywanych procesów. I możesz użyć współbieżnych wartości
skrótów
3

Dobre pytanie. Prawdopodobnie trudno powiedzieć, które podejście jest najlepsze, ale spróbuję z mojego doświadczenia.

Najlepszym sposobem na skalowanie aplikacji internetowej opartej na Javie jest napisanie jej tak bezstanowo, jak to możliwe (jeśli to możliwe). Umożliwia to skalowanie w poziomie aplikacji, do której można dodać serwery tomcat, jeśli jest więcej współbieżnych użytkowników.

Jednak, jak zauważyłeś, może występować problem z połączeniami z bazą danych. Ale mam pytanie, w jaki sposób otrzymujesz dane? Czy jest generowany przez użytkownika, czy otrzymujesz dane od strony trzeciej? Jest to bardzo ważne, ponieważ jeśli świadczysz usługę dla użytkownika z danymi zebranymi z aplikacji innej firmy (np. FB, Twitter itp.), Możesz śledzić zapisywanie w bazie danych master i replikowanie danych do baz danych slave które są przydzielane do każdej instancji tomcat. Następnie każdy serwer tomcat może uzyskać z własnej bazy danych slave.

 Are there faster alternatives to Mysql?

Możesz przejść do klastra MySQL, który ma magazyn danych w pamięci. Ale uwaga na to, że aplikacja może wymagać pewnych zmian. Nie sql joinssą dobrze obsługiwane w klastrze MySQL, chociaż w najnowszej wersji wprowadzono ulepszenia tego samego. Jeśli koszt nie jest czynnikiem, możesz wypróbować Oracle.

Rozwiązanie buforowania zdecydowanie poprawi wydajność. Ale wszystko zależy od architektury całej aplikacji. Powinieneś dobrze wiedzieć, kiedy przesłać dane do pamięci podręcznej, a kiedy je zabrudzić (usunąć z pamięci podręcznej).

Jeśli chodzi o rozkład obciążenia w środowisku wieloserwerowym, sugerowałbym użycie równoważenia obciążenia niż użycie Apache do równoważenia obciążenia.

Chandra
źródło
„Sugerowałbym, abyś używał modułu równoważenia obciążenia niż używał Apache do równoważenia obciążenia” Jakie podejście / oprogramowanie sugerowałbyś, gdyby nie Apache?
Kshitiz Sharma,
Zasadniczo zalecałem sprzęt do równoważenia obciążenia, który administrator sieci powinien móc skonfigurować. Ta oferta ma dodatkowy koszt dla projektu. Ten moduł równoważenia obciążenia będzie miał swój własny adres IP (zwany także wirtualnym adresem IP) i zasadniczo będziesz przypisywać ten adres IP do swojej domeny. Gdy nadejdzie żądanie, przekieruje je do wszystkich podłączonych serwerów w trybie round robin (także innych dostępnych algorytmów). Możesz użyć apache do tego celu, jeśli sprzęt nie jest opcją, ale wolałbym sprzęt, ponieważ nie musisz dostrajać apache tylko do tego celu.
Używamy dedykowanego serwera z httpd, aby zrobić to samo. Sprzęt nie stanowi problemu.
Kshitiz Sharma,
Możesz użyć httpd i mod_cluster, jeśli dobrze pamiętam. Zastanowię się dokładnie, zanim przejdę do rozwiązania „nadmiernej liczby” sprzętowego LB, przed sprawdzeniem httpd i mod_cluster
@zaske - Prawdopodobnie masz rację, że sprzętowy moduł równoważenia obciążenia może być przesadą. Ale w razie potrzeby skalowania można to łatwo zrobić, dodając więcej serwerów.
2

Obecnie konfiguruję podobny system (na poziomie profesjonalnym) i taki projekt wybrałem:

  • Dwa równoważniki obciążenia Nginx (oba aktywne, oba przełączanie awaryjne dla drugiego, zrównoważone za pomocą okrągłego robina DNS)
  • Dwie bazy danych MySQL w trybie master master replikacji
  • Dwie instancje Tomcat jako klaster tomcat
  • Dwie instancje Memcached dla buforowania i udostępniania stanu sesji dla klastra Tomcat

Pozwoli to uzyskać nadmiarowe, skalowalne rozwiązanie o wysokiej dostępności.

Loadbalancery (na przyzwoitym sprzęcie) z łatwością wyrównają nasycenie nasyconej linii 1 Gb / s każda. Jest to również świetne miejsce do odciążania SSL.

Możesz zapisać informacje o sesji w memcached. W przypadku awarii instancji tomcat inna instancja tomcat może pobrać odpowiednie informacje o sesji, a klienci nic nie zauważą. Nie zapomnij też połączyć tego z lepkimi sesjami. (Aby ograniczyć ruch w sieci)

Klastrowanie Tomcat ma również opcję udostępniania informacji o sesji między klastrami w czasie rzeczywistym, bez korzystania z memcached. Chociaż myślę, że pod względem wydajności, używanie Memcached będzie lepsze.

Jeśli potrzebujesz więcej mocy w którejkolwiek z tych aplikacji:

  • Nginx: Dodaj więcej modułów równoważących obciążenie, chociaż nie sądzę, że wkrótce będzie to wąskie gardło.
  • Tomcat: możesz łatwo zwiększyć rozmiar klastra Tomcat lub dodać więcej klastrów
  • MySQL: dodaj kilka urządzeń podrzędnych tylko do odczytu lub zwiększ rozmiar klastra (w zależności od aplikacji, ale ponieważ napisałeś aplikację opartą na REST, nie powinno to stanowić problemu)
  • Memcached: dodaj więcej węzłów, Memcached skaluje się całkiem dobrze, jak sądzę.

Nie wiem, jak tworzona jest aplikacja i jakie są duże zasoby zasobów, ale jeśli zauważysz duże obciążenie bazy danych (podczas testów ładowania!), Dodanie pamięci podręcznej między aplikacją a bazą danych może z pewnością znacznie poprawić wydajność. Ale nie zapominaj, że nie wszystko jest możliwe do buforowania, jeśli twoje zapytania są zawsze inne, buforowanie nie pomoże (dużo)

Radzę pobrać VMware Workbench (lub oprogramowanie do wirtualizacji similair) i spróbować stworzyć prostą konfigurację. Bez równoważenia obciążenia i grupowania, tylko podstawy i praca stamtąd. Jeden po drugim dodaj kolejne funkcje (równoważenie, buforowanie, klastrowanie itp.) I upewnij się, że przeprowadziłeś badania na każdy temat, abyś wiedział, że dokonałeś właściwego wyboru.

Jeśli nadal będziesz przeprowadzać te same testy wydajności podczas tego procesu, możesz sam przekonać się, czy użycie X jest lepsze niż użycie Y w konfiguracji lub jaki wpływ będzie miało buforowanie itp.

Ostatecznie taka konfiguracja naprawdę zależy od wymagań aplikacji i jej klientów, wszystko można zrobić na różne sposoby, każdy z własnymi mocnymi i słabymi stronami.

Jakieś pytania?

Powodzenia!

Wesley

Wesley
źródło
laskowe? hazelcast.com
NimChimpsky
Czy używasz frameworka dla warstwy buforującej, czy tylko kilka ręcznych skrótów w zapytaniach SQL?
djechlin