Die PHP Performance Tage auf Codejungle.org Part 1
Ich habe mir gedacht, nachdem ich ja sonst nix zu tun habe, ein paar
Tage lang eine bestehende Applikation so umzuschreiben, dass
sie auf mehreren Servern läuft.
Als Basis werde ich meinen Reminder Service verwenden.
Der erste Schritt um die Performance zu verbessern ist immer
die Analyse der bestehenden Applikation, dazu gehört auch das Profiling, um
Bottlenecks besser zu lokalisieren.
Um die Skalierbarkeit zu verbessern, werde ich
gewisse Teile ausgliedern, man nennt dies auch funktionale
Partitionierung.
Man könnte bei einem typischen Blog zum Beispiel anfangen,
Kommentare, Benutzer und Nachrichten jeweils auf eine eigene Datenbank auszulagern.
Weiters könnte man mit Hilfe eines Lastenverteilers und mehreren Webservern die
Last aufteilen.
In unserem Beispiel haben wir zwei Kernbereiche, erstens das Userinterface,
worüber der Benutzer Daten anlegen, verändern und löschen kann und
zweitens das Backend, welches die eingegebenen Daten verarbeitet.
Im Idealfall können wir am Ende das Front und Backend auf N Servern horizontal skalieren.
Das bedeutet, wir erhöhen nicht nur die Geschwindigkeit, sondern schaffen zusätzlich Redundanzen,
die eine gewisse Ausfallsicherheit garantieren.
Schauen wir uns das bestehende Backend mal an:
Code
<?
include("./config.php");
$connect=@mysql_connect("$db_host", "$db_user", "$db_pass")
or die("<li>Cant connect to: $db_host with user: $db_user</li>");
@mysql_select_db($db, $connect)or die("Cant select DB");
// hier wird jeder job aus der datenbank geholt,
// der den staus planned hat und in der vergangenheit liegt.
$sql="SELECT jid, job.rid, subject, description, email, reminder.interval,
reminder.remind_date, reminder.auth
FROM job, reminder
WHERE
status='planned' AND
planned<UNIX_TIMESTAMP() AND
reminder.rid=job.rid";
$result=mysql_query($sql);
while($row=mysql_fetch_array($result)){
$header = 'MIME-Version: 1.0' . "n";
$header .= 'Content-type: text/html; charset=iso-8859-1' . "n";
$header .= 'To: "'.$row['email'].'" <'.$row['email'].'>' . "n";
$header .= 'From: "Remind ME" <remind@codejungle.org>' . "n";
$msg='
<html>
<head>
<title>RemindME</title>
</head>
<body>
'.$row['description'].'
<br/><hr><a href="http://www.codejungle.org/reminder/uid/'.$row[auth].'">Modify your Reminder</a>
</body>
</html>
';
if(mail($row['email'], $row['subject'], $msg, $header)){
//wenn die email verschickt werden konnte, wird der job auf done gesetzt
//und ein neuer job mit neuem versand datum angelegt
$update="update job set status='done' where jid=".$row['jid'];
mysql_query($update);
$time=getdate($row['remind_date']);
if($row['interval']=="d"){
$dstr=date("U", mktime($time['hours'], $time['minutes'], $time['seconds'],
$time['mon'], $time['mday']+1, $time['year']));
}
if($row['interval']=="w"){
$dstr=date("U", mktime($time['hours'], $time['minutes'], $time['seconds'],
$time['mon'], $time['mday']+7, $time['year']));
}
if($row['interval']=="m"){
$dstr=date("U", mktime($time['hours'], $time['minutes'], $time['seconds'],
$time['mon']+1, $time['mday'], $time['year']));
}
if($row['interval']=="y"){
$dstr=date("U", mktime($time['hours'], $time['minutes'], $time['seconds'],
$time['mon'], $time['mday'], $time['year']+1));
}
if($row['interval']!=="n"){
$update_setting="update reminder set remind_date=".$dstr." where rid=".$row[rid];
mysql_query($update_setting);
$insert="insert into job values ('', ".$row['rid'].", 'planned', ".$dstr.")";
mysql_query($insert);
}
}
}
?>
Im Grunde passiert in diesem Script folgendes:
Hole mir alle unerledigten Jobs
Versende eMail
Markiere Job als erledigt
Erstelle gegebenenfalls neuen Job
Dieser Teil zeigt ganz schön, was man beachten muss, wenn man eine Applikation umschreibt, damit
Sie auf mehreren Server laufen kann.
Da zwischen "Hole mir alle unerledigten Jobs" und "Markiere Job als erledigt" etwas Zeit vergehen kann,
kann es passieren das ein zweiter Server die gleiche Routine startet und
ebenfalls den gleichen Job zugeteilt bekommt. Das Resultat wäre, dass der Benutzer
zwei oder mehr gleiche Nachrichten erhält.
Dies werden wir umgehen, indem wir nach "Hole mir alle unerledigten Jobs" einen Task einbauen,
der dafür sorgt, dass andere Server nicht den gleichen Task bekommen.
Hole mir 10 unerledigte Jobs
Markiere Job als in Bearbeitung
Versende eMail
Markiere Job als erledigt
Erstelle gegebenenfalls neuen Job
Desweiteren werden wir die Anzahl der zu erledigenden Jobs pro Prozess auf 10 verringern.
Daher sollte unser Code nun folgendermaßen aussehen:
Code
<?
include("./config.php");
$connect=@mysql_connect("$db_host", "$db_user", "$db_pass")
or die("<li>Cant connect to: $db_host with user: $db_user</li>");
@mysql_select_db($db, $connect)or die("Cant select DB");
// hier werden die letzen 10 jobs aus der datenbank geholt,
// der den staus planned hat und in der vergangenheit liegt.
$sql="SELECT jid, job.rid, subject, description, email, reminder.interval,
reminder.remind_date, reminder.auth
FROM job, reminder
WHERE
status='planned' AND
planned<UNIX_TIMESTAMP() AND
reminder.rid=job.rid
limit 10
";
$result=mysql_query($sql);
while($row=mysql_fetch_array($result)){
//setze job auf in bearbeitung, damit kein anderer prozess ihn ebenfalls erledigt
mysql_query("UPDATE job set staus='in_progress' where id='".$row['jid']."'");
$header = 'MIME-Version: 1.0' . "n";
$header .= 'Content-type: text/html; charset=iso-8859-1' . "n";
$header .= 'To: "'.$row['email'].'" <'.$row['email'].'>' . "n";
$header .= 'From: "Remind ME" <remind@codejungle.org>' . "n";
$msg='
<html>
<head>
<title>RemindME</title>
</head>
<body>
'.$row['description'].'
<br/><hr><a href="http://www.codejungle.org/reminder/uid/'.$row[auth].'">Modify your Reminder</a>
</body>
</html>
';
if(mail($row['email'], $row['subject'], $msg, $header)){
//wenn die email verschickt werden konnte, wird der job auf done gesetzt
//und ein neuer job mit neuem versand datum angelegt
$update="update job set status='done' where jid=".$row['jid'];
mysql_query($update);
$time=getdate($row['remind_date']);
if($row['interval']=="d"){
$dstr=date("U", mktime($time['hours'], $time['minutes'], $time['seconds'],
$time['mon'], $time['mday']+1, $time['year']));
}
if($row['interval']=="w"){
$dstr=date("U", mktime($time['hours'], $time['minutes'], $time['seconds'],
$time['mon'], $time['mday']+7, $time['year']));
}
if($row['interval']=="m"){
$dstr=date("U", mktime($time['hours'], $time['minutes'], $time['seconds'],
$time['mon']+1, $time['mday'], $time['year']));
}
if($row['interval']=="y"){
$dstr=date("U", mktime($time['hours'], $time['minutes'], $time['seconds'],
$time['mon'], $time['mday'], $time['year']+1));
}
if($row['interval']!=="n"){
$update_setting="update reminder set remind_date=".$dstr." where rid=".$row[rid];
mysql_query($update_setting);
$insert="insert into job values ('', ".$row['rid'].", 'planned', ".$dstr.")";
mysql_query($insert);
}
}
}
?>
Nachdem wir den Code nun soweit umgeschrieben haben, dass er auf mehren Servern laufen kann,
wäre eine Variante, ihn dort via Cron alle x Minuten auszuführen.
Im zweiten Teil möchte mit Hilfe dieses Beispiels, Gearman vorstellen, es ist ein Framework,
mit dem man parallele und lastenverteile Systeme aufbauen kann.
"It allows you to do work in parallel, to load balance processing, and to call functions between languages"
Außerdem möchte ich im dritten Teil noch etwas näher auf die Datenbankebene, memcache und verschiedene Lastenverteiler eingehen.
To be continuted
Andreas
Opensource Reminderservice
Schon wieder Omas Geburtstag vergessen?
Der Arzttermin war doch am Montag, oder war es doch Dienstag?
Was war noch mal die wichtige Sache, die ich heute unbedingt noch machen wollte?
Und wann fängt eigentlich das Meeting an?
Peinliche Situationen, die man sich mit meinem neuen Reminder Service
ersparen kann.
Der Sourcecode ist wie immer OpenSource, doch müsst
ihr euch noch ein paar Wochen gedulden.
Ich möchte zuerst sicherstellen, dass der Reminder Service
auch wirklich stabil läuft und dafür brauch ich möglichst viele Betatester.
Wenn du mir dabei helfen magst kannst du Remind ME hier testen:
http://www.codejungle.org/reminder/
LG
Andreas
Neues Jahr neues Glueck
Es ist nun mehr als ein Monat her, als ich mein letztes Blogpost veröffentlicht habe.
Nun, ich verfahre eben nach dem Motto "Qualität statt Quantität". Ich glaube, einfach dass es besser ist,
weniger dafür aber sinnvolle Posts zu veröffentlichen, als jeden Tag über das Wetter und weiß Gott was zu bloggen.
Auf der anderen Seite, wurde ich schon darauf angesprochen, wieso ich meine Homepage nicht aktualisiert habe.
Also was hat sich bei mir so im letzten Monat getan?

Ich war in Berlin, kam nicht auf den ccc Congress (Karten ausverkauft),
habe angefangen in Python zu hacken (django.codejungle.org),
war auf einem Advanced Security Vortrag im Metalab und
musste meine Wlan Antenne enteisen, damit ich wieder ins Internet komm,
hab mir mal die Endian Firewall angeschaut,
bin morgen auf der Abschiedsfeier von einem Freund der nach Japan siedelt (Goodbye Jay Jay)...
Soweit mal die Kurzfassung, doch bevor ich zur Vorschau auf dieses Jahr komme,
möchte ich noch meine Wörter des Jahres 2009 mit euch teilen.
auf Platz 1 : Terrorverdächtige Minderjährige
auf Platz 2 : Kognitive Dissonanz
auf Platz 3 : Stockholm Syndrom im Zusammenhang mit Apple Usern
Gut, wäre das auch gesagt, also zum Jahr 2010...
Wie immer ist der Terminkalender ziemlich voll, hier einige Events die ich 2010 gerne Besuchen würde.
Fosdem 10 - Feb 6th - 7 th. Brussels, Belgium
Black Hat Europe 2010 - Apr 12th to 15th , Barcelona, ES
Linuxwochen Vienna 2010 - Mai 6th to 8, Vienna AT
EuroPython 2010 - 19th to 22nd July, Birmingham, UK
DEF CON 18 2010 - July 29th - August 1, Las Vegas US
CCC - 27C3 2010 - Dez 27th - 30 th, Berlin GER
Mal sehen was sich so ausgeht. Und was gab es sonst noch, was mich bewegt hat, im noch relativ jungen neuen Jahr?
Haiti
Oracle buys Sun
So, genug davon, ich schätze mal, dass dieses Blogpost in der Form das einzige in diesem Jahr sein wird.
In Zukunft gibt es auch wieder weitere Bsp. Programme, Dokumentationen und aktuelle Themen rund um die IT Welt.
Voraussichtlich werde ich auch mein Blog bald auf Django umstellen, wenn ich das Syntax Highlighting endlich in
den Griff bekomme und das Design auch etwas hergibt... (django.codejungle.org).
In dem Sinne
Ein gutes neues Jahr
Andreas
Nachtrag:
Mir ist gerade noch eingefallen, dass ich und zwei Arbeitskollegen, demnächst ein Killer Ninja Coder
Weekend machen werden, bin gespannt was da raus kommen wird... ;D
26c3 Chaos Communication Congress
Ich freue mich sehr nach einigen Jahren Abstinenz,
dieses Jahr wieder auf den Chaos Communication Congress in Berlin
sein zu können.
Der Congress wird wieder vom 27. bis 30. Dezember im Berliner Congress Center (BCC) beim Alexanderplatz statt finden.
Happy Hacking, Xmas and New Year
Andreas
Boersenspiel in php zum gratis Download
Weil ich öfter gefragt worden bin ob ich mein Börsenspiel zum Download freigeben kann,
habe ich mich entschlossen es nun unter der GPL2 zu veröffentlichen.
Jeder der es testen mag kann das hier tun: Börsenspiel Demo
Jeder der es downloaden möchte kann das hier machen: Börsenspiel downloaden
Der Sourcecode ist relativ straight forword gecodet.
Was evtl. interessant ist, es gibt zwei Arten wie die Börsendaten
aggregiert werden.
1. Yahoo Finance (generate2.php)
2. Random (generate.php)
Ich würde die zweite Variante empfehlen, da die Daten von Yahoo sich nur alle 15 Min. ändern und
dann meist auch nicht viel.
Das Gameplay ist auf jeden Fall bei der zweiten Variante interessanter und man hat als Entwickler auch
mehr Möglichkeiten.
Ich wünsch euch viel Spass beim Brokern und würde mich über
Verbesserungsvorschläge sehr freuen.
LG
Andreas
Gesichtserkennung mit Openvc und meiner API
Ich möchte hier eine weitere Funktion meiner API kurz vorstellen.
Es handelt sich um eine Gesichtserkenungs API, mit der man zum Beispiel
eine grosse Anzahl von Bildern schnell und einfach sortieren kann oder aber
sicherstellen kann, dass auf einem hochgeladenen Profilbild ein Gesicht zu sehen ist.
Code
<?
/**
* Face detection
*
*
* @param $image string should be the path to your jpeg
*
* @return string xml output of my api
*
* @author andreas beder <office@codejungle.org>
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
**/
function face_detection($image){
$data = array('face' => '@'.$image);
$Curl_Session = curl_init('http://www.codejungle.org/api/face.php');
curl_setopt ($Curl_Session, CURLOPT_POST, 1);
curl_setopt ($Curl_Session, CURLOPT_POSTFIELDS, $data);
curl_setopt ($Curl_Session, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt ($Curl_Session, CURLOPT_RETURNTRANSFER, 1);
$response=curl_exec($Curl_Session);
curl_close ($Curl_Session);
return $response;
}
?>
Das ganze geht natürlich auch über die shell:
shell>curl -F 'face=@localfilename' http://www.codejungle.org/api/face.php
Sowohl diese als auch die vorher vorgestellte Funktionalität vom Websitethumbnailer funktionieren nach dem Fair-use-Prinzip.
Ich freue mich natürlich wenn sie ausgiebig getestet und genutzt wird, hoffe jedoch, dass nicht einzelne Nutzer exzessiv die
gesamte Bandbreite für sich in Beschlag nehmen. Die Traffic sollte sich einigermaßen in Grenzen halten, damit es möglichst
viele nutzen können.
Happy Hacking
Andreas
[«] « prev 1 2 3 4 5 6 7 next » [»]
