Dokumentacja do projektu - Hi, I`m Łukasz Przywarty aka Lucc

Transkrypt

Dokumentacja do projektu - Hi, I`m Łukasz Przywarty aka Lucc
Mariusz Kacała 171058
Wrocław, 25.01.2013
r.
Łukasz Przywarty 171018
Grupa: WT/N 14:15­16:00
Dokumentacja do projektu:
Analiza niezawodnościowa technologii node.js
­ prosta aplikacja webowa.
Projekt został zrealizowany w ramach przedmiotu:
Systemy bezpieczne (i FTC)
Prowadzący:
1
dr inż. Krzysztof Berezowski
1 Cel i założenia
Celem realizacji projektu była analiza niezawodnościowa rozwiązania node.js na
przykładzie prostej aplikacji webowej. Decyzją uczestników projektu zdecydowano o budowie
nieskomplikowanego systemu, który w czasie rzeczywistym odczytuje informacje o tempera­
turze z portu szeregowego. Dane dostarcza platforma Arduino, do której podłączony jest czujnik
temperatury.
2 Realizacja
Aplikacja została napisana w dużej części w języku JavaScript. W tym języku stworzono
skrypty odpowiedzialne za:
●
implementację serwera obsługującego HTTP (biblioteka ­ node.js1 ),
●
odczyt danych z portu szeregowego (pakiet serialport2 ),
●
wyświetlanie stron WWW, obsługę routingu i błędów (pakiety: express3 , jade4 , less5 ),
●
wyświetlanie wykresu z danymi o temperaturze (biblioteka jQuery 6 oraz flot7 ),
●
komunikację z użytkownikiem za pośrednictwem WebSocket’ów (biblioteka socket.io8 ),
●
monitorowanie stanu serwera aplikacji i zapewnianie jego nieustannej pracy (pakiet
forever­monitor9 ).
Podczas przygotowywania projektu korzystano również ze sprzętu:
1
●
platformy Arduino UNO (2 generacja),
●
czujnika temperatury MCP9700­E/TO,
http://nodejs.org/
2
https://npmjs.org/package/serialport
https://npmjs.org/package/express
4
https://npmjs.org/package/jade
5
https://npmjs.org/package/less­middleware
6
http://jquery.com/
7
http://code.google.com/p/flot/
8
https://npmjs.org/package/socket.io
9
https://npmjs.org/package/forever­monitor
3
2
●
diody LED z rezystorem (w celu monitorowania aktywności czujnika temperatury),
●
kabli połączeniowych.
Platforma Arduino programowana jest w języku będącym pochodną AVR C (specjalna
implementacja Arduino).
Rolę serwera aplikacji stanowiły zamiennie:
●
maszyna wirtualna z zainstalowanym systemem Ubuntu 12.04,
●
platforma Raspberry Pi.
2.1 Układ pomiarowy
Układ gromadzący dane dotyczące aktualnej temperatury powietrza został zbudowany
w oparciu o Arduino oraz czujnik temperatury (MCP9700­E/TO). W celach kontrolnych do układu
została dołączona dioda LED, która pulsuje z częstotliwością równą częstotliwości odczytów
temperatury (co 1s). Pozwala to zweryfikować czy czujnik poprawnie odczytuje dane. Sposób
podłączenia układu prezentuje rys. 1.
Rys. 1 Układ mierzący aktualną temperaturę
Czujnik temperatury posiada trzy wyjścia podłączone kolejno (od lewej) do: GND, analogowego
wejścia Arduino ­ A0 oraz portu zasilania 5V. Tak skonstruowany układ został odpowiednio
zaprogramowany.
3
Kod programu zawiera deklaracje zmiennych oraz prędkości transmisji danych portem
szeregowym (9600). Następnie występuja obliczenia odpowiedzialne za konwersję temperatury
do wartości wyrażonej w stopniach Celsjusza (listing 1). Na samym początku zostaje odczytana
wartość z wejścia analogowego. Wartość jest przeliczana na napięcie, czyli mnożona razy 5 a
następnie dzielona przez 1024 (ze względu na to, że napięcie mierzone przez Arduino wynosi
maksymalnie 5V a dokładność przetwornika analogowo­cyfrowego to 10 bitów ­ 1024 wartości).
Wartość temperatury należy również przeskalować odejmując 0,5 stopnia (wynika to z
parametru Output Voltage przy temperaturze 0°C ­ 500mV) oraz dzieląc przez 0,01 (ponieważ
czułość czujnika wynosi 10mV/°C).
Listing 1: Odczyt temperatury oraz wysłanie danych portem szeregowym.
float temperature = analogRead(0)*5/1024.0;
temperature = temperature - 0.5;
temperature = temperature / 0.01;
Serial.println(temperature);
2.2 Aplikacja ­ node.js
Przed rozpoczęciem prac implementacyjnych zespół podjął działania mające na celu
poznanie niskopoziomowego środowiska implementującego JavaScript po stronie serwera jakim
jest node.js. Wyniki zostały umieszczone w prezentacji dołączonej do dokumentu.
Każda aplikacja node.js posiada ustandaryzowaną strukturę. Folder projektowy zawiera
kilka różnych, podrzędnych katalogów:
●
node_modules ­ katalog zawierający pakiety npm, z których korzysta aplikacja
(wymienione w punkcie 2). Każdy pakiet został zainstalowany za pośrednictwem
komendy npm install nazwa_pakietu (niektóre pakiety np. express.js wymagają instalacji
globalnej, z parametrem -g),
●
public ­ główny, publiczny katalog serwera HTTP,
●
routes ­ katalog utworzony przez bibliotekę express.js, wewnątrz którego znajdują się
pliki odpowiedzialne za poprawny routing stron WWW,
●
views ­ katalog zawierający widoki poszczególnych stron WWW.
Dodatkowo w folderze znajduje się:
4
●
katalog arduino-prog, który zawiera kod programu wgrany na platformę Arduino Uno,
●
plik server.js ­ aplikacja serwerowa uruchamiana jako osobny proces, pełni rolę serwera
HTTP, odpowiada za pobieranie danych z portu szeregowego, a także na bieżąco
wysyła zgromadzone dane do użytkowników poprzez WebSocket’y,
●
plik app.js ­ proces monitora serwera, który na bieżąco sprawdza czy aplikacja serwera
jest uruchomiona, jeśli nie, natychmiast uruchamia ją ponownie.
2.2.1 Server.js
Serwer HTTP został napisany przy wykorzystaniu pakietu express.js, który jest dość
rozbudowanym i prostym do nauki frameworkiem aplikacji webowych, inspirowanym projektem
Sinatra (Ruby). Express.js to popularny, ale nie jedyny framework tego typu (inne: Geddy, Taco).
Oprócz tego serwer korzysta z modułu serialport, który umożliwia odczyt danych przesyłanych
portem szeregowym, a także socket.io ­ modułu umożliwiającego komunikację
w czasie rzeczywistym za pośrednictwem technologii WebSocket.
Aby napisany serwer spełniał swoje funkcje należało:
●
dołączyć moduły instalowane przy użyciu npm oraz inne zależności ­ require(),
●
skonfigurować aplikację dla express.js ­ dyrektywa app.set(), za pośrednictwem której
są przekazywane funkcje middleware (czyli funkcje z sygnaturą fn(req, res, next),
gdzie req to obiekt żądania, res ­ obiekt odpowiedzi, a next odwołanie do kolejnej części
middleware). Dzięki app.set() zostaje m.in:
○
zadeklarowany port, na którym działa aplikacja (8080),
○
użyty middleware modułu jade (pakiet jade to silnik służący do budowy szablonów
i będący językiem kompilowanym do HTML’a) oraz less (pakiet kompilujący pliki w
języku less ­ rozszerzającym możliwości CSS ­ do standardowego CSS’a),
○
wykorzystany middleware static modułu express.js ­ pozwala to w przyszłości
obsługiwać statyczne pliki (np. css i js),
●
uruchomić express.js ­ server.listen(),
●
podać parametry (adres, prędkość transmisji, parzystość itd.), a następnie otworzyć port
szeregowy,
●
otworzyć WebSocket (io.sockets.on(‘open’,...)) i przekazywać dane pobrane z portu
szeregowego (socket.emit()).
5
W przypadku gdy komunikacja z portem szeregowym zostanie przerwana aplikacja wykonuje
próby powtórnego połączenia z częstotliwością równą jednej próbie na sekundę.
2.2.2 App.js
W celu uruchomienia całej aplikacji należy (będąc wewnątrz katalogu projektowego)
użyć komendy node app.js. To właśnie plik app.js jest głównym węzłem aplikacji i jego
uruchomienie powoduje również stworzenie procesu serwera. Wewnątrz pliku app.js zostaje:
●
dołączony moduł forever­monitor, który zapewnia nieprzerwaną pracę procesu serwera,
●
utworzona zmienna child przechowująca informacje na temat skryptu, który ma
nadzorować forever­monitor ­ w tym przypadku server.js,
●
uruchomiony skrypt­dziecko ­ child.start().
W momencie gdy z jakiś przyczyn serwer HTTP, lub któryś z jego modułów przestaje działać,
skrypt przeprowadza próbę powtórnego uruchomienia procesu serwera.
2.3 Aplikacja ­ frontend
W celu wizualizacji wyników napisano proste skrypty, które umożliwiają wyświetlanie
wykresu temperatury w przeglądarce internetowej:
●
views/layout.jade ­ plik określający strukturę strony WWW aplikacji,
●
views/index.jade ­ plik zawierający elementy, z których składa się strona główna
aplikacji,
●
public/javascripts/temp.read.js ­ skrypt, który łączy się z WebSocket’em i pobiera
z niego dane. Informacje o temperaturze są przechowywane w tablicy, która jest na
bieżąco uaktualniana. Elementy tablicy są również źrodłem danych dla funkcji rysującej
wykres temperatury (biblioteka jQuery flot).
●
public/stylesheets/style.less ­ arkusz stylów w języku less, który jest automatycznie
konwertowany do swojego odpowiednika z rozszerzenim css.
2.4 Podsumowanie
Aplikacja działa poprawnie, jednak nie udało się stworzyć klastra, który podniósłby
niezawodność zbudowanego systemu. Mimo wszystko aplikacja w ramach podnoszenia swojej
niezawodości radzi sobie z następującymi problemami:
6
●
w momencie gdy zostaje przerwana komunikacja z portem szeregowym następują
próby ponownego połączenia (1 próba na sekundę),
●
wszystkie błędy serwera powodują zamknięcie jego procesu ­ umożliwia to zauważenie
tego faktu przez skrypt monitora i szybki restart procesu serwera.
3 Możliwości rozwoju
Aby zapewnić większą niezawodność działania aplikacji można się pokusić o próbę
uruchomienia systemu w modelu klastrowym10 . Proces serwera byłby wtedy replikowany,
a żądania od użytkowników obsługiwane równolegle. Potencjalne problemy związane
z prezentowanym rozwiązaniem:
●
aplikacja posiada dostęp do jednego portu szeregowego. Należy zapewnić poprawną
dystrybucję danych do wszystkich procesów lub stworzyć politykę dostępu do portu
szeregowego,
●
moduł socket.io domyślnie używa pamięci RAM do przechowywania wszystkich
informacji o połączeniach, event’ach etc. W przypadku tworzenia klastra staje się to
problemem ­ każdy proces będzie miał swoją część pamięci, gdzie będzie
przechowywał informacje, dlatego też procesy nie będą mogłby komunikować się
między sobą ­ proponowane rozwiązanie: RedisStore ­ zamiast zapisywać wszystkie
informacje do pamięci RAM należy je umieścić w bazie danych11 .
10
11
http://nodejs.org/api/cluster.html
http://blog.rstack.cc/post/node_js__using_socket_io_with_cluster_module
7