Warnung: file_put_contents(/home/www/web1/html/php_dev/test.txt) [function.file-put-contents]: failed to open stream: Permission denied in /home/www/web1/html/php_dev/sys/lib.activity.php (Zeile 58)
curl_multi langsam [Archiv] - PHP-Scripte PHP-Tutorials PHP-Jobs und vieles mehr
ebiz-webhosting
- Ad -
php-resource




Archiv verlassen und diese Seite im Standarddesign anzeigen :
curl_multi langsam


 
JR-EWING
14-12-2009, 19:37 
 
Hallo zusammen

ich experimentiere gerade mit Curl Multi herum um parallel Abfragen zu senden.
Ich habe einen eigenen Server und habe leider den Fall dass Multi Curl langsamer ist als der normale Aufruf.

Aber zuerst mal der Aufbau.....

Um das zu testet, habe ich das Script von PHP: curl_multi_add_handle - Manual (http://php.net/manual/de/function.curl-multi-add-handle.php)
genommen und auf 30 Urls erweitert. Ich hab da Wikipedia, Amazon usw als Domains genommen.

Hier messe ich nun die Zeit. Danach mach ich das gleich nochmal, bloß mit normalen CURL Aufbau und vergleiche die Zeiten:


function curlopen($url) {
$ref = " ";
$ch = curl_init();
$user_agent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)";

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_HEADER, 0);
if (ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) {
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
}
curl_setopt($ch, CURLOPT_REFERER, $ref);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

curl_setopt($ch, CURLOPT_INTERFACE, $_SERVER['HTTP_HOST']);//select IP


$result = curl_exec ($ch);
curl_close ($ch);
return $result;
}


Hier schauen die Zeiten auch Top aus:


1260810149.7 : ---------- : ----------START MULTI

1260810155.89 : ---------- : ----------ENDE

1260810158.89 : ---------- : ----------START SINGLE

1260810180.45 : ---------- : ----------ENDE


Sprich normales Curl 22 Sek und Multi nur 6 Sekunden. Das hab ich ja auch erwartet.

Wenn ich nun aber die Domains tausche und 30 mal die gleiche Domain auf meinem Server abfrage, ist die parallel Abfrage langsam als die sequenzielle.


1260812134.89 : ---------- : ----------START MULTI

1260812138.98 : ---------- : ----------ENDE

1260812141.98 : ---------- : ----------START SINGLE

1260812143.96 : ---------- : ----------ENDE



Woran kann denn sowas liegen. Gibt es irgendwo ne Einstellung für Apache wieviele Anfragen er gleichzeitig machen kann, oder woran kann denn sowas noch liegen ?

Danke schon mal im voraus

Gruß Tom

 
wahsaga
14-12-2009, 19:45 
 
Danach mach ich das gleich nochmal, bloß mit normalen CURL Aufbau und vergleiche die Zeiten
Und damit dieser Versuchsaufbau sinnvoll sein kann, hast du natürlich schon ausgeschlossen, dass irgendwo (seitens cURL, PHP/Webserver, Zugangsprovider) Caching stattfindet?

 
JR-EWING
14-12-2009, 20:22 
 
Also ich hab Root Rechte und den auch selber eingerichtet.

Müsste er nicht bei beiden (multi und normal) cachen ?

es sind aber immer unterschiedliche Urls - also

domain-a.de/1.html
domain-a.de/2.html
domain-a.de/3.html
domain-a.de/4.html
domain-a.de/5.html

 
wahsaga
14-12-2009, 20:50 
 
es sind aber immer unterschiedliche Urls
Unterschiedlich zwischen was - zwei den beiden Testreihen, die du aufgebaut hast und nacheinander durchführst?

 
JR-EWING
14-12-2009, 21:07 
 
ich hab das jetzt mal umgedreht.

Vorher

$test = curlopen( 'http://188.40.xx.65/1.html');
$test = curlopen( 'http://188.40.xx.65/2.html');
$test = curlopen( 'http://188.40.xx.65/3.html');
$test = curlopen( 'http://188.40.xx.65/4.html');
$test = curlopen( 'http://188.40.xx.65/5.html');
....
curl_setopt($ch1, CURLOPT_URL, 'http://188.40.xx.65/1.html');
curl_setopt($ch2, CURLOPT_URL, 'http://188.40.xx.65/2.html');
curl_setopt($ch3, CURLOPT_URL, 'http://188.40.xx.65/3.html');
curl_setopt($ch4, CURLOPT_URL, 'http://188.40.xx.65/4.html');
curl_setopt($ch5, CURLOPT_URL, 'http://188.40.xx.65/5.html');


Nachher


curl_setopt($ch1, CURLOPT_URL, 'http://188.40.xx.65/1.html');
curl_setopt($ch2, CURLOPT_URL, 'http://188.40.xx.65/2.html');
curl_setopt($ch3, CURLOPT_URL, 'http://188.40.xx.65/3.html');
curl_setopt($ch4, CURLOPT_URL, 'http://188.40.xx.65/4.html');
curl_setopt($ch5, CURLOPT_URL, 'http://188.40.xx.65/5.html');
...
$test = curlopen( 'http://188.40.xx.65/1.html');
$test = curlopen( 'http://188.40.xx.65/2.html');
$test = curlopen( 'http://188.40.xx.65/3.html');
$test = curlopen( 'http://188.40.xx.65/4.html');
$test = curlopen( 'http://188.40.xx.65/5.html');


ist aber egal wie rum - Multi ist langsamer

Wie gesagt bei anderen Urls also Google, Amazon, Ebay usw klappt es ja

Nur bei meiner Domain, ( für die ich aber das ganze leider brauche) die auf meinen Server liegt, leider nicht :-(

 
wahsaga
14-12-2009, 21:15 
 
ist aber egal wie rum - Multi ist langsamer
Gut - das schliesst zumindest schon mal Caching als ersten Hauptverdächtigen aus.

Nur bei meiner Domain, ( für die ich aber das ganze leider brauche) die auf meinen Server liegt, leider nicht :-(
Dann würde ich erst mal schauen, ob dein Server Requests mit einer Content-Length-Angabe ausliefert. Die ist nämlich notwendig, um mehrere HTTP-Requests über eine (aufrechterhaltene) Verbindung abwickeln zu können.

Wenn er das nicht tut, dann hat cURL auch mit multi-Funktionalität keine andere Möglichkeit, als für jede Ressource eine neue Verbindung aufzubauen.
Und dass das schnell in irgendwelche Limits läuft, ist nachvollziehbar.

 
JR-EWING
14-12-2009, 21:53 
 
Sorry jetzt muss ich leider dumm fragen - du meinst sowas ?


HTTP/1.1 200 OK
Date: Mon, 14 Dec 2009 19:44:52 GMT
Server: Apache/2.2.9 (Debian)
PHP/5.2.6-1+lenny3 with Suhosin-Patch
mod_ssl/2.2.9 OpenSSL/0.9.8g
X-Powered-By: PHP/5.2.6-1+lenny3
Vary: Accept-Encoding
Content-Length: 1


also schaut so aus als würde mein Server das ausgeben. Ich hab jetzt auch mal die Anzahl der Anfragen auf 10 reduziert. Aber auch ohne Erfolg


1260820272.45 : ---------- : ----------START MULTI

1260820275.37 : ---------- : ----------ENDE

sleep(3)

1260820278.37 : ---------- : ----------START SINGLE

1260820278.85 : ---------- : ----------ENDE

 
JR-EWING
14-12-2009, 22:30 
 
hmmm ich hab jetzt das Script auch einmal auf einem anderen Server installiert.
Dort geht Multi richtig schnell - so wie es sein sollte.

Es scheint also wirklich ein Config Problem des Apache auf meinem Server zu sein.

Also Cache und Script Fehler kann ich daher ausschließen.

Gruß Tom

 
wahsaga
14-12-2009, 22:43 
 
Na dann schau dir mal an, wie viele parallele Connections dein APache erlaubt, wie viele permanente, etc.

 
JR-EWING
15-12-2009, 00:01 
 
habe den Fehler gefunden:

Es lag an Werten in der http.conf vom Apache


MaxRequestsPerChild 0


Neuer Wert

MaxRequestsPerChild 50


und schon läuft es wie gewünscht.


1260827895.35 : ---------- : ----------START MULTI

1260827895.41 : ---------- : ----------ENDE

1260827898.41 : ---------- : ----------START SINGLE

1260827898.77 : ---------- : ----------ENDE



wieder was gelernt....

 
JR-EWING
15-12-2009, 00:29 
 
hm doch zu früh gefreut - war wohl ne Ausnahme

 
AmicaNoctis
15-12-2009, 00:42 
 
Es kann sein, dass die CURL-Library das kaputtoptimiert. Normalerweise ist es teurer, eine neue Verbindung aufzubauen, als eine bestehende nochmal zu benutzen. Wenn du aber lokal arbeitest, könnte es sein, dass CURL merkt, dass es derselbe Server ist und daraufhin die bestehende Verbindung weiterbenutzt, statt für jeden Request eine neue aufzubauen. Da dann die Requests seriell erfolgen, dauert das länger.

Du könntest versuchen, einen "Connection: close"-Header zu setzen, aber ob CURL das merkt und das Verhalten dadurch ändert, kann ich jetzt nicht sagen. Einen Versuch ist es jedenfalls wert.

Generell ist das Problem aber eher theoretischer Natur, denn im Normalfall wirst du ja eher fremde (und auch verschiedene) Server mit CURL ansprechen und da macht dann ein keep-alive wieder Sinn.

Gruß,

Amica

 
JR-EWING
15-12-2009, 01:06 
 
Ich hab leider wirklich das Problem, dass ich auf meinem Server bleibe :-(

Mit Connection Close meinst du jetzt in den normalen Curl Anweisungen - also sowas ?


$header = "Connection: close \r\n\r\n";
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $header);



das erzeugt mir jetzt ein Bad Request

 
AmicaNoctis
15-12-2009, 01:10 
 
Connection ist ein Response Header, muss also vom Server gesetzt werden.

Wenn du auf lokale Ressourcen zugreifst, warum dann überhaupt CURL? Du hast doch das ganze Dateisystem vor deinen Füßen. Statt an der Nachbarwohnungstür zu klopfen, gehst du also lieber runter vor die Haustür und nutzt die Sprechanlage?

Edit:


$header = "Connection: close \r\n\r\n";
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $header);


das erzeugt mir jetzt ein Bad Request

Sollte es auch, mit CURLOPT_CUSTOMREQUEST kann man nur die Request-Methode setzen und nicht irgendwelche Header. ;)

 
JR-EWING
15-12-2009, 01:19 
 
Das Script das ich parallel 30fach aufrufen möchte, dient als Proxy Script das bestimmte APIs aufruft. Zugriff auf die API hab ich nur von meiner Server IP. Aber so kann ich die Api auch von anderen IPs nutzen.


Connection ist ein Response Header, muss also vom Server gesetzt werden.

wie mach ich das ?

 
AmicaNoctis
15-12-2009, 01:23 
 
Das Script das ich parallel 30fach aufrufen möchte, dient als Proxy Script das bestimmte APIs aufruft. Zugriff auf die API hab ich nur von meiner Server IP. Aber so kann ich die Api auch von anderen IPs nutzen.

Klingt trotzdem nicht besonders gut. Gibt es zu dieser Web-API keine direkte Schnittstelle, die du nutzen kannst?

wie mach ich das ?

Im entsprechenden Skript das zu der aufgerufenen Ressource gehört -- in PHP mit der Funktion header (http://php.net/manual/de/function.header.php).

 
wahsaga
15-12-2009, 01:49 
 
Zugriff auf die API hab ich nur von meiner Server IP.
Das klingt nach einem bewusst implementierten Sicherheits-Feature ...
Aber so kann ich die Api auch von anderen IPs nutzen.
... welches du mit deinem „Proxy-Script” unterlaufen willst.

Aber nachzufragen, ob du dir das auch wirklich gut überlegt hast, dürfte vermutlich mal wieder sinnlos sein ...?

 
JR-EWING
15-12-2009, 02:15 
 
Hi Wahsaga,

Das klingt nach einem bewusst implementierten Sicherheits-Feature ...

Bitte verstehe, dass ich nicht meine ganze Architektur aufzeigen möchte und den Sinn meines Scriptes hier aufführen will. Es würde mir ja nicht weiterhelfen, dass momentane Problem zu lösen. Das angedeutete Sichheitsfeature ist von mir selber implementiert. Es dient zum Austausch von Datenbank inhalten die ich nur zentral an einer Stelle halte. Deswegen kommt man nicht extern auf die DB und nur über die API kann man z.B. Daten einfügen. Durch curl_multi dachte ich es geht schneller und ich kann das parallel abfragen.
Ich versteh bloß nicht warum bei mir der Curl Multi so lange dauert während sequenziell es deutlich schneller geht.

Das setzen von Header Connection Close in meinem Proxy Script hat leider keine Besserung gebracht.

 
AmicaNoctis
15-12-2009, 02:34 
 
Ich frage mich trotzdem noch, warum du – gerade wenn du es selbst implementiert hast – über eine Web-API darauf zugreifst und nicht direkt im Skript. In welcher Programmiersprache ist es denn geschrieben? In PHP? Dann kannst du doch genausogut die entsprechende Klasse direkt im Code instanziieren und benutzen, statt einen Loopback-Request zu erzeugen. Wenn du bei jeder Anfrage eines Clients 30 weitere Anfragen erzeugst, verbrauchst du nur massig Ressourcen.

Wenn du nicht weiter darauf eingehen kannst, verstehe ich das, aber trotzdem sieht das für mich nach einem üblen Designfehler aus, solange keine triftigen Gründe für diesen Ansatz erkennbar sind.

 
onemorenerd
15-12-2009, 03:24 
 
Zugriff auf die API hab ich nur von meiner Server IP.Über HTTP!?! :goth:

Ich kannte mal einen, der hat die PIN für seine EC-Karte in eine Datei auf einem Server im Internet gespeichert, um sie nicht zu vergessen. Damit aber nicht jeder Hans Wurst seine PIN sehen konnte, hat er sie mit einer Passwortabfrage vernagelt. Rate mal was das Passwort war! ;)

 
AmicaNoctis
15-12-2009, 03:26 
 
rate mal was das passwort war! ;)

123456? :)

 
onemorenerd
15-12-2009, 04:03 
 
Völlig egal welches Passwort! Der Witz ist doch, dass er sich nun ein Passwort merken musste, um an seine PIN zu kommen, die er sich nicht mehr merken musste.

Der TO hat seine DB hinter einer API versteckt, um die Operationen auf und mit der DB kontrollieren zu können. Die API wird über ein Netzwerkprotokoll benutzt. Damit nicht jeder Hans Wurst die kontrollierten Operationen ausführen kann, ist der Zugriff auf localhost beschränkt.
Er hat also
- eine DB,
- eine API auf localhost, die mit der DB spricht
- ein Script auf localhost, das mit der API auf localhost spricht

Preisfrage: Was hindert das Script daran, direkt zur DB zu connecten so wie es die API macht?
Vermutlich genau so wenig wie den EC-Kartenbesitzer daran gehindert hat, seine PIN als Passwort zu wählen. ;)

Beiden gemeinsam ist, dass das eigentliche Problem (Merkzwang bzw. Sicherheit/Kontrolle) auf dem jeweiligen Weg (Passwort bzw. API) gar nicht gelöst wurde.

 
JR-EWING
15-12-2009, 10:17 
 
ja jetzt wissen wir alle, dass ich ein ganz mieser Softwaredesigner bin.

Preisfrage: Was hindert das Script daran, direkt zur DB zu connecten so wie es die API macht?
Bei mir ist es halt nicht die gleiche IP obwohls der gleiche Server ist. Aber egal.



Wäre dankbar wenn jemand noch einen Tipp hätte woran es liegen könnte, dass ich innerhalb eines Servers so einen Zeitverlust bei Curl Multi habe.



gruß Tom

 
unset
15-12-2009, 19:10 
 
Das kann so viele verschiedene Ursachen haben wie du Bibliotheken auf einem Server installiert hast. Das ist übrigens kein Vergleich, sondern eine konkrete Aussage: Um eine Antwort auf deine Frage zu erhalten, bleibt dir nichts anderes übrig als deine komplette Serverkonfiguration Preis zu geben. Aber wenn du schon Bedenken hast, uns den Sinn einer –*wie von onemorenerd ja ausführlich erläuterten – sinnlosen Architektur zu nennen, wird dir das sicherlich die Schuhe ausziehen. :rolleyes:

 
onemorenerd
15-12-2009, 19:31 
 
Bei mir ist es halt nicht die gleiche IP obwohls der gleiche Server ist.Was hat das damit zu tun?

Der Mehrwert von Multi-cURL ist übrigens nicht nur das parallele Ausführen der Requests sondern auch, dass es non-blocking parallel zum PHP-Script läuft. Daher ist nicht sehr sinnvoll, die Gesamtlaufzeit alles Requests zu messen. Du solltest nur die Zeit erfassen, die du wirklich auf cURL warten musst.

Die unterschiedliche Performance auf unterschiedlichen Plattformen kann viele Ursachen haben, z.B. Lib-Version, PHP-Version, DNS-Performance, DNS-Caches, ...

Generell sollte sequentielles cURLing ab einer nennenswerten Zahl von Anfragen niemals schneller sein als multi-threaded cURLing. Wenn das bei dir so ist, liegt es wahrscheinlich an deinen Messmethoden.


Alle Zeitangaben in WEZ +2. Es ist jetzt 02:06 Uhr.