Myšlenka JavaScriptu na straně serveru vypadá na první pohled strašidelně, protože JavaScript obsahuje spoustu konstrukcí, které ne každému jdou na ruku a navíc byl doposud až magicky spojen s webovými prohlížeči. V tomto článku ale nebudu rozebírat použitý jazyk. Důležité je, co vám může projekt Node.js nabídnout, a kromě jazyka známého v celé webové komunitě to je možná až ohromující výkon v paralelních I/O operacích.
Node.js je postaveno na enginu V8, který znáte z prohlížeče Google Chrome a Chromium. K němu autoři připojili několik modulů komunikujících asynchronně se světem. V praxi to vypadá tak, že vytvoření malého web serveru neznamená, že budete ve smyčce čekat, až se objeví nové spojení, ale importujete http modul, řeknete mu, že má poslouchat na localhostu a portu 8000 a registrujete na něj svou callback funkci. Váš kód jede dál a když pak přijde spojení od uživatele, Node.js zavolá vaši registrovanou funkci. Když se podíváte na společnosti, které už Node.js nasadily, jsou jejich zkušenosti vesměs kladné. Pokud Node.js nasadíte tam, kde se nejvíce hodí, a to na aplikace s velkým množstvím paralelních I/O operací, je zrychlení proti alternativním řešením až dechberoucí.
Například služba LinkedIn se rozhodla používat Node.js jako backend pro jejich mobilní aplikaci. Mnoho konkurenčních požadavků, to je oblast, kde Node.js vyniká a reálná čísla to jen potvrzují. To, co dříve běželo na Ruby On Rails na 15 serverech a 15 virtuálních serverech na každém z nich, dnes běží pouze na čtyřech virtuálních serverech a navíc to zvládne dvojnásobnou zátěž. Jako bonus se prý podařilo aplikaci vyvinout velmi rychle. Více o technických detailech najdete v článku na serveru venturebeat.com.
Na eBay zase řešili, jak sjednotit několik API pod jednotné API a tím snížili počet požadavků od klientů. To se podařilo, ale v porovnání s předchozím případem je nárůst výkonu menší – běžný počítač s Ubuntu prý zvládl 120 000 spojení najednou, ale další informace pro porovnání tohoto čísla k dispozici nejsou. Co si vývojáři pochvalují, jsou hlavně nízké nároky na paměť (2 kB na každé spojení), škálovatelnost a jednodušší monitorování. Více o jejich zkušenostech najdete na ebaytechblog.com.
Deployment Node.js aplikace
Na začátku jsem zmínil, že Node.js je běhové prostředí pro JavaScript, takže co se týká hostování aplikací napsaných v JavaScriptu, není potřeba nic speciálního. Node.js umí komunikovat se světem různými protokoly, ale pro potřeby webu se nejvíce hodí HTTP. Hostování Node.js se tedy neliší nějak od Pythonu nebo Ruby on Rails, stačí aplikaci spustit jako daemona a nechat ji naslouchat na lokálním portu, na který nasměrujete reverzní proxy, nejlépe Nginx, ale nevadí ani Apache či jiný web server s touto funkcionalitou.
HTTP není jedinou možností, jak spojit web server s aplikací. Node.js je totiž jen základní balík, na kterém staví mnoho dalších modulů, takže existují implementace SCGI nebo FastCGI, nicméně k těmto modulům přistupujte s opatrností, protože nejsou vyvíjeny společně s Node.js, ale třetími stranami.
Kromě samotného otevření aplikace světu je ještě potřeba se postarat o to, aby na serveru běžela, a když by náhodou spadla, tak aby se opět spustila. K tomu je možné použít třeba Supervisor, o kterém jsme psali začátkem tohoto roku. Jde o velmi univerzální nástroj schopný spouštět téměř cokoli. Jednou z dalších možností je projekt forever, který je napsaný v JavaScriptu a pro JavaScript. Jeho použití je jednodušší, ale nepostará se o spuštění skriptu po restartu serveru.
I tak se jedná o rozumnou možnost, kterou rozhodně stojí rozebrat. Z ovládání si může vzít příklad kdejaký podobný nástroj. Forever se snaží vše co nejvíce zautomatizovat. Začneme tím, že si forever nainstalujeme. Pokud ještě v systému Node.js nemáte, tak v novějších distribucích ho nainstalujete z balíčku nodejs. Určitě během instalace ještě přidejte program npm, což je správce balíčků pro Node.js, kterým také nainstalujeme forever:
# npm -g install forever
Parametr -g znamená globální instalaci, takže forever bude dostupný všem uživatelům systému.
Abychom nový přírůstek do systému vyzkoušeli, potřebujeme nějaký krátký program, třeba jeden z „Hello Worldů“, kterých se po Node.js tutoriálech válí hromada, a uložíme ho do souboru hello_world.js.
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(8080, '127.0.0.1');
console.log('Server running at http://127.0.0.1:8080/');
Po spuštění se nastartuje HTTP serveru, který na každý požadavek vrátí text „Hello World“. Server běží na adrese 127.0.0.1 a na portu 8080. HTTP server spustíme jednoduše přes node:
$ node hello_world.js
Server running at http://127.0.0.1:8080/
Pokud jsme s výsledkem spokojeni, můžete zkusit forever. Použití je velmi jednoduché, jak naznačuje nápověda:
usage: forever [action] [options] SCRIPT [script-options]
Kde action může být start, stop, stopall, restart, restartall, list, logs a několik dalších. Z parametrů je důležitý hlavně -w, kterým lze forever říci, že když se skript změní, má se běžící instance zabít a nastartovat nová. Mezi další parametry patří třeba -l říkající kde má být soubor s logy, parametr -o je obdobou pro stdout a -e pro stderr. Další parametry jsou popsané v nápovědě -h.
Spuštění skriptu na pozadí se provede takto:
$ forever start hello_world.js info: Forever processing file: hello_world.js
Když skript běží, je možné si prohlédnout jeho logy. Příkaz logs zobrazí logy ke všem běžícím Node.js procesům a když se přidá pořadové číslo, objeví se i samotný log.
$ forever logs
info: Logs for running Forever processes
data: script logfile
data: [0] hello_world.js /home/cx/.forever/JVRf.log
$ forever logs 0
info: Showing logs for hello_world.js
data: Server running at http://127.0.0.1:8080/
Zastavení aplikace se dělá obdobným způsobem:
$ forever stop 0
V tomto případě lze získat pořadové číslo pomocí příkazu list:
$ forever list
info: Forever processes running
data: uid command script forever pid logfile uptime
data: [0] JVRf node hello_world.js 528 529 /home/cx/.forever/JVRf.log 0:0:12:55.138
Když skript běží, je potřeba na něj nasměrovat Apache, Nginx nebo jiný webový server. Je možné skript spustit i přímo na portu 80, ale v takovém případě musí běžet pod uživatelem root, což vyžaduje práci navíc, kterou už autoři web serverů udělali. Nginx se ve většině distribucí schovává ve stejnojmenném balíčku a jeho konfiguraci najdete v /etc/nginx/nginx.conf. U Apache to je složitější a je lepší se řídit dokumentací vaší distribuce, stejně jako u konfigurace, která je u Apache mnohem více „distrocentrická“ než u Nginx.
Pro Nginx konfigurace reverzní proxy na běžící HTTP server vypadá takto:
server {
listen [::]:80;
server_name domena.cz www.domena.cz;
access_log /var/log/app1.log;
error_log /var/log/app1-error.log;
location / {
proxy_pass http://127.0.0.1:8080/;
}
}
Názvy jednotlivých direktiv jsou dostatečně výmluvné, takže přejdeme na Apache, kde je konfigurace velmi podobná:
NameVirtualHost *:80
<VirtualHost *:80>
ServerName domena.cz
ServerAlias www.domena.cz
ErrorLog /var/log/app1-error.log
CustomLog /var/log/app1.log combined
LogLevel error
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass / http://127.0.0.1:8080/
</VirtualHost>
Konfigurace jak Apache, tak Nginxu jsou témata na celé knihy a není v silách jednoho článku popsat všechny možnosti. Uvedené příklady ale budou fungovat ve většině případů bez problémů. Pokud i tak narazíte na nějakou nejasnost, pravděpodobně najdete odpověď v dokumentaci.
Shrnutí
Za forever můžeme poděkovat lidem z projektu nodejitsu, což je hosting Node.js aplikací postavený na cloudové infrastruktuře. Hostování Node.js aplikací na vlastním stroji ať už virtuálním či fyzickém není o moc náročnější než hostování jakékoli jiné aplikace. Pokud jste zatím pracovali jen s PHP, které má modul do Apache, připadá vám deployment Node.js určitě o něco složitější, ale pokud tento postup pochopíte, nebudete mít problémy s projekty napsanými v dalších jazycích jako je Python, Ruby nebo třeba Perl.
Za zmínku ještě stojí projekt nodeenv. Je napsaný v Pythonu a umožňuje uzavřít prostředí Node.js do adresáře. Díky tomu můžete provozovat aplikace s různými požadavky na knihovny a jejich verze, aniž by se navzájem ovlivňovaly. Nodeenv si poradí i s instalací různých verzí Nodejs. Projekt je víceméně podobný projektu virtualenv, který dělá to samé pro Python.