Kürzlich musste ich ein Problem beheben, bei dem eine größere WordPress-Website nicht mehr erreichbar war, da alle PHP-Worker auf dem Server bereits damit beschäftigt waren, Anfragen zu verarbeiten. Das bedeutet im Normalfall eines von zwei Dingen: entweder haben wir viele gleichzeitig Verbindungen und der Server nicht genug Ressourcen, um sie alle schnell genug zu verarbeiten, oder die Verarbeitung der Anfragen dauert ungewöhnlich lange.

In unserem Fall konnten wir serverseitig identifizieren, dass es letzteres war. Was ist demnach passiert? Nach einen tieferen Blick fanden wir heraus, dass es eine ungewöhnliche Anzahl an Anfragen gegen eine API eines bestimmten Plugins gab, das wir benutzen. Ich werde hier nicht seinen Namen nennen, da es nicht relevant ist. Da wir serverseitig nur den Domainnamen erhalten können, entschied ich, alle Anfragen, die von der WP_Http-Klasse von WordPress verarbeitet werden, zu protokollieren (also praktisch alle, außer sie werden direkt über cURL oder Ähnliches aufgerufen).

Debugging, Debugging, Debugging

Das Debugging kann mit folgendem Code durchgeführt werden:

\add_action(
	'http_api_debug',
	static function ( array|WP_Error $response, string $context, string $class, array $parsed_args, string $url ) {
		\error_log( \print_r( $url . \PHP_EOL, true ), 3, __DIR__ . '/debug.log' );
	},
	10,
	5
);
Code-Sprache: PHP (php)

Auf diesem Weg wird jede URL einer Anfrage in eine debug.log im selben Verzeichnis geschrieben, in der dieses Skript liegt. Da es hier potenziell zu einer großen Anzahl an Daten innerhalb eines bestimmten Zeitrausm kommen kann, kannst du den Dateinamen auch anpassen, um beispielsweise ein Teil des Datums und der Uhrzeit mit anzugeben, um die Daten pro Datei zu beschränken: '/debug_' . \wp_date( 'Y-m-d-H' ) . '.log'

Ein anderes Problem tritt auf

Zuerst sah ich viele Anfragen an eine andere URL, auch von einem Plugin, aber einem anderen. Das prüfte auf verfügbare Credits für eine spezifische Aktion. Während ich dieses Verhalten grundsätzlich nachvollziehen kann, doch da es sich hier um eine Multisite mit einer großen Anzahl an Websites handelte, wurden dieselben Daten für jede der Websites erneut abgefragt. Nicht unbedingt notwendig. Insbesondere, da unser Preismodell eine unbeschränkte Anzahl an Credits beinhaltet.

Das erste, was ich demnach tat, war zu prüfen, wo diese Daten gespeichert werden (es war ein generischer Transient). Danach stellte ich sicher, dass die Daten des Transients immer von der primären Website der Multisite geladen wurden, sodass sie nur einmal täglich für eine einzelne Website aktualisiert wurden. Das hat für einige Zeit problemlos funktioniert, aber ich änderte die Prüfung für “ist Kontingent überschritten“, sodass hier immer false zurückkam, da eine unbeschränkte Anzahl an Credits bedeutet, dass es kein Kontingent gibt, das überschritten werden kann.

Ich habe darüber auch den Support kontaktiert, aber sie sagten mir, dass das so funktioniert, wie es soll. Es ist allerdings auch erwähnenswert, dass das Plugin selbst nicht für einen Multisite-Betrieb optimiert ist.

Und das initiale Problem?

Nachdem das erste Problem nun gelöst war, machte ich mich an das ursprüngliche. An dieser Stelle erweiterte ich auch die Debug-Informationen, um zu erkennen, ob die Anfrage von einem Cronjob (\wp_doing_cron()) oder via Ajax (\wp_doing_ajax()) aufgerufen wurde und ob sie aus dem Frontend oder Backend kommt (\is_admin()). Tatsächlich musste ich feststellen, dass die meisten Anfragen regulär aus dem Frontend kamen, mit einigen Ausnahmen, um zu prüfen, ob die Lizenz des Plugins noch aktiv war. An dieser Stelle kontaktierte ich den Support des Plugins, da das meiner Meinung nach nicht korrekt war. Zusätzlich war eine Zeitüberschreitung von über 30 Sekunden eingestellt, damit „ihr Loadbalancing aktiv wird“. Gut zu wissen, aber nicht so schön, wenn dadurch viele Anfragen an unseren Server blockiert werden, weil deren Loadbalancing sich Zeit lässt, und so bei uns viele PHP-Worker bindet.

Die schnelle Lösung war ähnlich zur ersten: Deaktivierung der Lizenzüberprüfung durch Überschreiben der Daten, dass die Lizenz bereits überprüft wurde und aktiv ist. Praktisch gesehen ein sogenanntes „Nulling“ des Plugins (Nulling bedeutet, wenn alle Anfragen zur Lizenzprüfung unterdrückt werden). Ich möchte hervorheben, dass das keine permanente Lösung war und die Lizenz lebenslang gültig, sodass es hier keinen Unterschied machte. Für unsere Websites dagegen machte es sehr wohl einen großen Unterschied, da sie so wieder erreichbar waren.

Es ist ebenfalls erwähnenswert, dass das Problem mit den Frontend-Anfragen gelöst wurde und seither der Lizenzserver nur einmal täglich dann aus dem Backend angefragt wird, wie es sein soll.

Fazit

Auch wenn du kein akutes Problem im Moment mit externen Anfragen deiner WordPress-Installation hast, kann es dir ebenfalls passieren. Deshalb kann es definitiv sinnvoll sein, einmal für geraume Zeit alle ausgehenden Anfragen zu protokollieren und auf verdächtiges Verhalten zu prüfen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert