Posts mit dem Label geschwindigkeit werden angezeigt. Alle Posts anzeigen
Posts mit dem Label geschwindigkeit werden angezeigt. Alle Posts anzeigen

Dienstag, 7. Oktober 2014

[linux] rsync Performance verbessern. Mehr CPU Kerne.

Ich stand vor dem Problem viele kleine (3 Millionen) Bilddateien von einem Server zum anderen kopieren zu müssen, da der Bildauslagerungsserver gewechselt werden sollte.

Das Packen und Archivieren mit tar und gzip war leider unbefriedigend langsam.

Auch die Alternative mit pigz (gzip mit Mehrkern-Unterstützung) brachte keine großartige Besserung.


Syntax für pigz:

 tar -cv –use-compress-program=pigz -f meinarchiv.tar /srv/www/img

Was ich noch nicht probiert habe, ist tar mit einer Erweiterung zu versehen, die mehrere Threads zum Schreiben verwenden kann.

Das gibts hier: http://www.maier-komor.de/mtwrite.html


Syntax für Nutzung mit mtwrite:

mttar xf mytarfile.tar


Ich habe mich dann aber erstmal für die Nutzung von rsync entschieden. Vorteile: Ich muss den laufenden Betrieb (Bildupload) nicht stoppen; Abgebrochene Aktionen können wieder aufgenommen werden; Ich habe nur eine Aktion auszuführen, denn die Daten werden direkt via ssh übertragen.

Leider dauert dieser Vorgang wegen der vielen kleinen Dateien auch ziemlich lange. Nach 24 Stunden waren knapp 70GB übertragen.

Nun gibt es noch einige Dinge die ich demnächst ausprobieren möchte. Und damit ich Sie nicht vergesse gibt es diesen Post :)

Zum Beispiel lässt sich der CPU - Kern den rsync verwendet auf den Maximalwert hochtakten.
Das kann man so machen:

for i in 0 ; do
echo performance > /sys/devices/system/cpu/cpu$i/cpufreq/scaling_governor
done

Mehr dazu auf http://lwn.net/Articles/400489/

Noch etwas mehr verspreche ich mir jedoch von mehreren parallel laufenden rsync- Prozessen.
Mit Hilfe eines Scripts werden die Dateien auf die Prozesse verteilt.

Das Script gibts dort: https://wiki.ncsa.illinois.edu/display/~wglick/Parallel+Rsync

Falls der Link irgendwann mal down sein sollte, hier zum Kopieren:

/bin/bash
# SETUP OPTIONS
export SRCDIR="/folder/path"
export DESTDIR="/folder2/path"
export THREADS="8"
# RSYNC TOP LEVEL FILES AND DIRECTORY STRUCTURE
rsync -lptgoDzd $SRCDIR/ /$DESTDIR/
# FIND ALL FILES AND PASS THEM TO MULTIPLE RSYNC PROCESSES
cd $SRCDIR; find . -type f | xargs -n1 -P$THREADS -I% rsync -az % /$DESTDIR/%
# IF YOU WANT TO LIMIT THE IO PRIORITY, 
# PREPEND THE FOLLOWING TO THE rsync & cd/find COMMANDS ABOVE:
#   ionice -c2

Nachteil hierbei: Bei diesem Script werden alle Dateien des Hauptverzeichnisses mit nur einem Prozess übertragen. In den Kommentaren gab es eine alternative Lösung:

#!/bin/bash
 
# SETUP OPTIONS
export SRCDIR="/Storage/data1"
export DESTDIR="/Storage/data2"
export THREADS="32"
 
# FIND ALL FILES AND PASS THEM TO MULTIPLE RSYNC PROCESSES
cd $SRCDIR
if [[ $? -eq 0 ]]; then
        find . -type d | xargs -I% mkdir -p /$DESTDIR/%
        find . -type f | xargs -n1 -P$THREADS -I% rsync -a % /$DESTDIR/%
fi

Für beide Fälle gilt: Soll per ssh übertragen werden - also von Server zu Server - müssen die rsync Befehle abgeändert werden:

rsync -lptgoDzd -e 'ssh -c arcfour' $SRCDIR/ remotehost:/$DESTDIR/
cd $SRCDIR; find . -type f | xargs -n1 -P$THREADS -I% rsync -az -e 'ssh -c arcfour' % remotehost:/$DESTDIR/%

Und noch ein wichtiger Parameter: Soll das Verzeichnis lediglich geupdated werden und nicht alle Dateien überschrieben werden, unbedingt die Option "-u"verwenden.

Quellen:

http://www.maier-komor.de/mtwrite.html
http://lwn.net/Articles/400489/
https://wiki.ncsa.illinois.edu/display/~wglick/Parallel+Rsync
http://wiki.ubuntuusers.de/rsync


Montag, 4. Oktober 2010

Geheimtipp I/O NOOP Scheduler bei Hardware RAID Systemen

Unsere Datenbankserver waren trotz 4 SAS HDDs mit 15K UPM und Hardware RAID 10 immer der Flaschenhals. Beim Server an sich gabs auch nie Probleme mit der CPU Leistung.

Ich möchte in dem Artikel garnicht groß drum rum reden und viel erklären, da mir dazu auch die nötige Sachkenntnis fehlt. Außerdem hab ich keine Benchmarks gemacht. In unserem Fall konnte man die Veränderung direkt an der Projektgeschwindigkeit spüren. Das reichte uns :)

Mein Tipp: Bei Hardware RAID Systemen lohnt es sich mit I/O Schedulern herumzuexperimentieren.
Nachdem wir statt CFQ (OpenSuse 11.0 Standard) NOOP eingesetzt haben, lief alles bedeutend schneller.

Ein Scheduler ist dafür verantwortlich, wie die Festplatte(n) Lese- und Schreibvorgänge koordiniert. CFQ gehört dabei zu einer Variante die versucht die Anfragen möglichst sinnig zu sortieren, damit die Schreib- und Leseköpfe nicht unnötig viel umherspringen, sondern nahgelegene Operationen nacheinander abgearbeitet werden und eine "weit entferntere" Operation danach folgt.

NOOP hingegen lässt diese Optimierung gänzlich sein und arbeitet die Anfragen sequentiell ab. Dadurch wird natürlich Zeit gespart, da das ganze Berechnen und Koordinieren und evntl. Warten weggelassen wird, kann aber dazu führen, dass die Schreib- und Leseköpfe viele große Sprünge machen.
Bei Flash-Drives wird daher grundsätzlich NOOP empfohlen, da es dort keine Lese- und Schreibköpfe gibt und es dem Laufwerk egal ist wo der nächste Datenzugriff stattfindet.

So wie ich das jetzt, nach dem Lesen einiger Artikel, verstanden habe, verhält es sich ähnlich bei Hardware - Raid Systemen. Die Raid Controller nämlich, optimieren selbst schon ihre Operationen und ein weiterer Optimierer der keinen Einblick in diese Optimierungen hat, wäre verschwenderisch und im schlimmsten Fall kontraproduktiv.

Den I/O Scheduler kann man im laufendem Betrieb ändern und so problemlos testen. In einem Forum schrieb jemand, er hätte dabei mal einen Server-Freeze gehabt. Das kann ich von meiner Seite her nicht bestätigen. Es lief immer alles glatt.

So kann man gucken welcher I/O Scheduler derzeit aktiv ist:


cat /sys/block/sda/queue/scheduler
noop [anticipatory] deadline cfq

In diesem Fall wäre anticipatory aktiv.

Ändern kann man ihn wie folgt:

echo noop > /sys/block/sda/queue/scheduler

Man hat nun "noop" aktiviert.

Diese Änderung ist nach einem Neustart verloren. Man kann das auch permanent ändern, aber ich finde das grad nicht. Wird nachgereicht.

Links zum Thema:
http://www.linuxhowtos.org/System/iosched.htm
http://www.linuxtechnicalreview.de/content/download/420/3357/file/I-O-Scheduler-und-RAID-Performance.pdf

Donnerstag, 14. Januar 2010

MySQL vs. Memcached vs. Memcached + XCache ... Benchmark

Aus aktuellen Anlass hat mich Folgendes interessiert:

Auf einem Userprofil sollen 50 Freunde ausgegeben werden. Jeder User der online ist, soll dabei farblich anders dargestellt werden als die, die offline sind.

Die MySQL Query dazu sieht in etwa so aus: SELECT a.user_id, a.hat_freund, b.username, c.user_id AS online FROM friends AS a JOIN userdaten AS b ON a.hat_freund = b.user_id LEFT JOIN last_action AS c ON a.hat_freund = c.user_id AND c.last_action > UNIX_TIMESTAMP() - 1200 WHERE a.user_id = 111 ORDER BY a.seit DESC ...als "online" gelten also User, die in den letzten 20 Minuten eine Aktion durchgeführt haben.

So eine Query kommt zur Zeit zum Einsatz. Wir sind aber bemüht dem Datenbankserver so viel Last wie möglich zu entziehen und Cachingmethoden einzusetzen.


Verglichen wurde nun:

1. Der Istzustand, die reine MySql-Abfrage und die anschliessende Ausgabe der Daten.

2. Die reine MySql-Abfrage, mit anschliessender Serialisierung und Speicherung als Array in Memcached, sowie die Ausgabe der Daten aus der Datenbank. (Bzw. die soeben serialisierten Daten)

3. Das reine Auslesen des Resultsets aus Memcached und die Ausgabe.

4. Das reine Auslesen des Resultsets aus Memcached und die Ausgabe, mit dem Unterschied, dass in der Ausgabeschleife für jeden einzelnen User per XCache der aktuelle Onlinestatus abgefragt wird.

5. Das reine Auslesen des Resultsets aus Memcached und die Ausgabe, mit dem Unterschied, dass in der Ausgabeschleife für jeden einzelnen User per Memcached der aktuelle Onlinestatus abgefragt wird.

(Memcached läuft lokal. Datenbankserver im gleichen Rack.)

Die Ergebnisse:

1. normal aus datenbank ( 0.0036)

2. aus datenbank, werte in array speichern, in den cache packen und dann ausgeben ( 0.0043)

3. daten aus memcached auslesen und ausgeben ( 0.0010)

4. daten aus memcached auslesen und ausgeben. in der schleife jeden onlinestatus via xcache prüfen ( 0.0012)

5. daten aus memcached auslesen und ausgeben. in der schleife jeden onlinestatus via memcached prüfen ( 0.0046)



Auswertung:

Methode 3 ist hier eindeutig die Schnellste. Mit dieser Variante liesse sich allerdings nicht Anzeigen, wer von den ausgegebenen Usern gerade online ist bzw. wären diese Daten schnell veraltet, so dass der Cache höchstens ein paar Minuten Gültigkeit haben sollte.

Methode 4 sieht da schon vielversprechender aus. Speichert man die Useraktivitäten jeweils auch in einer XCache Variablen, so dauert es bei diesen 50 Durchgängen lediglich 0,0002 Sekunden um alle zu überprüfen. Dadurch kann der Teil, der mit Memcached gecached wird solange gültig sein, bis der User einen neuen Freund hinzugefügt oder gelöscht hat.

Methode 5 ist die Langsamste von allen. Auf diese Methode müsste man zurückgreifen, wenn man mehr als einen Webserver verwendet und XCache als Cachingsystem unbrauchbar wird*. Wenn man aber bedenkt, dass die Hauptaufgabe nicht ist, bedeutend schneller zu sein als MySQL, sondern nur, den Datenbankserver zu entlasten, so ist die Geschwindigkeit immernoch mehr als ausreichend.


Fazit:

Solange man noch nicht darüber nachdenkt, mehr als einen Webserver zu verwenden, sollte Methode 4 verwendet werden, bzw. Methode 3, wenn die Onlinezustände der User nicht angezeigt werden sollen.
Methode 4 geht bei 50 Durchläufen noch in Ordnung. Man sollte es mit den Schleifen jedoch nicht übertreiben. Die benötigte Zeit steigt entsprechend der Anzahl der Durchläufe!

Mittwoch, 13. Januar 2010

Xcache vs. Memcached

Xcache 1.3.0 vs. Memcached 1.4.4

php 5.2.12 ... xcache statisch eingebunden.
memcache modul ebenfalls statisch eingebunden in der version 2.2.5

webserver: nginx-0.7.64

system: 2 x intel quadcore. 8GB ram. open suse 10.

getestet wurde die geschwindigkeit des setzens und des einlesens von werten in den jeweiligen cache.

testreihe 1 mit memcached über unix-socket:

1.test:
timer: 100000 mal xcache variable gesetzt ( 0.4659)
timer: 100000 mal memcached variable gesetzt ( 2.5669)
timer: 100000 mal xcache variable eingelesen ( 0.1838)
timer: 100000 mal memcache variable eingelesen ( 2.4150)


2.test:
timer: 100000 mal xcache variable gesetzt ( 0.4774)
timer: 100000 mal memcached variable gesetzt ( 2.5527)
timer: 100000 mal xcache variable eingelesen ( 0.1897)
timer: 100000 mal memcache variable eingelesen ( 2.3908)


3.test:
timer: 100000 mal xcache variable gesetzt ( 0.4690)
timer: 100000 mal memcached variable gesetzt ( 2.8108)
timer: 100000 mal xcache variable eingelesen ( 0.1873)
timer: 100000 mal memcache variable eingelesen ( 2.6441)



testreihe 2 mit memcached über TCP:
(hier wurde ein anderer server benutzt, mit 16GB ram und etwas schnelleren prozessoren. alles andere ist identisch)

1.test:
timer: 100000 mal xcache variable gesetzt ( 0.2311)
timer: 100000 mal memcached variable gesetzt ( 2.5986)
timer: 100000 mal xcache variable eingelesen ( 0.1547)
timer: 100000 mal memcache variable eingelesen ( 2.3529)


2.test:
timer: 100000 mal xcache variable gesetzt ( 0.2354)
timer: 100000 mal memcached variable gesetzt ( 2.6385)
timer: 100000 mal xcache variable eingelesen ( 0.1561)
timer: 100000 mal memcache variable eingelesen ( 2.3573)


3.test:
timer: 100000 mal xcache variable gesetzt ( 0.2376)
timer: 100000 mal memcached variable gesetzt ( 2.6054)
timer: 100000 mal xcache variable eingelesen ( 0.1541)
timer: 100000 mal memcache variable eingelesen ( 2.3435)




auswertung:
das reine setzen und einlesen von einfachen variablen ist mit xcache deutlich schneller. das ist nicht verwunderlich, denn xcache bietet weniger funktionen und ist direkt in php eingebunden, wohingegen memcached als eigenständiger daemon läuft und seperat angesprochen werden muss.

wenn man einfache html-stücke oder variablen cachen möchte und man keinen extra-server zum cachen benutzt, dann sollte xcache die erste wahl sein.

memcached hingegen bietet die möglichkeit ganze objekte zu cachen. also beispielsweise mehrdimensionale arrays, womit man ergebnisse von datenbankabfragen cachen kann.
memcached bietet außerdem die möglichkeit große objekte bzw. strings zu komprimieren.

der entscheidende vorteil jedoch liegt in der fähigkeit memcacheds, sich auf verschiedene server verteilen zu lassen. dies ist insbesondere für größere projekte von vorteil.

fazit: es schadet nichts beide varianten parallel zu nutzen. xcache ist als opcode cacher ohnehin ein must-have. der variablen-cache ist da schon mit bei, also kann man ihn auch ruhig nutzen.
memcached sollte man nutzen, wenn es darum geht, wirklich große mysql resultsets zu cachen.


xcache: http://xcache.lighttpd.net/
memcached: http://www.memcached.org/
memcache (pecl): http://pecl.php.net/package/memcache
nginx: http://www.nginx.net


test-script:

ini_set('error_reporting', E_ALL);
ini_set('display_errors', 'On');
ini_set('display_startup_errors', 'On');

function start_timer($event) {
printf("timer: %s
\n", $event);
list($low, $high) = split(" ", microtime());
$t = $high + $low;
flush();

return $t;
}

function next_timer($start, $event) {
list($low, $high) = split(" ", microtime());
$t = $high + $low;
$used = $t - $start;
printf("timer: %s (%8.4f)
\n", $event, $used);
flush();

return $t;
}

$t = start_timer("");

$x = 0;
while($x < 100000) {
xcache_set('111',"aaahhh ein string!!!",300);
$x = $x+1;
}

$t = next_timer($t, "100000 mal xcache variable gesetzt");

$memcache_obj = memcache_connect('unix:///tmp/memcached.socket', 0);
//$memcache_obj = memcache_connect('127.0.0.1', 11211);
$x = 0;
while($x < 100000) {
//$memcache_obj->set('111',"aaahhh ein string!!!",0,300);
memcache_set($memcache_obj, '111', "aaahhh ein string!!!", 0, 300);
$x = $x+1;
}

$t = next_timer($t, "100000 mal memcached variable gesetzt");

$x = 0;
while($x < 100000) {
$daten = xcache_get('111');
$x = $x+1;
}

$t = next_timer($t, "100000 mal xcache variable eingelesen");

$x = 0;
while($x < 100000) {
$daten = memcache_get($memcache_obj, '111');
$x = $x+1;
}

$t = next_timer($t, "100000 mal memcache variable eingelesen");

?>

Dienstag, 5. August 2008

schlankes PHP selbst kompilieren

Ja so... 1. Thema... habe in den letzten Tagen PHP 5.2.6 auf mehreren Servern installieren müssen. Bisher nutzte ich immer die Standardpakete der Distributionen, doch jetzt erst ist mir aufgefallen, dass da sauviel qautsch mit bei ist, den wir niiieee verwendet haben. man dachte ja immer "ohhh hmhm 'pdo_mysql' ... klingt wichtig.. lass ich mal drin". Einen Überblick über die PECL Module von PHP findet man dort: http://www.php.net/manual/de/funcref.php ...wenn man sich nun anguckt, wozu diese ganzen Sachen gut sind, die in den standard rpm's und deb's drin sind, merkt man, dass man das meiste garnicht braucht.

Welche Erweiterungen man "nutzt", kann man übrigens mit folgendem Skript nachprüfen:

phpinfo();
?>

Den Code als phpinfo.php speichern und mitm Browser aufrufen.

Da stehen denn so sachen wie "pdo", "xml", "simplexml", "spl", "filter" und und und... alles Module, die Funktionen anbieten die wir bei uns nie verwendeten... also? Kann doch weg, oder? Klar, denn unnötige Funktionen machen unser schönes PHP doch so schwerfällig und wir wollen doch das Beste aus der Hardware holen.

Nun müssen wir PHP aber selber kompilieren... am besten erstmal php von der Kiste schmeissen. Bei OpenSuse geht das gut mit "yast" und der Softwareverwaltung. Ich beziehe mich in meinen Postings immer auf OpenSuse, da wir dieses standardmäßig verwenden. Bevor PHP deinstalliert wird aber bitte erstmal das configure command von der phpinfo sichern. (dieses ./configure --with...)
Zur Info: wir nutzen kein Apache... wer PHP mit Apache nutzt sollte PHP als Apachemodul installieren. Da ich das nie benötigte, gehe ich darauf auch nicht ein.. will ja nix falsches erzählen...glaube aber diese Sachen werden im configure command benötigt: --with-apxs and --with-apxs2

Nun ziehen wir uns die PHP Quellen.
Ab ins root oder Homeverzeichnis und

#wget http://link.zu.den.quellen.com/php-5.2.6.tar.gz

eingeben. (quellen findet man auf http://www.php.net/downloads.php)
danach entpacken mit

#tar xf php-5.*
#cd php-5*

Sooo mittlerweile müsste man ja wissen, welche Sachen man selbst für sein PHP benötigt... bei uns reichte folgendes configure vollkommen aus:

#./configure '--with-mysql=/usr/' '--with-mysqli' '--prefix=/usr' '--datadir=/usr/share/php5' '--mandir=/usr/share/man' '--with-libdir=lib64' '--includedir=/usr/include' '--sysconfdir=/etc/php5/fastcgi' '--with-config-file-path=/etc/php5/fastcgi' '--with-config-file-scan-dir=/etc/php5/conf.d' '--enable-session' '--with-mm' '--with-pcre-regex=/usr' '--disable-debug' '--enable-inline-optimization' '--disable-rpath' '--enable-shared' '--program-suffix=5' '--enable-force-cgi-redirect' '--disable-discard-path' '--enable-fastcgi' '--bindir=/usr/bin' '--disable-cli' '--disable-all' '--enable-ftp' '--with-gd' '--enable-mbstring' '--with-zlib' '--with-jpeg-dir=/usr/lib64' '--enable-shmop'

#./configure --help

Zeigt alle verfügbaren Optionen an. --enable-xxx nutzt man, wenn ein Modul keine externen Quellen/Bibliotheken benötigt. --with-xxx benutzt man beim Gegenteil.

Shmop benötigen auch die Wenigsten, daher können die Meisten das wohl rausnehmen. Schaut am besten selbst nach, was ihr benötigt.
Während configure arbeitet kann es zu diversen Fehlermeldungen kommen. Da man hier nun alles selbst kompiliert, benötigt man viele extra devel Pakete. Zum beispiel gd-devel für die gd Erweiterung oder mm-devel. Das kann etwas dauern bis man configure alle Wünsche erfüllt hat.
(hint: trotz erfolgreicher gd Installation, kann beispielsweise der jpeg Support fehlen, falls die jpeg Bibliotheken nicht installiert sind)
Zur Belohnung hat man ein schlankes PHP ohne externe Module, was auch einen Geschwindigkeitsgewinn bringt, da diese nicht nachträglich reingeladen werden müssen.

Wurde configure erfolgreich ausgeführt fehlen noch zwei Kommandos:

#make (kann etwas dauern)
#make install


tja... feddich. Die Binarys befinden sich nun in /usr/bin
Die datei heisst meines Wissens dann 'php-cgi5'.

So... das wars erstmal... wir haben nun ein schlankes PHP installiert. Wir nutzen dies übrigens mit dem spawn-fcgi Skript von lighttpd (www.lighttpd.net) (http://trac.lighttpd.net/trac/wiki/Docs%3AModFastCGI)