Acg N. .
Temat: OpenCPU - krótka historia REST owej aplikacji webowej z R...
Niedawno doradzałem w kwestii projektu serwisu internetowego wykonującego pewne obliczenia i generującego raporty. Obliczenia nie były zbytnio złożone, można by je wykonać w dowolnym języku programowania z odpowiednimi bibliotekami, ale w firmie i tak jest już wykorzystywany R. Raporty miały być generowane w formacie MS Office (Excel i Word - do dalszego przetwarzania, PowerPoint - "podsumowanie dla szefa") oraz "log" w PDF (do archiwum).Padła nieśmiertelna kwestia: "No to jak i w czym to piszemy?". Propozycji było kilka: Java ze Springiem, .NET z ASP.NET MVC, PHP z CodeIgniter albo Kohana. Było Reporting Services, Jasper Reports, a nawet Excel z Sharepointem.
Ponieważ serwis nie był dużych rozmiarów, zaproponowałem: "Napiszcie go R z użyciem HTML i JS. Będzie darmowo, ładnie, RWD (responsywnie) i "niezasobożernie". Zdziwienie było ogromne, "Ale jak to w R? Tak w samym R? A baza danych? A uwierzytelnianie? A generowanie widoków? A.......?".
"Jak to jak? Normalnie" - odpowiedziałem z uśmiechem :)
- Konektory mamy do wszystkich wykorzystywanych przez nas baz danych. Nie mówcie, że wyciągnięcia paru datasetów potrzebujecie ORMa i wzorców repozytorium :)
- Kod R i HTML maksymalnie rozdzielimy na osobne pliki. Nie mamy tutaj oczywiście typowego MVC czy MVP, ale mamy rozdzielenie logiki od widoku, a to już nieźle.
- Generowanie widoków - przecież i tak ma być z założenia statyczne, więc przygotujemy odpowiednie strony HTML dla zapytań i widoków, wykorzystamy do tego jQuery i AJAXa. Aby było responsywnie, wykorzystamy Bootstrap (bo nie macie speca od CSS żeby wam zaprojektował odpowiedni layout "z palca") i jego pakiet "kontrolek" HTMLowych. Mamy tam wszystko co potrzeba. Oczywiście jestem otwarty także na inne frameworki widoku (layout + kontrolki).
- Dokumenty generować będzie eRowy pakiet ReporteRs (pracuje na Javie). Mamy tam wszystko co potrzeba by wygenerować profesjonalnie wyglądające dokumenty, które dodatkowo można otwierać w OpenOffice (OpenXML).
- PDFowy log wygeneruje się "sam" - a to dzięki podejściu reproducible research, wykorzystamy do tego pakiety knitr i pandoc
- uwierzytelnianie - RESTowo. Żadnych "sesji" na serwerze. Wszystko po stronie klienta. Użytkownik podaje login, hasło, serwis zwraca mu token, którym ten się posługuje podczas kolejnych wywołań usług serwisu. Tak naprawdę użytkownik nie musi nawet pamiętać, aby się zalogować, bo jak wykona jakąś akcję nieuwierzytelniony (z pustym tonekem), system sam go przeniesie na stronę logowania.
Wylogowanie? Zamknięcie okna przeglądarki. Zabije to "sesję klienta" i token zostanie utracony
- W ogóle wszystko ma być RESTowo, dzięki czemu nie będziemy się martwić co z "osieroconymi sesjami R na serwerze" (a takie sesje trzymają połączenia do bazy danych, datasety obiekty pomocnicze, załadowane biblioteki) i nie będziemy ich musieli samodzielnie "ubijać" ani martwić się o timeouty - proces R zostanie "ubity" po obsłużeniu zapytania. Każde wywołanie usługi serwisu ma jej dostarczać wszystkiego, czego ona potrzebuje do wykonania zadania, a ona zwróci wyniki. Dzięki temu nie zajedziemy pamięci.
Dla wygody użytkownika, który może zechcieć wrócić do wyników wielokrotnie w ciągu dnia, pójdziemy krok dalej i wprowadzimy niejako "równolegle" pseudosesje, w których będziemy przechowywać wygenerowane wyniki wraz z tokenem. Taka pseudosesja trwać będzie np. 24 godziny i zajmie bardzo mało pamięci, bo raptem tyle, co na wyniki. Pod pojęciem "wyniki" rozumiem nie megabajtowego rozmiaru datasety, tylko finalne tabelki, która mają trafić do dokumentu.
- Wydajność? Tak, tu jest mały szkopuł, bo zamiast mieć jedną sesję R z wczytanymi uprzednio bibliotekami, musimy ją tworzyć za każdym razem. Wczytywanie bibliotek kosztuje. ALE - z drugiej strony nie trwa to długo (raptem sekundę, może 2), a poza tym sama odpowiedź bazy danych na przeciętne zapytanie SQL z waszych raportów trwa dłużej, niż załadowanie procesu R. Użytkownicy nie potrzebują tutaj milisekundowych odpowiedzi, to nie Facebook :]
Jeśli jednak skorzystamy z proponowanego przeze mnie rozwiązania, będziemy mogli skorzystać z opcji "preload", która pozwoli załadować wybrane pakiety do "globalnego cache", co zlikwiduje problem :)
A poza tym jest jeszcze jedna, niezaprzeczalna zaleta podejścia RESTowego. Jeśli R się wysypie (a potrafi się wysypać, podobnie jak Excel, SAS czy dowolny inny program), to nie "zamorduje" wyników innym użytkownikom, którzy może czekali na nie już kilka ładnych minut. Po prostu - padnie proces tego jednego konkretnego użytkownika, reszta będzie sobie pracować dalej. Tego nie da się przecenić.
---
"OK, powiedział jeden z eRowych speców, czyli RApache? Shiny? RServe?"
Nie - pokręciłem głową.
RApache - tak i nie. Sam w sobie jest naprawdę fajny i świetnie
integruje się z Apachem. Co bardzo ważne, wykorzystuje apache2-mpm-prefork, co pozwoli korzystać bezpiecznie i stabilnie z osobnych procesów dla każdego wywołania Niestety, tworzenie aplikacji z użyciem wyłącznie RApache przypomina dawne złe praktyki - mix HTMLa z kodem
R. Do "internetowego reproducible research" nadaje się wspaniale, do prostych aplikacji również, ale do naszych celów - nie. Nie samodzielnie. Użyjemy go jednak "nie wprost", ponieważ jest on wykorzystywany przez rozwiązanie, które podam na końcu.
Shiny - w wersji darmowej uruchamia jedną instancję R per aplikacja. Oznacza to, że bezpiecznie pracować może tylko jeden użytkownik. Jeśli będzie ich więcej - "pogryzą się" wzajemnie. No i nie jest RESTowy. No i nie ma SSLa.
RServe - obsługuje co prawda sesje użytkowników, ale musiałbyś napisać osobnego klienta, np. okienkowego. No i nie jest RESTowy.
Jest tylko jedna opcja: OpenCPU (opis: http://arxiv.org/abs/1406.4806 ) , oparty o wspomniany wcześniej RApache (z apache2-mpm-prefork). Tutaj macie nieco przykładów: https://www.opencpu.org/apps.html
A tutaj piękny przykład separacji widoku od kodu serwisu: https://github.com/opencpu/VisiStat/tree/master/inst/www
Jedna wada: niestety, działa tylko na Linuksie.
"Łe... to mamy stawiać osobną maszynę tylko pod raporty?"
Ależ skąd! Postawimy środowisko robocze na maszynie wirtualnej, a ona sobie chodzić na Windows Server.
Aczkolwiek.... uważam, że TAK, powinniście postawić osobną maszynę do raportów z JEJ WŁASNĄ bazą danych zasilaną z bazy macierzystej za pomocą ciągłej replikacji (albo okresowych snapshotów). Dobrą praktyką jest rozdzielanie serwerów aplikacji, bazy danych i raportowania, ponieważ źle napisane raporty nie "zabiją" wydajnościowo bazy danych głównego oprogramowania ani procesora serwera, który je obsługuje.
...chwila konsternacji...
"Robimy!" :)Ten post został edytowany przez Autora dnia 28.09.15 o godzinie 03:19