Martin Lantzsch
Software Entwickler
8. Januar 2013

Umzug der resi:DATA Infrastruktur

8. Januar 2013 - Geschrieben von Martin - 4 Kommentare

Da seit dem letzten Post über die Infrastruktur einiges an Webspaces und Servern dazu gekommen ist, muss nun alles mal neu formiert werden.

Aktuell arbeite ich mit 2 Webspaces für Webseiten und Mail Hosting, einen Webspace für Backups, zwei Linux vServer für Webapplikationen, Webservices und Git Repositories und einen Windows vServer für ein C# Projekt, dass eine Serverapplikation und einen Team Foundation Server erfordert.

Das ganze soll im nächsten halben Jahr auf zwei vServer und einen Webspace zusammengezogen werden. Hierzu werden zwei Webspaces gekündigt und alle Domains auf einen großen Webspace Umgezogen, der auch gleichzeitig die Mail Struktur beherbergen soll (dann muss ich keine Mail Server mehr administrieren, was sehr entspannend ist :)). Die Linux vServer werden aus dem Momentanen Dienste Mix gelöst und einer wird für Lighttpd + PHP und der andere für MySQL, NodeJS und Git zuständig sein. Der Windows Server verschwindet ganz, da die Applikation mitsamt des Team Foundation Servers in ein Cloud Hosting migriert wird.

Im nächsten Schritt, der nicht so Zeitkritisch ist, werden alle Webseiten und Applikationen die derzeitig noch auf PHP Basis laufen auf NodeJS umgezogen. Ist dieser Schritt abgeschlossen wird vServer Nr 1. als dedizierter MySQL Server und vServer 2. als dedizierter NodeJS Server eingesetzt.

Soweit das vorhaben. Nun muss erst einmal eine Bestandsaufnahme bezüglich Domains, Apps, etc. gemacht werden. Anschließend heißt es Verträge kündigen, neue Server mieten, etc.

6. Januar 2013

NodeJS MySQL pool

6. Januar 2013 - Geschrieben von Martin - 2 Kommentare

Momentan arbeite ich daran Resigame 2.0 auf NodeJS Basis zu entwickeln. Da abzusehen ist, dass auf Resigame wieder sehr hoher Traffic entstehen wird, wird das ganze Performance optimiert entwickelt. Cluster, SQL Pooling, etc.

Gestern habe ich mir ein Modul für den MySQL Pool geschrieben, denn bei vielen NodeJS Applikationen wird entweder für jeden HTTP Request eine MySQL Verbindung verwendet oder eine für alle.

Das Problem bei einer Verbindung pro HTTP Request ist, dass die Verbindungen bei hohen Nutzerzahlen sehr schnell ausgehen (MySQL max connections) und man ggf. ein paar Sekunden auf die nächste freie Verbindung warten muss.

Bei der Methode mit einer Verbindung, die für alle Nutzer verwendet wird, ist natürlich die Performance sehr bescheiden. Aufwändige Querys können die ganze Applikation stark ausbremsen.

Also habe ich einen MySQL Pool entwickelt, dieser wird beim starten der Anwendung erzeugt. Man übergibt die „poolsize“ – also die Anzahl der Verbindungen die hergestellt werden sollen (diese muss natürlich unter der maximalen Anzahl an Verbindungen, die der MySQL Server zulässt liegen) und die Zugangsdaten zum Datenbankserver. z.B.

var pool = new require('/helpers/pool')({
	poolsize: 50,
	mysql: {
		host: 'localhost',
		user: 'root',
		password: 'root',
		database: 'resigame'
	}
});

Querys können nun direkt an den Pool gesendet werden:

pool.query('SELECT * FROM users WHERE userID = ?', [userID], function(err, results) {
	// whatever
});

Der Aufruf fügt den Query zur Warteschlange hinzu und sieht nach ob gerade eine Verbindung frei ist. Wenn ja wird diese gleich verwendet, ansonsten dauert es bis wieder eine Verbindung frei wird. (Ergo, je mehr Benutzer die gleichzeitig auf die Datenbank zugreifen, desto höher die poolsize –> mehr Performance).

Hier der Quellcode, ich werde ihn die Tage noch ein wenig erweitern und dann auf GitHub stellen.

/** 
 * MySQL pool to hold multiple connections to the database server
 *
 * @author	Martin Lantzsch <martin@linux-doku.de>
 */
 
var mysql = require('mysql');
module.exports = function(config) {
	this.freeConnections = [];
	this.queryQueue = [];
 
	this.createConnection = function(details) {
		var connection = mysql.createConnection(details);
		connection.connect();
		connection.number = this.freeConnections.length;
		this.freeConnections.push(connection);
	};
 
	this.query = function(command, params, callback) {
		if(typeof(params) == 'function') {
			callback = params;
			params = [];
		}
 
		this.queryQueue.push({
			command: command,
			params: params,
			callback: callback
		});
		this.work();
	};
 
	this.work = function() {
		var self = this;
		if(self.queryQueue.length > 0) {
			if(self.freeConnections.length > 0) {
				var query = self.queryQueue.shift();
				var connection = self.freeConnections.shift();
				connection.query(query.command, query.params, function(err, results) {
					if(err) throw err;
					query.callback(err, results);
					self.freeConnections.push(connection);
					if(self.queryQueue.length > 0)
						self.work();
				});
			}
		}
	};
 
	for(i = 0; i < config.poolsize; i++) {
		this.createConnection(config.mysql);
	}
 
	return this;
}

11. Juni 2012

NodeJS Dateien aus Verzeichnis einlesen und ausgeben

11. Juni 2012 - Geschrieben von Martin - Keine Kommentare

Vieles bei NodeJS läuft synchron ab, was die Handhabung öfter etwas erschwert, wenn man wie ich z.B. von PHP kommt. Eben musste ich eine Lösung finden, wie ich alle Dateien aus einem Verzeichnis mit Inhalt einlesen, parsen und ausgeben kann.

Einen Array mit allen Dateien zu bekommen war kein Problem.

fs.readdir(filePath, function(err, files) { });

Nun wollte ich in dem Callback eine foreach Schleife laufen lassen um jede Datei einzulesen, zu parsen und an eine Variable anhänngen zu lassen. Natürlich auch kein Problem… Aber…

files.forEach(function(file) {
	fs.readFile(filePath + file, 'utf-8', function(err, data) {
		html += markdown(data.toString());
	});
});

wie gebe ich die Variable html nun an den Client zurück? Denn alles was nach dem „readdir“ kam, würde bereits ausgeführt, wenn ich es nach der foreach setze wurde es auch bereits ausgeführt. Also kommt hier Trick 17.

fs.readdir(filePath, function(err, files) {
	i = 0;
	files.forEach(function(file) {
		i++;
		fs.readFile(filePath + file, 'utf-8', function(err, data) {
			html += markdown(data.toString());
			if(--i === 0) {
				res.send(html);
			}
		});
	});
});

Eh alter was? Ja schon klar ;-) Und zwar setzen wir nachdem wir den Array mit den Dateinamen bekommen haben die Variable i, weisen ihr den Wert 0 zu und beim durchlaufen der einzelnen Dateien zählen wir immer um eines hoch. Wenn wir nun die Dateien einlesen zählen wir in der if Abfrage immer um eines runter und wenn in diesem Moment die Variable i auf 0 gesetzt wird, senden wir den Inhalt. Ja so einfach geht das. Achja, das *minus minus* muss vor das i, denn ansonsten wird der Wert von i für die if Abfrage genommen und danach erst runtergezählt.

7. Dezember 2011

NodeJS auf Windows installieren und nutzen

7. Dezember 2011 - Geschrieben von Martin - 4 Kommentare

Was unter Linux so leicht ist, ist unter Windows auch nicht viel schwerer, wenn man weiß wo man anpacken muss. Da NodeJS seit Version 0.6 einen Windows Build hat, muss man sich gar nicht mit kompilieren herumschlagen sondern kann es direkt per Setup installieren.
Den Download gibt es hier: NodeJS Windows installer
Das Setup verläuft wie jedes andere ganz unspektakulär. Das war es auch schon.

Die node.exe, also das Herzstück von NodeJS findet sich unter

C:\Program Files\nodejs\node.exe

Um effektiv mit NodeJS arbeiten zu können öffnen wir cmd und wechseln in dieses Verzeichnis. Für die Noobs ;-)

cmd.exe
cd C:\Program Files\nodejs\

Hier können wir nun mittels

node.exe

den Server starten. Es begrüßt uns ein Kommando Promt, in dem wir Befehle eingeben können. Wie zum Beispiel Console.Log()

console.Log('Hallo Welt');

Nun wird uns „Hallo Welt“ ausgegeben. Schön, nicht?

Aber jetzt ran an den Speck, wir legen uns nun irgendwo ein NodeJS Arbeitsverzeichnis an, in dem wir unsere JavaScript Dateien ablegen. Ich habe zum Beispiel unter „C:\Users\Martin\Documents\NodeJS\“ ein solches Verzeichnis. Darin erstellen wir uns eine Datei namens „helloWorld.js“

var http = require('http');
var server = http.createServer(function(req, res) {
	res.writeHead(200);
	res.end('Hallo Welt');
}).listen(8080);

Dieses Script lauscht auf den Port 8080 und gibt „Hallo Welt“ aus wenn eine Anfrage per HTTP kommt.
Um nun den Server mit diesem Script zu starten wechseln wir wieder zur Konsole und starten die node.exe folgendermaßen

node.exe C:\Users\Martin\Documents\NodeJS\helloWorld.js

Nun den Browser der Wahl öffnen und „localhost:8080“ in die Adresszeile eingeben und vòila

Hallo Welt