Category Archives: PHP

VZ meets OpenSocial GeekNight

opensocialHeute, am 20.08.2009, veranstalten wir eine GeekNight, um euch über den aktuellen Entwicklungsstand in Hinsicht auf die Einführung von OpenSocial auf unseren Plattformen zu informieren. Die Veranstaltung ist offen für alle Entwickler, Agenturen und technisch Interessierte.

Nährere Infos sind auf dem entsprechenden Edelprofil bei studiVZ und meinVZ zu finden.

Wir freuen uns auf viele Interessante Gespräche in gepflegter Atmosphäre!

Update
Wir werden Ende September eine weitere GeekNight in Berlin veranstalten, um euch über den aktuellen Stand zu informieren. Der Termin wird rechtzeitig angekündigt, versprochen ;).

Automated acceptance tests using Selenium Grid without parallelization

Originally we built our automated acceptance tests within our agile development process on a continuous integration server using Selenium with only one Selenium Remote Control. The tests were executed on a fixed browser under a specific operating system. With the growth of the test cases in the test suite the execution time of the builds extended rapidly, so the tests could not directly identify defects and thus a part of their function was lost.

The common strategy to solve this problem is to install Selenium Grid on the machine that formerly hosted the one Selenium RC to parallelize the execution of the tests. By connecting only 4 Selenium RC’s to this Grid Hub the execution time of these tests is reduced by a factor of 4 without any additional hardware and without rewriting the tests. The only prerequisite for this is that the used testing framework supports a parallelized test execution, i.e. it must be able to start more than one test of a test suite simultaneously and assign the answers supplied by Selenium Grid to the right test again.

Although our used testing framework PHPUnit does not provide a parallel execution of tests yet we found a way to use the benefits of Selenium Grid in our testing environment. Our continuous integration server provides the possibility to set up more than one build agent to run the Selenium driven acceptance tests. If we would do this with one single Selenium RC these agents would stress this RC rapidly because there is no possibility to check its state. The agents would start new tests no matter how many tests are already running at this RC.

So we installed Selenium Grid with 4 connected Remote Controls as described above. We can now control the number of simultaneously running tests, because Selenium Grid starts only so many test suites as RC’s are connected. Other incoming requests are queued in the Selenium Grid Hub until one of the connected RC’s has finished its test suite. Unlike the common usage of Selenium Grid we have not yet a real parallelization with this solution, since the test suites from the build agents of the continuous integration server run simultaneously, but each is still to be processed sequentially. But we have always the option of switching to a real parallelization when our testing framework supports it.

Memcache Feeds

Buschfunk, die Möglichkeit die Statusnachrichten (“Ist gerade…”) deiner Freunde auf unseren VZ’s anzuzeigen, ist nun/nur der Beginn der VZ Feeds. Letzlich ist der Buschfunk nur die Zusammenführung aller Statusnachrichten deiner Freunde auf der Startseite.

Nach dem Launch der ersten Version des Buschfunks, gab es bereits wenige Minuten später einen riesigen Impakt auf unserer Serverfarm. Dies führte dazu, dass wir bereits nach einem Tag die Statusnachrichtendatenbank auf eigene Server umziehen mussten. Ihr seht hier die absolute Anzahl von Statusaktualisierungen pro Minute (getrennt nach studiVZ/meinVZ = blau/flacher Graph und schuelerVZ = rot/steiler Graph):

zugriffe_mb2

Man kann Feeds, also Mitteilungen über Statusaktualisierungen eines Freundes, unterschiedlich implementieren und stellt sich dabei einigen Herausforderungen, gerade wenn es nicht nur um die optimale Speicherung, sondern auch um performante Zugriffe und logisches Zusammenführen von ähnlichen Feedeinträgen geht.

Wir haben uns für erste Tests in Richtung Social-Feeds für eine reine Memcache-Implementierung entschieden. Man hat den Vorteil, dass man die ohnehin nur momentan interessanten Posts von Usern nicht in der Datenbank vorhalten muss und Memcacheoperationen dazu noch um einiges schneller sind. Für einen Feed baut man sich im einfachsten Fall eine Queue pro User mit sortierten Einträgen auf, die man als Entity im Memcache ablegt. Da man nicht unendlich viele Einträge vorhalten muss und ein Memcacheobjekt per default eh nur 1 MB pro Eintrag groß sein darf, limitiert man die Queue auf eine feste Anzahl und wirft bei einem neuen Eintrag einfach alte Einträge weg.

Ok, genug der Einleitung, kommen wir zu ein paar Codeschnippseln. Am besten baut man sich ein Interface, welches sich um das Handling von Feedeinträgen kümmert:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface FeedEntry {
 
//referenziertes Memcacheobject, also eigentlicher Inhalt
public function getFeedEntryReference(...);
 
//ist der Eintrag sichtbar -> Privacy
public function isFeedEntryHidden(...);
 
//initialer Aufbau
public function initializeFeedEntry(...);
 
[...]
 
}

Jetzt haben wir einen beliebig erweiterbaren Feed Typen und können mit Implementierungen, wie zum Beispiel Statusänderungen von Nutzerprofilen, Microblogeinträgen etc, beginnen.

Was man jetzt noch braucht, ist das eigentliche Aufbauen der Queue, also Füllen des Feeds mit Feed Typen. Man sollte sich überlegen, woraus ein Eintrag innerhalb der Queue aussehen soll. Es sollte die id des Users, einen Zeitstempel, sowie den eigentlichen Inhalt enthalten. Wir haben uns dafür entschieden, den Inhalt des Eintrages nur als Referenz in der Queue zu halten, damit bei Änderungen nicht jedes Queueobjekt, sondern lediglich das referenzierte Memcacheobjekt geändert werden muss. Ausserdem will man die Daten nicht doppelt im Speicher halten.

Beispielhaft könnte eine vereinfachte Queue folgendermaßen aussehen:

1
2
3
4
5
$queue = array(
0 => array ('timestamp' => time(), 'userId' => 123456789, 'contentId' => 1000, 'type' => TYPE_MICROBLOG),
1 => array ('timestamp' => time(), 'userId' => 1234567910, 'contentId' => 1001, 'type'  => TYPE_PHOTOCOMMENT)
[...]
);

Mit Hilfe des Typs und dessen konkreter Implementierung eines Feed Entries kann nun der eigentliche Inhalt aus einem weiteren Memcacheobjekt oder aus der Datenbank geholt werden. Sortiert ist die Queue bereits nach dem Einfügen eines neuen Entries. Wird nun der Content hinter einer solchen Referenz gelöscht, so braucht man die Queues der User, dessen Feeds beeinflusst werden, nicht updaten, da der Feed beim Einlesen automatisch merkt, dass die Referenz nicht mehr gültig ist und diese “überspringt”.

Für’s Aufbauen der Queue noch ein Tipp: Verwendet lieber mehrmaliges array_reverse im Zusammenhang mit array_push, anstatt ein array_shift! Das ist um Welten schneller, wenn man ein Element vorn ranhängt bzw. hinten anfügt.

(Quelle: http://www.ingo-schramm.de/blog/archives/9-PHP-array_shift-does-not-scale.html)

Da der Memcache, wenn der ihm zugewiesene Speicher vollläuft, wenig frequentierte Bereiche freigibt, muss man sich zwangsweise überlegen, wie man mit Datenverlusten innerhalb der Queue umgeht. Dazu könnte man zyklische Backups der Queueeinträge oder ein initiales Befüllen der Feedeinträge implementieren (im Interface bereits vorgesehen). Die eigentlichen Daten (bsp. das konkrete Statusupdate) bleiben natürlich erhalten und liegen in der Datenbank persistent vor, es geht hierbei nur um die Referenzen auf diese Einträge.

PHP SPL Data Structures Benchmark

Data structures and collections are one of the most wanted features for the Standard PHP Library SPL over the last few years. With PHP 5.3 we’ll finally get a little of what we want and this is good news. With data structures like stack,  queue, heap or priority queue implemented in C we expect PHP programming to become somewhat more efficient.

Inspired by this post http://blueparabola.com/blog/spl-deserves-some-reiteration we decided to run our own benchmarks to either verify or disapprove the results posted. Our benchmarks were executed on a 64bit RHEL with PHP 5.3.0beta1. As you may expect, we carefully excluded startup or compilation time and measured only the code blocks in question. We used getrusage() to determine CPU time consumption. A huge number of iterations guaranteed smooth results.

The first structure under consideration was the SplFixedArray. If you only need numerical indices you now can create an array of fixed size that does not have to grow while more and more items are inserted. Dealing with an SplFixedArray saves you about 10 percent of runtime compared to a plain old PHP array.

Next we tried the SplStack and SplQueue. It is usually easy to implement a stack and a queue with plain arrays. Using array_push(), array_pop() and array_shift() is straightforward. It may be a surprise to the average PHP programmer to learn about the runtime behaviour of these functions. Worst is array_shift() because of the internal rehashing and the experienced PHP programmer may – for critical code at least – try to access arrays by indices maintaining counters, for example. This is much more efficient. Compared to the functions, at least SplQueue is something like an upset, but it is possible to find comparable solutions with plain PHP.

bars_full_ok

There is a little danger to compare apples and pears when turning towards SplHeap and SplPriorityQueue. What is the proper representation of a heap implemented using plain old arrays only? It’s a sorted array, ok. But a heap is sorted for each insert, so, do we really have to sort the array for each insert? Who will do this in real life?

It’s the use case that decides about the sorting strategy. If you are supposed to carefully separate writing the heap and reading from it, it is sufficient to sort it once. That way you beat SPL. But if you have to mix reading and writing arbitrarily the SPL will beat plain arrays by far. This is shown in the pictures below. For the mixed strategy we read once for 5 inserts and the SplMinHeap scales very well. The same holds for SplMaxHeap and SplPriorityQueue.

splminheap_rw_separated

splminheap_rw_mixed

Lessons learned:

  • SPL rules
  • use SPL data structures where appropriate for a particular use case, they are efficient and comfortable
  • benchmarking is error prone
  • anyway, always benchmark performance critical code blocks

Google Gadgets – Jetzt auch bei uns

Ein wenig Schweiß und Fleiß war schon vonnöten, doch seit heute sind wir mit den ersten Gadgets online. Basierend auf dem Google-Gadget Standard haben wir die Möglichkeit geschaffen, dynamische Inhalte von Drittanbietern in unsere Gruppenseiten einzubinden.

Unser besonderer Dank gilt hier Chris Chabot von Google, der die Basis des von uns eingesetzten Shindig Servers entwickelt hat. Natürlich waren noch einige studiVZ-spezifische Anpassungen notwendig. Unter Anderem haben wir zusätzlich zum Standard den “Group”-View eingeführt, der speziell für die Anzeige von Gadgets in Gruppen optimiert ist. Auch müssen Anbieter von Gadgets nicht mehr um die Last auf ihren Servern bangen, denn dank intelligenter Verteilung der statischen Inhalte auf unserer CDN Farm, ist die Verfügbarkeit der Inhalte gewährleistet.

Wir befinden uns noch in der Beta-Phase, weitere Funktionalitäten werden folgen. Ihr dürft also gespannt sein ;)

Die ersten Fussballverein-Gadgets in Kooperation mit Bild.de könnt ihr in den folgenden Gruppen bewundern:

studiVZ

bild_de_gadget_2009-02-18_105706

schülerVZ

meinVZ

Google sowie das Logo sind ein eingetragenes Zeichen von Google Inc.