Christoph Zurnieden: "Too many open files" ?

Beitrag lesen

Hallo,

Eigentlich sollte ich das so stehen lassen, aber ein paar Fragen/Kommentare hätte ich doch noch.

Naja, so leider finde ich das gar nicht. Es erfordert halt
einfach eine Konsequent saubere Programmierung -- nichts
anderes als Threadsafeness (geiles Wort, leider bestimmt
falsch ;-)

Ich kenne auch nichts anderes als "threadsafe" (Man könnte es
auch übersetzen, aber "einfädelsicher"? ;-)

Naja, aber threadsafeness? Ich bin fast sicher, es muss threadsafety
heissen ;-)

Das erste ist mehr "Zuverlässigkeit" das zweite mehr dem deutschem "Sicherheit" zuzuordnen.
Mmh...
Ach, nimm "reentrant" ;-)

Aber (für's Archiv) was genau heißt den Threadsafe in Perl?
Was gibt es da zu beachten?

Naja. Das ist bei mod_perl etwas komplizierter. Generell kann man
IMHO sagen:

  • globale Variablen *immer* initialisieren! Man kann nie wissen, was
      da nicht schon drin steht.
  • Niemals Konstrukte wie

use strict;

my $counter = 0;

addone();
    addone();

sub addone {
      $counter++;
    }

Benutzen. In 'sub addone' ist bei mod_perl nicht die lexikalisierte
  Variable '$counter' gemeint, sondern die globale Variable
  '$counter'. Das haengt damit zusammen, wie mod_perl ein Script
  sieht. Denn bevor der Code ausgefuehrt wird, macht mod_perl daraus

package Apache::ROOT::verzeichnis::zum::script;
   use Apache qw(exit);
   sub handler {
      use strict;

my $counter = 0;

addone();
      addone();

sub addone {
        $counter++;
      }
   }

Aus jedem Script wird ein Modul mit nur einer Sub (handler).
  Daraus folgt, dass man an Subroutinen grundsaetzlich *alles*
  uebergeben sollte, als Funktionsargumente. Ausserdem muss man
  natuerlich grundsaetzlich alle Variablen initialisieren!

Auf die Gefahr hin, Dich zu wiederholen: man sollte _immer_ und _überall_ _alle_ Variablen initialisieren. Ausnahmen nur für Experten und auch nicht in jeder Sprache.

  • Dann gilt: Scripte, die auf mod_perl laufen sollen, grundsaetzlich
      *sehr* gut durchtesten. Es kann sehr gut sein, dass ein
      Fehlerverhalten erst nach einer gewissen Zeit auftritt. Das liegt
      daran, dass der Apache forked: in jedem Apache-Prozess wird das
      Script neu geladen. Und weil der Apache den Child, der den Request
      bearbeiten soll, nach dem Round-Robin-Verfahren

Round-Robin:
http://choices.cs.uiuc.edu/f-kon/RoundRobin/node1.html

aussucht, kann es
  durchaus sein, dass ein Fehlverhalten erst nach 40 oder 50
  Testlaeufen zum Vorschein kommt. Ich wuerde empfehlen, bei dem
  eigenen Testserver die Anzahl der Childs auf nur sehr wenige
  einzuschraenken. Die Alternative ist natuerlich, dem Apachen
  komplett zu verbieten zu forken. Das erreicht man, indem man ihn
  mit 'httpd -x' aufruft.

Das ist aber wenig zu empfehlen bei "gleichzeitigen" Lese/Schreibzugriffen auf gemeinsame Dateien. (Datenbank etc)
Also Vorsicht bei scheinbar simplen Lösungen ;-)

  • Man sollte niemals $^W abschalten. mod_perl schreibt alle Warnings
      ins Errorlog, ein unersetzbares Werkzeug.

So man denn eins hat >;->
Nein, der war zu fies, denn ziehe ich, wenn auch nur halbherzig, zurück ;-)

  • Ich kann es nie oft genug wiederholen: vorsicht mit globalen
      Variablen! Globale Variablen erhalten ihren Wert fuer die gesamte
      Lebensdauer des Apache-Kind-Prozesses!

Globale Variablen sind selten threadsafe. Das gilt für alle Sprachen.

(In Pseudo-Perl)

$pi = 3.1415;

geht,

$name = "Heinz";

sub foo(){
 if($name == "Heinz")
 code-for-Heinz
 else
 code-for-otto
}
sub bar(){
 $name ="Otto";
}

gibt Probleme, die hier eindeutig sind. Das kann sich aber auch ganz unangenehm verstecken, wie im folgendem Beispiel:

Eine typische Falle waere
  beispielsweise

use strict;
    use vars qw($user);

use CGI;
    my $cgi = new CGI;

$user = 1 if $cgi->param('username') eq 'admin' and $cgi->param('password') eq 'strenggeheim';

Wenn hier die Authentifizierung fehl schlaegt, ist $user trotzdem
  noch 1! Ein moeglicher Loesungsansatz waere:

$user = $cgi->param('username') eq 'admin' && $cgi->param('password') eq 'strenggeheim' ? 1 : 0;

  • Wichtig ist auch, daran zu denken, dass Scripte nicht im Namespace
      'main' laufen, sondern in einem eigenen Namespace. Das haengt, wie
      weiter oben schon erwaehnt, damit zusammen, dass mod_perl aus
      Scripten ein Modul macht.

Sollte aber nicht zu sehr verführen! ;-)

  • Man kann @INC zur Laufzeit nicht mehr aendern! mod_perl ist ein
      laufender Apache-Prozess, da kann man @INC nicht mehr veraendern.

Sollte eigentlich in mod_perl eingebaut werden können. Was habe ich hier? mod_perl-1.26, dann schau ich mal.
Aber nur gucken! ;-)

  • Module werde nicht neu geladen. Das heisst, wenn das Script das
      erste mal laeuft, wird das Modul frisch geladen. Beim zweiten mal
      nicht mehr. Um das zu erreichen, muss man...

- den Server neu starten.

Naja ;-)

- Apache::Reload benutzen. AFAIK ist das eine Weiterentwicklung
    von Apache::StatINC und wird so benutzt:

PerlInitHandler Apache::Reload

Jetzt gibt es zwei Moeglichkeiten. Die erste ist das implizite
    registrieren von Modulen. Das erfordert eine weitere
    Konfigurations-Direktive:

PerlSetVar ReloadAll Off

und in jedem Modul, dass neu geladen werden soll, ein

use Apache::Reload;

Das scheint mir wohl die beste Möglichkeit. Erfordert allerdings auch Schreibzugriff auf die Conf, das nicht jeder hat

- Eine Touch-Datei definieren. Man kann mit mod_perl eine Datei
    definieren, auf die ein stat() gemacht wird. Wenn die Access-Time
    sich geaendert hat, dann werden die Module neu geladen. Das geht
    auch mit einer Konfigurations-Direktive:

PerlSetVar ReloadTouchFile /tmp/reload_modules

(In /tmp würde ich nie etwas lagern. Man muß immer damit rechnen, daß der liebe Sysadmin jederzeit ein 'rm -rf /tmp/*' ausführen kann)

  • Man sollte mit den Modulen aufpassen.

Gibt es da noch keine Unterscheidung bezüglich reentrance?

  • Die SheBang-Zeile hat keinen Einfluss mehr.

Erklärung(?):
Da alles in ein sub{} gesetzt wird, steht diese Zeile nicht mehr am Anfang und ist somit ein simpler Kommentar.

Puh. Mehr faellt mir jetzt nicht ein, aber ich bin sicher, da gibt
es noch mehr zu beachten.

Noch ist dieser Thread verlängerbar ;-)

Zumindest die, die mir so unter die Finger gekommen sind.

Meiner leider nicht.

Wie sieht es denn da aus?

Da wird Perl ganz normal als CGI-Prozess benutzt :-)

Und da wundern sich die Leute, wenn ich CGI als zweifelhaften Workaround ansehe ;-)
Ist doch wirklich nicht so schwer ein Modul zu bauen, geschweige denn an den Apachen anzuhängen, oder?

Das kann bei den Default(?)grenzen von 1024 aber schnell
mal passieren.

Naja, also eigentlich ja nicht. Und IMHO liegen die Grenzen
auch hoeher, aber das ist natuerlich in hoechstem Masse
systemabhaengig.

Nein, gottseidank nicht, sie sind einstellungsabhängig.

Na, das ist in diesem Fall doch dasselbe :-)

Aha, dann Mißverständnis, ich ziehe die Grenze zum System sehr hart an Hardware/Objektcodierung. Alles, was sich irgendwie (ohne Reboot ;-) einstellen läßt, fällt da nicht drunter. (sozusagen: System = 'uname -a')

Ach, ich weiss auch nicht. Der ISP war anfangs recht gut, ich
hatte sehr viele Freiheiten. Aber jetzt... ich hab nichtmal
mehr ein eigenes Errorlog. Und dann

Noch nicht einmal einen Errorlog?
Na, _das_ ist aber ziemlich hart!

Ja. Sagte ich ja. Und vom Support-Team kommen nur dumme Kommentare
wie 'Leider koennen wir Ihnen kein Errorlog zur Verfuegung stellen'.
Naja, wird Zeit, dass ich (wieder mal) umziehe :-)

Dann ist's wirklich dringend.
Hatte nicht letzte Tage hier mal jemand Teilhaber gesucht? ;-)))

bezahle ich auch noch einen ziemlich teuren Preis dafuer. Der
ISP ist all- -- den Rest musst du dir selber suchen ;-))

"all-exclusive" ? >;->

*hehe* fast ;-))

Kenne mich da nicht aus. (Und zu faul Google zu bemühen ;-)

Kannst es mir ja heimlich stecken.

Kleine Schwester war so nett, meinte: "Tonline wird nix geschenkt!" ;-)

Wenn's nur nicht immer so ein Aufwand wäre, nicht? KK stellen,
neuen Hoster suchen, da alles finden und wahrscheinlich auch noch
dies und das portieren usw.

Jo... Das anpassen der Scripte ist das muehsamste. Ueberall
Pfadangaben aendern.

'man m4' ?

Au, au, au, nich' hauen!

;-)))

so short

Christoph Zurnieden