ugrás a tartalomhoz

Node.js Windows környezetben

Joó Ádám · 2011. Nov. 1. (K), 16.50
Jegyzetek Poetro webkonfos előadásához
 
1

Érdekes és izgalmas

Hidvégi Gábor · 2011. Nov. 5. (Szo), 16.31
Érdekes és izgalmas elképzelés a node.js, az érdeklődésemet azért keltette fel, mert munkám sajnos egyre többször ütközök a php korlátaiba: engem például nagyon zavar, hogy minden kéréskor újra kell inicializálni mindent (a munkamenetet, az objektumokat, változókat), vagy az, hogy munkamenetek megosztott adatai csökkentik a script számára elérhető memória méretét (több megabájtos objektumokra kell gondolni, amelyeket munkamenetben vagy memcached-ben tárolunk).

A héten kezdtem el játszani a rendszerrel, mert amúgy is nagyon szeretek js-ben programozni, ráadásul a fenti problémákra is megoldást lehet benne találni.

Az első dolog, ami feltűnt, hogy sok minden nem lineárisan működik benne, mind mondjuk a php-ben. Egy példa: csináltam egy nagyon egyszerű szervert, ami egy porton figyel, és küldtem neki egy POST kérést különböző paraméterekkel. Ekkor lefut a szerver 'request' eseménye, ami meghív egy függvényt egy 'request' és egy 'response' paraméterrel, amelyek objektumok. Ahhoz, hogy a POST adatait megkapjam, a 'request' objektum különböző eseményeire kell feliratkoznom:

var post; //ebbe kerülnek a POST adatok
function request(_request, _response) {
  _request.on('data', function (_data) {
    post += _data;
  });
  _request.on('end', function () {
    console.log(JSON.parse(querystring.parse(post)));
    _response.writeHead(200, {'Content-Type': 'text; charset=utf-8'});
    _response.end('siker');
  });
 
  post = '';
  if (_request.method != 'POST') {
    return;
  }
}


Úgy vettem észre, hogy az összes kliens-szerver kapcsolat hasonlóan működik, azaz a kódunk bizonyos helyeken atomi szintű függvényekre fragmentálódik. Ez mindenképp más szemléletet igényel, mint amit megszokhattunk.

Maga az alaprendszer fapadosnak tűnik, az adatbáziskapcsolatokat egyáltalán nem kezeli, ahhoz nekünk kell keresnünk egy már kész megoldást, vagy pedig magunknak kell fejleszteni egyet. Én a többek által ajánlott node-mysql-t próbáltam ki, ami a különböző függőségekkel együtt egy körülbelül kilencven kilobájtos csomag.

Arra voltam kíváncsi, hogy sebességben hogyan viszonyul a php-hoz, ezért a munkámhoz használt rendszerből kiexportáltam 54 darab egymást követő lekérdezést (selectek, insertek, tábladefiníciók vegyesen), és a legelső lekérdezés előtt, valamint a legutolsó után lekérdeztem az aktuális időt, a kettő különbségéből pedig kiszámoltam az eltelt időt. Az eredmények a következők lettek (többszöri frissítés után, az eredményeket a MySQL a Query Cache-ből szolgálta ki):
PHP: 61ms
Node.js: 260ms

A különbség sajnos eléggé szignifikáns, több, mint négyszeres, szóval van még hol fejlődnie a node.js-nek. A korábban említett kódtöredezés a lekérdezéseknél is előjön, azaz, ha egy függvényben több lekérdezést szeretnénk futtatni, akkor azt nagy valószínűséggel ennyi darabra kell szednünk.

Van egy olyan sejtésem, hogy a NoSQL rendszereket, amelyeknek JSON kimenetük van, hatékonyabban lehet kezelni (meg lehet spórolni az adatbáziskezelőtől visszakapott adatok parse-olását), viszont ezek használatával jelenleg mindenképp nőhet a rizikófaktor, hiszen mind a node.js, mind pedig a dokumentum alapú adatbázisok nagyon friss fejlesztések, jellemzően pár évesek, és nincs mögöttük annyi tapasztalat, mint egy RDBMS mögött.

Egyébként a ma megjelent 0.6.0-s verziójú, Windows-os node-ot használtam, de az előző, 0.5.2-ben is hasonló eredmények jöttek ki.
2

Érdekes

Poetro · 2011. Nov. 5. (Szo), 17.00
Ez már csak azért is érdekes, mert a Node.js kódnak gyorsabbnak kellene lennie. Szerintem valamit nem megfelelően készítettél elő a Node.js oldalon, vagy valamit nem optimálisan használtál, mert ekkora különbségnek nem kellene lennie, főleg mivel a JavaScript többször gyorsabb, mint a PHP.
Kíváncsi lennék a kódra, valamint hogy miért a MySQL sebességét méred. És ha már a MySQL-nél maradtál, akkor figyelembe kell venned, hogy az általad használt MySQL kliens tisztán JavaScript-ben van megírva, míg PHP-ban natív kódban van, azaz nem PHP-ban megírva a MySQL kliens. Ha igazi összehasonlítást szeretnél, akkor jó lenne mindkét oldalon vagy PHP és JS megvalósítást használni, vagy mindkettőben natív bináris klienst (Node.js alá is létezik, bár nem tudom Windowsos bináris van-e).

A Node.js-t pont ilyen fapadosra akarták építeni, hogy ne legyen vele olyan probléma, mint ami van például PHP-val. Ugye a PHP-val az a probléma, hogy ugyan alapból van benne minden, de azok nem működnek konzisztensen. Ezért az lett a szemlélet, hogy az alapvető dolgokhoz ad kész megoldásokat, minden ami már külső eszköz, azt majd megoldja a programozó userspace-ben. Így stabil és konzisztens lehet maga a core, ezáltal tesztelhetőbb lesz.
3

Ez a kód.

Hidvégi Gábor · 2011. Nov. 5. (Szo), 17.51
var mysql = require('./mysql');
var client = mysql.createClient({
  user: 'root',
  password: '',
});

client.query('USE teszt');

var tomb = ['SELECT id, value FROM teszt_setup', ...];

var ido1 = new Date().getTime();
var hany = tomb.length;

var i = 0;

function kovetkezo(err, results, fields) {
  if (err) {
    throw err;
  }
  i++;
  if (i < hany) {
    client.query(tomb[i], kovetkezo);
  }
  else {
    console.log(new Date().getTime() - ido1);
    client.end();
    return;
  }
}
client.query(tomb[0], kovetkezo);

Natív meghajtóval biztosan gyorsabb lenne, de arra még várnunk kell (Windowsra legalábbis, és ugye a blogmark arról szólt), de az első hozzászólásom azért született, hogy erre felhívjam a figyelmet. Amint meglesz, szinte biztosan "legyőzi" a php-t, hiszen meg lehet vele spórolni a $_SESSION fájlba való kiírását és beolvasását, valamint kényelmesen lehet kezelni emiatt a megosztott memóriát.

Ami viszont még érdekelne, az a kód töredezettségének problémájáról a véleményed.
5

Probléma

Poetro · 2011. Nov. 5. (Szo), 21.08
Namármost ezzel pont az a probléma, hogy nem használod ki a Node.js-t. Mert a kódot pont úgy futtatod, ahogy PHP alatt futtatnád. Nem kell megvárni, hogy a lekérdezés visszatérjen, hogy indíts még egyet. Persze a párhuzamos lekérdezésekhez érdemesebb több mysql klienst használni egyszerre, és úgy futtatni a párhuzamos kéréseket, hogy azok ne zavarják meg egymást.

Windows alatt is használhatsz bináris MySQL meghajtót, de ehhez egyelőre Cygwin-re lesz szükséged, vagy magad fordítod le Windows alá a binárist.

A kódodnak nem feltétlen kell töredezettnek lennie. Ehhez használhatsz több flow control modult, amikről az előadásomban is beszéltem. Ilyenek az async, fibers vagy az egyik kedvencem a funk.
4

Egyébként azért MySQL, mert a

Hidvégi Gábor · 2011. Nov. 5. (Szo), 18.09
Egyébként azért MySQL, mert a rendszerünk adatait ebben tároljuk, és első körben arra keresek lehetőséget, hogy a php-t leváltsuk.
Ugye a PHP-val az a probléma, hogy ugyan alapból van benne minden, de azok nem működnek konzisztensen.
Ezen mit értesz pontosan? Azt, hogy bizonyos hasonló függvények paraméterei egyiknél ilyen, másiknál másik sorrendben vannak?
6

Nehéz

Poetro · 2011. Nov. 5. (Szo), 21.13
A legnagyobb probléma a régóta beépített MySQL támogatással az, hogy semmilyen segítséget nem nyújt az SQL injection ellen. A másik dolog, hogy rengeteg függvény van, ami majdnem ugyanazt csinálja, csak mások a paraméterek, azok sorrendje. Valamint használatuk se feltétlen egyértelmű, ami kezdőknek rengeteg problémát szokott okozni.
7

Ezt komolyan gondoltad?

H.Z. v2 · 2011. Nov. 6. (V), 08.27
semmilyen segítséget nem nyújt az SQL injection ellen.

Tudtommal a hagyományos("régóta beépített") mysql interface már obsolete kategóriába került, a mysqli-ben pedig már van bind.
8

Használják

Poetro · 2011. Nov. 6. (V), 12.13
Az a baj, hogy a „többség” még mindig ezt használja. Itt azokra gondolok, akik amatőr, illetve félprofi szinten végzik csak a PHP fejlesztést. Ráadásul a legtöbb könyv és tutorial is még mindig a mysql_* parancsokat hozza fel elsőként mint MySQL kapcsolódási lehetőség, és a felhasználók jó része ennél a pontnál le is ragad, nem jut tovább. Még akkor sem, ha a könyv később ír a MySQLi illetve PDO lehetőségeiről is. Ennek két oka van. Az olvasó nem olvas tovább, vagy nem tartja szükségét a fejlettebb interfész használatának, ha már az első működik. Ezért ezt használja, hiszen ez „működik”.

Mivel én PHP tekintetében már évek óta Drupal-t használók, régen nem érdekel, hogy milyen adatbázis-kapcsolatot használ, én csak az interfészt használom, kapcsolódjon MongoDB-hez vagy MySQL-hez (főleg mivel frontend fejlesztőként nem igen foglalkozok adatbázissal).
A legutóbbi legbonyolultabb lekérdezéseim kb. így néznek ki:

  $item = db_select('item_data', 'b')
    ->fields('b')
    ->condition('bid', $bid, '=')
    ->execute()
    ->fetchAssoc();
  if ($item) {
    $item = (object)$item;
    $item->components = db_select('item_components', 'i')
      ->fields('i')
      ->condition('bid', $bid, '=')
      ->execute()
      ->fetchAllAssoc('iid');
  }
9

Mondjuk ebben van valami: pl.

H.Z. v2 · 2011. Nov. 6. (V), 12.23
Mondjuk ebben van valami: pl. "kedvenc" hazai szolgáltatómnál (fw) a mai napig nem lehet OO interface-t használni a mysql-hez. Se mysqli, se PDO... :(((
Én eleve úgy kezdtem bele a PHP-be, hogy objektum orientáltan akarom használni, így ha akarom sem tudtam volna a hagyományos felületét használni.