Beim Programmieren einer Anwendung mit Zend und IBM DB2 bin ich auf ein Phänomen gestoßen, das zunächst unerklärlich schien. Führte ich einen langen Query aus (in diesem Fall sollte ein längerer XML-String in ein XML-Datenfeld der IBM DB2 Express-C geschrieben werden), so stürzte Apache ohne Fehlermeldung ab. In den Logs tauchte nur „restarting“ auf, sonst nichts.
Nach etwas Recherche stellte sich heraus, dass wohl eine fehlerhafte Implementierung der PCRE-Erweiterung Schuld an dem Desaster ist. Ist Backtracking auf einen zu hohen Wert eingestellt, so konsumiert PCRE (Zend Framework benutzt preg_match(), um SQL-Queries auf Korrektheit zu prüfen) den gesamten Stack, wodurch der Prozess sang- und klanglos abgeschossen wird.
Eine Erklärung zu PCRE-Backtracking gibt es hier: http://www.regular-expressions.info/catastrophic.html.
Für PHP ist die Lösung relativ simpel, der voreingestellte Wert von 100.000 für pcre.backtrack_limit und pcre.recursion_limit muss (entgegen einiger Aussagen in diversen Bugreports und Tutorials) heruntergesetzt werden. In meiner PHP.ini sieht das zurzeit folgendermaßen aus:
1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 | [Pcre] ;PCRE library backtracking limit. ; http://php.net/pcre.backtrack-limit pcre.backtrack_limit=1000 ;PCRE library recursion limit. ;Please note that if you set this value to a high number you may consume all ;the available process stack and eventually crash PHP (due to reaching the ;stack size limit imposed by the Operating System). ; http://php.net/pcre.recursion-limit pcre.recursion_limit=1000 |
Damit laufen meine Queries (~1800 Zeichen pro Query) anstandslos durch. Bei Bedarf kann dieser Wert auch weiter abgesenkt werden, auf 500 zum Beispiel. Da die PCRE-Funktion einen Aufwand von O(2^n) hat, bringt auch diese relativ kleine Änderung wieder recht viel.