# [solved] Apache mit Multithreading, PHP und die Nextcloud

## schmidicom

Nach irgend einem Update, ich weiß inzwischen selber nicht mehr so genau welches, versuchte ich fast einen Monat lang herauszufinden warum sich meine Nextcloud bei eingeschaltetem opcache immer wieder innerhalb von nur 24h komplett aufhängte. Und auch wenn sich inzwischen endlich eine brauchbare Lösung finden ließ so wüsste ich doch gern wer/was jetzt eigentlich schuld war.

Die Details:

Ich habe eine Nextcloud mit knapp 200 Usern (per LDAP von einem Active Directory) im Betrieb, von denen aber selten mehr als 10 gleichzeitig online sind. Diese Läuft auf einer Gentoo-Installation mit [zum Zeitpunkt an dem ich das hier schreibe] Apache 2.4.32, PHP 7.2.3 und einem MariaDB 10.1.31.

Was passierte:

Wie bereits erwähnte hängte sich die Nextcloud, bei eingeschaltetem opcache, mit allen möglichen und nicht wirklich hilfreichen Fehlermeldungen innert 24h auf. Und oft sogar so heftig das der ganze Apache gleich mit gerissen wurde wodurch alle die versuchten die Webseite zu öffnen nur noch einen HTTP ERROR 500 zu sehen bekommen haben. Die Fehlerlogdateien vom Apache und Nextcloud wurden dabei regelrecht zugemüllt so das diese innert kürzester Zeit ein paar GB groß waren.

Ich versuchte, unter anderem, durch das umkonfigurieren des opcache in der php.ini das alles irgendwie in den Griff zu bekommen aber nichts half. Erst vor kurzem bin ich durch mehr oder weniger zufälliges durchwälzen irgendwelcher Bugreports die nur entfernt etwas mit meinem Problem zu tun hatten darauf gekommen in der php.ini mal die persistenten MySQL-Verbindungen zu limitieren und tatsächlich es wurde besser, noch nicht gut aber dennoch deutlich besser. Nach dem vollständigen abschalten über die Option "mysqli.allow_persistent = Off" läuft nun alles wieder genau so wie es soll.

Vielleicht kann mir ja hier jemand erklären warum diese "persistenten Verbindungen" von einem Moment auf den anderen ein so heftiges Problem wurden. Mir ist das ein Rätsel...

Links:

http://php.net/manual/de/features.persistent-connections.php

http://php.net/manual/de/mysqli.configuration.phpLast edited by schmidicom on Fri May 04, 2018 5:42 am; edited 2 times in total

----------

## ChrisJumper

Hast du schon via mytop oder nach Login in die Datenbank via show processlist oder

```
mysql> show status like 'Con%'
```

Nachgeschaut wie viele Verbindungen offen sind? Vielleicht baut das System wegen einem Bug in Nextcloud immer wieder neue persistente Verbindungen auf und diese nicht mehr ab. Wodurch nach einer Zeit natürlich die Ressourcen schwinden.

Was du auch machen könntest wäre das System nachts, wenn es nicht gebraucht wird mal neu zu starten. Also MYSQL und Nextcloud deaktivieren und dann gleich wieder neu zu starten.

Zwischendrin könntest dann auch ein Backup machen.

Ansonsten ist es natürlich immer gut Vitaldaten vom System zu protokolieren und schauen ob es da hinweise gibt auf erhöhten Speicherverbrauch etc..

----------

## schmidicom

Durch das abschalten der persistenten Verbindungen läuft meine Nextlcoud stabil, daher könnte ich es gegenüber den Benutzern nicht verantworten es zu Analysezwecken wieder einzuschalten. Aber ich habe während der Fehlersuche regelmäßig einen Blick auf den Monitor von phpMyAdmin geworfen und immer kurz bevor sich der Apache mit verabschiedete schnellte die anzahl Verbindungen in die Höhe. An die Logs die davon noch übrig geblieben sind komme ich aber erst nach Ostern wieder heran (die liegen auf meinem Rechner am Arbeitsplatz). Jedoch erinnere ich mich daran das gegen Ende der Fehlersuche im Apache-Log manchmal eine "SQLSTATE[HY000] *** Too Many Connections"-Meldung auftauchte.

Inzwischen glaube ich das etwas ähnliches passiert sein muss was in dem weiter oben schon verlinkten Artikel erwähnt wird:

 *Persistente Datenbankverbindungen wrote:*   

> ...
> 
> Sie sollten sich zur Vorsicht noch ein paar Gedanken machen, wenn Sie persistente Verbindungen benutzen. Einer ist, wenn Sie über eine persistente Verbindung Tabellen sperren und das Skript diese Sperre aus welchem Grund auch immer nicht mehr aufheben kann, nachfolgende Skripte, welche die selbe Verbindung benutzen, blockieren und den Neustart von entweder dem Webserver oder dem Datenbankserver verlangen.
> 
> ...

 

EDIT: [12.04.2018]

Heute ist es wieder passiert, die Nextcloud war nicht mehr aufrufbar aber der Apache funktionierte noch. Fast zwei Wochen ohne Ausfall und dann wieder haufenweise "...SQLSTATE[HY000] [1040] Zu viele Verbindungen in..." im Log. Ich habe nun die persistenten Verbindungen wieder erlaubt und stattdessen das "max_connections"-Limit im MariaDB-Server von 151 auf 1000 hochgeschraubt, mal sehen was jetzt in den nächsten Tagen passiert oder mit viel Glück eben nicht mehr passiert...

Was ich noch sagen kann ist das nun (laut Aussage von phpMyAdmin) die Anzahl aktiver Verbindung, selbst wenn nur wenig los ist, gelegentlich kurz auf bis zu 95 hochschnellt obwohl nur 3 bis 5 Prozesse am laufen sind.

EDIT: [25.04.2018]

Also das Problem mit den zu vielen Verbindungen zum DB-Server ist wohl gelöst. Mein Apache läuft unter anderem wegen der Unterstützung von HTTP2 zwingend mit Multithreading-Support (keine Ahnung warum HTTP2 das erfordert aber darüber dürfen sich andere Gedanken machen) und das wiederum bringt den einen oder anderen MPM (bei mir ist es "event") von Apache ins Spiel welcher standardmäßig gern mal bis zu 10000 Threads gleichzeitig ausführt. Am Ende bleibt einem also nichts anderes übrig als entweder die "max_connection"-Option von MySQL/MariaDB hoch zu drehen oder den MPM von Apache stärker zu drosseln.

Was aber die allgemeine Instabilität angeht da bin ich noch dran, im Moment vermute ich das sich der gezwungenermaßen aktivierte Multithreading-Support nicht sonderlich gut mit PHP verträgt (siehe dazu auch What is thread safe or non-thread safe in PHP? und das Error-Log meines Apache). Um das zu testen habe ich meinen Apache mal so umkonfiguriert (siehe "PHP-FPM durch mod_proxy_fcgi in Apache 2.4 aktivieren") das die PHP-Unterstützung über PHP-FPM bereitgestellt wird, so ist PHP hoffentlich nicht mehr länger der Arbeitsweise des Apache-MPM "event" unterworfen.

EDIT: [26.04.2018]

Nach der einen oder anderen Google-Suche bekomme ich immer mehr das Gefühl das die Gentoo-Devs einem hier ein schönes Ei legen. Will man den eigenen Apache Beispielweise mit HTTP2-Support laufen lassen kommt man wegen den Abhängigkeiten nicht drum herum diesen mit Multithreading-Support und dem MPM "event" oder "worker" aufzusetzen, nur wird dabei dann in keinster Weise davor gewarnt das sich dies (siehe Link unten) mit PHP offenbar nicht sonderlich gut verträgt.

PHP.net - Installation on Unix systems - Apache 2.x on Unix systems - Why shouldn't I use Apache2 with a threaded MPM in a production environment?

----------

## schmidicom

Die Umstellung auf PHP-FPM war, wie es aussieht, tatsächlich die Lösung. Jetzt spuckt die Nextcloud selbst bei großem Ansturm nur noch wenige unbedeutende Fehler aus und auch das Apache-Log zeigt keine Auffälligkeiten mehr. Im Endeffekt ist es wohl offensichtlich das sich das PHP-Modul für den Apache schlicht nicht mit dem Apache-MPM "event" oder "worker" verträgt.

Falls das auch jemand so machen möchte hier meine Konfiguration:

Im Gegensatz zum Gentoo-Wiki habe ich nicht die Datei "/etc/apache2/modules.d/70_mod_php.conf" verändert sondern eine neue erstellt.

```
<IfDefine PHP-FPM>

        <FilesMatch "\.php$">

                SetHandler "proxy:unix:/var/run/php-fpm/www.sock|fcgi://localhost"

        </FilesMatch>

        # Parameters for PHP-FPM Connection

        <Proxy "fcgi://localhost" enablereuse=on max=450>

        </Proxy>

        # Set it to handle the files

        <IfModule mod_mime.c>

                AddHandler application/x-httpd-php .php .php5 .phtml

                AddHandler application/x-httpd-php-source .phps

        </IfModule>

        DirectoryIndex index.php index.phtml

</IfDefine>
```

Danach musste ich in der Datei "/etc/conf.d/apache2" nur noch den Eintrag "-D PHP" durch "-D PHP-FPM" ersetzen und sicherstellen das auch "-D PROXY" angegeben ist. Der Rest stimmt mit dem Gentoo-Wiki überein.

Nun zum PHP-FPM, im Gentoo-Wiki wird leider nicht sehr ausführlich auf die hier wichtigen stellen eingegangen weshalb ich das meiste auch selbst herausfinden musste.

1. In der Konfiguration (bei mir ist das die Datei "/etc/php/fpm-php7.2/fpm.d/www.conf") müssen alle Sockets definiert sein welche auch in der neuen Modul-Konfiguration des Apache angegeben sind. In meinem Fall sieht das so aus:

```
; The address on which to accept FastCGI requests.

; Valid syntaxes are:

;   'ip.add.re.ss:port'    - to listen on a TCP socket to a specific IPv4 address on

;                            a specific port;

;   '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on

;                            a specific port;

;   'port'                 - to listen on a TCP socket to all addresses

;                            (IPv6 and IPv4-mapped) on a specific port;

;   '/path/to/unix/socket' - to listen on a unix socket.

; Note: This value is mandatory.

listen = 127.0.0.1:9000

listen = /var/run/php-fpm/www.sock
```

2. Wenn wie bei mir ein Unix-Socket benutzt wird muss der Apache auch in der Lage sein es zu benutzen, deshalb ist es nötig die Rechte entsprechend fest zu legen:

```
; Set permissions for unix socket, if one is used. In Linux, read/write

; permissions must be set in order to allow connections from a web server. Many

; BSD-derived systems allow connections regardless of permissions.

; Default Values: user and group are set as the running user

;                 mode is set to 0660

listen.owner = apache

listen.group = apache

;listen.mode = 066
```

3. Ebenfalls sehr wichtig ist das der PHP-FPM für jede Verbindung seitens Apache auch genug Prozesse bereit stellt. Wie viele Verbindungen der Apache zu PHP-FPM aufbaut wurde bereits weiter oben in der neuen Modul-Konfiguration mit "max=450" festgelegt und nun muss das nur noch zu den Einstellungen des PHP-FPM passen:

```
pm = dynamic

; The number of child processes to be created when pm is set to 'static' and the

; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.

; This value sets the limit on the number of simultaneous requests that will be

; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.

; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP

; CGI. The below defaults are based on a server without much resources. Don't

; forget to tweak pm.* to fit your needs.

; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'

; Note: This value is mandatory.

pm.max_children = 500

; The number of child processes created on startup.

; Note: Used only when pm is set to 'dynamic'

; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2

;pm.start_servers = 5

; The desired minimum number of idle server processes.

; Note: Used only when pm is set to 'dynamic'

; Note: Mandatory when pm is set to 'dynamic'

pm.min_spare_servers = 25

; The desired maximum number of idle server processes.

; Note: Used only when pm is set to 'dynamic'

; Note: Mandatory when pm is set to 'dynamic'

pm.max_spare_servers = 100
```

4. Im Internet habe ich gelesen das man die PHP-FPM Prozesse unter dem selben User laufen lassen sollte wie auch der Apache, warum und ob das wirklich nötig ist weiß ich nicht aber bis jetzt hat es nicht geschadet.

```
; Unix user/group of processes

; Note: The user is mandatory. If the group is not set, the default user's group

;       will be used.

user = apache

group = apache
```

Das wars, jetzt sollte sich beides in Betrieb nehmen lassen und funktionieren.

EDIT 21.08.2019:

Die Einstellung "pm = dynamic", in der Konfiguration des PHP-FPM, ist vor allem für eine Nextcloud offenbar nicht die beste Wahl. Deshalb hier eine noch eine Variante mit "ondemand" was zumindest bei mir einen deutlichen Performance-Unterschied gemacht hat.

```
pm = ondemand

; The number of child processes to be created when pm is set to 'static' and the

; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.

; This value sets the limit on the number of simultaneous requests that will be

; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.

; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP

; CGI. The below defaults are based on a server without much resources. Don't

; forget to tweak pm.* to fit your needs.

; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'

; Note: This value is mandatory.

pm.max_children = 500

; The number of child processes created on startup.

; Note: Used only when pm is set to 'dynamic'

; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2

;pm.start_servers = 5

; The desired minimum number of idle server processes.

; Note: Used only when pm is set to 'dynamic'

; Note: Mandatory when pm is set to 'dynamic'

;pm.min_spare_servers = 25

; The desired maximum number of idle server processes.

; Note: Used only when pm is set to 'dynamic'

; Note: Mandatory when pm is set to 'dynamic'

;pm.max_spare_servers = 100

; The number of seconds after which an idle process will be killed.

; Note: Used only when pm is set to 'ondemand'

; Default Value: 10s

pm.process_idle_timeout = 10s;

; The number of requests each child process should execute before respawning.

; This can be useful to work around memory leaks in 3rd party libraries. For

; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS.

; Default Value: 0

pm.max_requests = 200
```

Last edited by schmidicom on Wed Aug 21, 2019 10:42 am; edited 3 times in total

----------

## flockmock

Vielen Dank für den Beitrag, damit konnte ich NextCloud mit postgresql, apache-fpm u. php7.1 installieren läuft bis jetzt problemlos. Sehr hilfreich!

----------

## tazinblack

So ein ähnliches Phänomen hab ich auch. Hatte leider bisher keine Zeit es zu untersuchen. 

Als workaround starte ich inzwischen den Apache alle paar Stunden einfach neu.

Das ist wohl die hässlichste Art, das zu umgehen   :Confused: 

----------

## schmidicom

 *tazinblack wrote:*   

> So ein ähnliches Phänomen hab ich auch. Hatte leider bisher keine Zeit es zu untersuchen. 
> 
> Als workaround starte ich inzwischen den Apache alle paar Stunden einfach neu.
> 
> Das ist wohl die hässlichste Art, das zu umgehen  

 

Ich vermute inzwischen sogar dass das fehlerhaft arbeitende PHP-Modul durchaus in der Lage ist eine Datenbank (oder eher deren Inhalt), mit der es eventuell herumhantiert, nachhaltig zu beschädigen. Ist also möglicherweise nicht der beste "Workaround".

----------

## tazinblack

 *schmidicom wrote:*   

>  *tazinblack wrote:*   So ein ähnliches Phänomen hab ich auch. Hatte leider bisher keine Zeit es zu untersuchen. 
> 
> Als workaround starte ich inzwischen den Apache alle paar Stunden einfach neu.
> 
> Das ist wohl die hässlichste Art, das zu umgehen   
> ...

 

Dann könnte ich doch fürs Erste auch einfach USE="-threads" verwenden. Ich habe nur 5 User drauf und auf high performance kommt es nicht drauf an

----------

## schmidicom

Bei mir hat das verzichten auf "threads" wegen dem HTTP2-Support nicht geklappt.

----------

## tazinblack

 *schmidicom wrote:*   

> Bei mir hat das verzichten auf "threads" wegen dem HTTP2-Support nicht geklappt.

 

Ich wüsste nicht wo ich den brauche. Nextcloud sollte auch ohne H2 laufen, oder ?

----------

## schmidicom

 *tazinblack wrote:*   

> extcloud sollte auch ohne H2 laufen, oder ?

 

Hab ich nicht ausprobiert, kann ich also nix zu sagen aber es würde mich wundern wenn nicht. Der von mir aufgesetzte Cloud-Server für die Firma sollte einfach auf dem aktuellen Stand der Technik sein und deshalb eben mit HTTP2.

----------

## Max Steel

Für den Change von HTTP/1.1 zu HTTP/2 ist imho keine Änderung am Code von Nöten.

Weiterhin habe ich mehrere NextClouds mit HTTP/1.1 ohne PRobleme in Betrieb.

----------

## tazinblack

 *schmidicom wrote:*   

>  *tazinblack wrote:*   extcloud sollte auch ohne H2 laufen, oder ? 
> 
> Hab ich nicht ausprobiert, kann ich also nix zu sagen aber es würde mich wundern wenn nicht. Der von mir aufgesetzte Cloud-Server für die Firma sollte einfach auf dem aktuellen Stand der Technik sein und deshalb eben mit HTTP2.

 

Ihr mit eurem neumodernen Zeugs   :Laughing: 

Ne, passt schon! Danke für die Info.

Ich hab sonst nix Wildes drauf auf dem Apache. Noch phpmyadmin, nen roundcube und nen uralten postfixadmin, der inzwischen so alt ist, dass ich nur noch mit apacheseitiger Passwort-Auth drauf zugreife.

----------

## msst

Um das mal wieder hoch zu holen, das Problem besteht durchaus immer noch. Und der Work-around mit dem php-fpm ist wohl die einzige Lösung.

Wichtig noch: Dazu muß man dann freilich die ganzen apache proxy module auch einschalten:

```
APACHE2_MODULES="$APACHE2_MODULES proxy proxy_ajp proxy_connect proxy_fcgi proxy_ftp proxy_html proxy_http proxy_http2 xml2enc"
```

Nervig insgesamt. Und vor allem nextcloud macht die Probleme mit dem apache_php modul.

----------

## schmidicom

 *msst wrote:*   

> Wichtig noch: Dazu muß man dann freilich die ganzen apache proxy module auch einschalten:
> 
> ```
> APACHE2_MODULES="$APACHE2_MODULES proxy proxy_ajp proxy_connect proxy_fcgi proxy_ftp proxy_html proxy_http proxy_http2 xml2enc"
> ```
> ...

 Eigentlich müssten die beiden Module "proxy_fcgi" und "proxy" für PHP-FPM völlig reichen.

 *msst wrote:*   

> Nervig insgesamt.

 Ja das ist es...

----------

