From 1f0b8085e3d10cbe0dfa16edbeaa591bc1528a47 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 11 Jan 2026 02:30:17 +0100 Subject: [PATCH] Infrastructure: document simple webserver load monitoring --- doc/technical/infra/Webserver/Webserver.txt | 42 +++++++++++++ wiki/thinkPad.ichthyo.mm | 70 +++++++++------------ 2 files changed, 72 insertions(+), 40 deletions(-) diff --git a/doc/technical/infra/Webserver/Webserver.txt b/doc/technical/infra/Webserver/Webserver.txt index 21bcb7302..da7fe237b 100644 --- a/doc/technical/infra/Webserver/Webserver.txt +++ b/doc/technical/infra/Webserver/Webserver.txt @@ -128,3 +128,45 @@ the CSS styles and the Subtickets-Plugin (Python code). - a dump of the TracDB is also checked into that Git + +Setup and Configuration +----------------------- + +- Apache is configured with the `worker'-MPM +- Trac runs under WSGI configured with a pool of _multithread daemon processes_ + +Load and Calibration +~~~~~~~~~~~~~~~~~~~~ +As of 1/2026, we employ a simplistic load monitoring based on evaluating the +running processes and some server statistics. This is implemented as a bash script, +checked in as '/var/local/trac/scripts/collect-server-stats' and configured to run +every two minutes (via SystemD timer). The resulting data trail can be found in +'/var/log/apache2/loadwatch.csv', with the following columns: + +- Timestamp: ISO UTC min +- Sum webserver... + * Processes + * Threads + * overall resident memory (KiB) + * factor of overall memory resident +- Apache + * workload factor + * Processes + * Threads + * resident memory +- WSGI-Trac + * workload factor + * Processes + * Threads + * resident memory +- Server-statistics + * ∅ requests per second + * ∅ request duration in ms + * currently active slots + * currently idle workers + * scoreboard of slot allocation + +The parameters of the Apache MPM and the WSGI daemon are then tuned such +as to make good use of the available memory, while avoiding excess idle workers. + + diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index d6b5b73cb..dc27fd750 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -174429,8 +174429,7 @@ runner.run(test_suite()) Die Umstellung war nicht ganz einfach, da wir eine spezielle Konfiguration in der trac.ini hatten. Es ist aber ein neues Modul AccountNotificationFormatter hinzugekommen; solange das nicht aktiviert war, funktionierte die Email-Verifikation nicht mehr.

- - + @@ -174438,9 +174437,10 @@ runner.run(test_suite()) - + + - + @@ -174449,6 +174449,7 @@ runner.run(test_suite())

+ @@ -174525,7 +174526,8 @@ runner.run(test_suite()) - + + @@ -175946,7 +175948,8 @@ runner.run(test_suite()) - + + @@ -176639,7 +176642,7 @@ runner.run(test_suite()) - + @@ -178073,7 +178076,8 @@ runner.run(test_suite()) - + + @@ -179568,7 +179572,8 @@ runner.run(test_suite()) - + + @@ -179801,7 +179806,7 @@ runner.run(test_suite()) - + @@ -179908,8 +179913,7 @@ runner.run(test_suite()) Christian hat mich darauf aufmerksam gemacht, prefork ist wohl veraltet und beitet nicht optimalen Durchsatz

- -
+
@@ -179929,8 +179933,7 @@ runner.run(test_suite()) issues.lumiera.org:80 -> https://www.lumiera.org/

- - +
@@ -179944,8 +179947,7 @@ runner.run(test_suite()) Wenn in einem Prozeß die Requests im Schnitt länger als 60sek brauchen, wird der Prozeß getötet. Einzelne Requests können also durchaus länger brauchen, aber wenn sich die Dinge hochschaukeln, dann Tilt

- - +
@@ -179955,8 +179957,7 @@ runner.run(test_suite()) das heißt, wenn es 10 Minuten für einen Dämon-Prozeß nix mehr zu tun gab, wird er runtergefahren (was bei erneuten Hochfahren zusätzliche Boot-Zeit bedeutet)

- -
+
@@ -179966,8 +179967,7 @@ runner.run(test_suite()) wenn ein Request für 30 sekunden in der Eingangsqueue in WSGI steht, wird er nicht mehr verarbeitet, sondern weggeworfen (da der user sowiso nicht so lange warten wird)

- -
+
@@ -179977,8 +179977,7 @@ runner.run(test_suite()) wie lange Apache wartet, bis er eine Antwort vom WSGI-Dispatcher bekommt

- -
+
@@ -179988,8 +179987,7 @@ runner.run(test_suite()) wie lange auf Read/Writes auf den Sockets geblockt werden darf, bevor Apache abbricht

- -
+
@@ -180000,8 +179998,7 @@ runner.run(test_suite()) Das bedetuet, daß alle WSGI-Requests in diesem VServer ausschließlich vom Daemon-Process bedient werden. Ich gebe aber bewußt keine WSGIApplicationGroup an, weil dann der Default greift, daß jede Applikation und jedes unterschiedliche Skript automatisch eine eigene separate Python-Umgebung bekommt

- - +
@@ -180020,8 +180017,7 @@ runner.run(test_suite()) Im Moment ist es ehr ruhig. Die Seiten reagieren schnell

- - +
@@ -180035,8 +180031,7 @@ runner.run(test_suite()) wir verweden immer noch prefork MPM

- - +
@@ -180095,8 +180090,7 @@ runner.run(test_suite()) Das event-MPM ist besonders abgestimmt auf Web-Applikationen mit elaborierter Client-seitiger Logik, und offen gehaltenen Socket-Connections. Mit dem worker-MPM fürht das nämlich zu dem Problem, daß ein Worker-Thread während der ganzen keep-Alive-Dauer auf einen einzigen Client gebunden bleibt. Da aber in unserer Situation die Mehrzahl der Aufrufe einfachen statischen Content ausliefern, und auch eine Mehrzahl der Bots für jeden Request mit einer anderen IP daherkommt, erscheint der (definitiv vorhandene) Overhead von event-MPM nicht gerechtfertigt. Wir sollten ehr darauf zielen, unseren Speicher möglichst optimal auf möglichst viele Worker-Threads zu verteilen

- - +
@@ -180159,8 +180153,7 @@ runner.run(test_suite()) ExecStart=/var/local/trac/scripts/collect-server-stats

- - + @@ -180200,8 +180193,7 @@ runner.run(test_suite()) WantedBy=timers.target

- - + @@ -180213,8 +180205,7 @@ runner.run(test_suite()) OnUnitActiveSec=2min

- - +
@@ -180230,8 +180221,7 @@ runner.run(test_suite()) AccuracySec=1s

- -
+