Piotr
Jasiulewicz
PHP/Java
professional
Temat: Prosba o podpowiedz w sprawie projektu systemu rozproszonego
Czesc,chcialbym zaciagnac troche wiedzy madrzejszych ode mnie, odnosnie projektu architektonicznego systemu, ktorego budowa zostala mi powiezona.
Jest w trakcie projektowania (a w zasadzie przeprojektowywania) systemu sluzacego do oceniania. Stary system napisany byl w PHP/Mysql, co raczej bylo spowodowane potrzeba szybkiego posiadania prototypu, niz czyjas zlowrogoscia. O ile nie bylo to zbyt dobra decyzja, kod wyglada jak Perlowa miazga, bez slowa komentarza, pozwolilo to na spostrzezenie wielu potencjalnych problemow.
System sluzy do oceniania prac, w zasadzie jest jednym duzym silnikiem statystycznym, z niestety niepodzielnym (w wiekszej czesci) algorytmem obliczeniowym. Czesc akgorytmu wymaga pewnego sposobu dodawania danych do systemu, w ktorym aplikacja, uzywana przez Sedziow (osoby oceniajace) wysyla kazdorazowo zapytanie do systemu poprzez API, jaka to prace ma nastepnie oceniac, Efekt tejze oceny jest zwracany rowniez przez API. Wszystko byloby fajnie, oprocz tego, ze ma byc to przygotowane na pokazne ilosci:
- 100k+ prac ocenianych
- API potrzebne do komunikacji (dodawanie prac, sedziow, ocenianie, okreslanie co oceniac, raportowanie), zapewne prosty JSON, moze tez XML (ale preferowalbym to pierwsze)
- 10-20k sedziow, przy jednym ocenianiu, czyli duzo requestow do API
- algorytm jest dosc wolny pod wzgledem tego, ze ma zlozonosc obliczeniowa O(x*(n^n)), wiec widzlalem juz szybsze... aczkolwiek podczas takiej pelnej oceny 100 tys prac, wystarczy zeby byl obliczony z 10-20 razy, tyle, ze w odstepach godzin/dni.
Kolejnym problemem sa dane, ladowanie kilkuset tys elementow (prace, oceny itd) nawet z pliku do pamieci, budowanie struktury i obliczanie na zawolanie nie wchodzi w gre, bo trwalo by to zbyt dlugo. Jedna z problematycznych elementow odnosnie algorytmu, to to, ze jak juz bedzie musial byc obliczony to raz na pare dni, ale w ciagu paru (nastu) sekund max (poniewaz blokuje to wszystko inne, jak ocenianie). Tak wiec dane musza byc wszystkie w pamieci caly czas. Calosc musi tez wisiec w pamieci dosc dlugo (tydzien-miesiac).
Doswiadczenie podpowiada mi aby zabrac sie za to bardzo szczegolowo i uwaznie, ze wzgledu na dosc zroznicowane problemy na poszczegolnych etapach architektury, jakie mozna sobie stworzyc.
Z punktu widzenia samej budowy architektury aplikacji, Event Sourcing wydaje mi sie odpowiednia opcja, jako, ze posiadajac wszelkie eventy oraz stan podstawowy, bede mogl bez problemu "doliczyc sie" do kazdego dowolnego stanu oraz latwo rozeslac informacje w postaci zdarzen na dowlona ilosc maszyn. Wszystkie eventy beda musialby byc tez gdzies zserializowane sekwencyjnie per jakis klucz (moze column data store).
1 Pomysl
- szereg maszyn API, ktore jednoczesnie komunikuja sie z jakims storagem danych (pewnie uzyje Amazon DynamoDB) oraz wysylaja eventy do maszyn obliczeniowych oraz bioracych z nich pewne informacje
- szereg maszyn obliczeniowych, na ktorych "wisi" sobie cala informacja w pamieci i jest obczliana jednoczesnie
- load balancer nie-proxy, ktory bedzie mogl instruowac serwery o wzajemnym polozeniu i stanie
- do dzielenia eventow API przychodzacego (nie wymagajacego odpowiedzi zwiazanej ze stanem systemu) mozna uzyc RabbitMQ albo ZeroMQ
Ma to plus bycia przejrzystym, mozna tez ocenic szybko stan poszczegolnych maszyn, wiadomo gdzie to jest. Czesc z maszynami API, oczywiscie dosc latwo sie skaluje, Komunikacja jedyni API<->obliczeniowe. Rozwiazany jest tez problem z redundancja, - prawdopodobnie nigdy nie bedzie trzeba odnawiac calosci obliczen, przy 3+ maszynach chodzacych. Ma tez jednak minusy:
- wszystkie maszyny obliczeniowe musialyby przeprowadzac obliczenia (czasem to jest zbedne, szczegolnie, gdy mamy do czynienia z malymi sesjami oceniania) - potencjalnie sporo mocy sie marnuje, wystarczyloby zeby 2-3 razy przeprwadzac to samo
- ciezko skalowac maszyny obliczeniowe
- MQ maja bardzo duze wydajnosci (przynajmneij jak na moje potrzeby), latwo sie je klastruje oraz potrafia zrzucac wszystko na dysk dla bezpieczenstwa
Mam tez pomysl inny, troche bardziej "cudowny", chodz chcialbym uslyszec Wasze zdanie odnosnie obu.
2 Pomysl
System z "bladzacym" systemem obliczeniowym:
- Maszyny jednoczenie obsluguja API oraz potencjalnie czesc obliczeniowa
- kazdy event w systemie trzymany jest w jakims wspoldzielonym gridzie pamieci, aczkolwiek tez gdzies serializowany (grupowo jakos raczej, niz pojedynczo)
- w kazdej chwili na podstawie polecenia, system moze "postawic" aktualny stan systemu obliczeniowego na ktorejs z maszyn oraz wspoldzielic go innym maszynom
- load balancer middle tier (za tym internet facing ktory uznalem za oczywisty) wewnetrzny non-proxy - informacje cos sie dzieje na jakiej maszynie i gdzie kierowac zapytania
Plusy:
- latwiejsze do skalowania, maszyny obliczeniowe mozna "stawiac" automatycznie pod obciazeniem na kazdej dowolnej maszynie
- redundancja opcjonalnie wysoka
Minusy:
- trudniej wydzielic maszyne do konkretnej roboty (jak np serializacja, albo poprostu okreslic, ktora maszyna ma dostac obliczenia) i trzeba sie poslugiwac jakims losowaniem zewnetrznym, zapewne
- troche bardziej pogmatwany dezajn, bardziej skomplikowany kod komunikacji i interakcji z load balancerem i maszynami
Pomysl 3 - cos pomiedzy, czyli maszyny api oddzielnie, trzymajace eventy w gridzie, oddzielni maszyny obliczeniowe, mozliwosc okreslanie ile maszyn ma miec jednoczesnie stan na sobie.
Dajcie znac, co na ten temat myslicie. Moze jakies propozycje implementacji/frameworka (sam myslalem Spring, Vertx+Guice, Scala, gridow zadnych jeszcze nie uzywalem, ale mysle terracotta, vertx uzywa hazelcasta)
Z gory dziekuje :-)
Piotr