2009-10-14 4 views
6

Ich hätte gerne ein paar Gedanken darüber, ob die Verwendung von fork {} zu 'Hintergrund' ein Prozess aus einer Schiene App ist so eine gute Idee oder nicht ...mit Kernel # fork für Hintergrundprozesse, Profis? Nachteile?

Von was ich sammeln fork {my_method; Prozess # setsid tut tatsächlich, was es tun soll.

1) schafft eine andere Prozesse mit einer anderen PID

2) nicht unterbricht den aufrufenden Prozess (zB es weiter w/o für die Gabel warten, das Kind zu beenden)

3) ausführt, bis Es endet

.. was ist cool, aber ist es eine gute Idee? Was genau macht Gabel? Erzeugt es eine doppelte Instanz meiner gesamten rails mongrel/Passagierinstanz im Speicher? Wenn das so wäre, wäre das sehr schlecht. Oder macht es das irgendwie, ohne einen riesigen Speicher zu verbrauchen?

Mein Ziel war weg zugunsten mit meinem Hintergrund-Daemon/Queue-System zu tun, um diese Prozesse von Forking (vor allem E-Mails) - aber wenn dieser Speicher nicht speichern Sie dann wird es auf jeden Fall ein Schritt in der falschen Richtung

+0

Ich würde mit dem Warteschlangensystem bleiben. Wenn Sie ein gut gepflegtes Paket dafür verwenden, müssen Sie sich keine Gedanken über Forkbombing-Exploits und die vielen anderen Details machen, die für ein gutes Warteschlangensystem benötigt werden. Dies ist ein Fall, in dem Sie darauf achten sollten, Ihren eigenen Code zu rollen, es sei denn, dies ist eindeutig erforderlich. –

+0

Warteschlangenserver ++. Vielleicht möchten Sie MQ (http://github.com/mdarby/mq) für E-Mail-Warteschlangen überprüfen. Ich habe es monatelang ohne Probleme in der Produktion verwendet. –

Antwort

0

Die Semantik von Fork besteht darin, den gesamten Speicherbereich des Prozesses in einen neuen Prozess zu kopieren, aber viele (die meisten?) Systeme tun dies, indem sie einfach eine Kopie der virtuellen Speichertabellen erstellen und sie als Kopie-beim-Schreiben markieren. Das bedeutet, dass (zumindest anfangs) nicht so viel physischer Speicher verwendet wird, gerade genug, um die neuen Tabellen und andere Datenstrukturen pro Prozess zu erstellen.

Das heißt, ich bin mir nicht sicher, wie gut Ruby, RoR, etc. mit Copy-on-Write Forking interagieren. Insbesondere kann die Speicherbereinigung problematisch sein, wenn sie viele Speicherseiten berührt (wodurch sie kopiert werden).

+0

Ich habe beide Dinge über COW gehört ... ziemlich sicher, dass einige der 1.8-Zweig es nicht unterstützt, aber REE (?). Und ich habe beide gehört, dass 1.9 COW unterstützt und nicht unterstützt. Das, sagte * auch wenn es * nicht, meine Schienen Aktion vorstellen: def do_stuff fork_and_send_email do_more_stuff Ende auch wenn die Gabel KUH nicht sofort geändert werden, der ursprüngliche Speicherplatz würde foo (aufgrund dessen, was kommt danach) und regt so eine Kopie an? Auch wenn die Gabelung der letzte Methodenaufruf war. Ich könnte mir vorstellen, dass Rails immer noch Sachen nach sich zieht, ganz zu schweigen von ... der nächsten Anfrage, die auf demselben Prozess eingeht. jsharpe

+0

verdammt, kommentieren Formatierung: def foo; Sachen machen; fork_and_send_email; do_more_stuff; ende – jsharpe

+0

Nun, ja, es würde etwas kopieren, aber hoffentlich wäre es nicht der gesamte Speicherplatz des Prozesses; es wären vielmehr einzelne Speicherseiten hier und da (auf x86-Speicherseiten sind es meist 4 Kilobyte). – wdebeaum

4

Der Fork erstellt eine Kopie Ihres gesamten Prozesses, und abhängig davon, wie genau Sie mit dem Anwendungsserver verbunden sind, eine Kopie davon. Wie in der anderen Diskussion erwähnt, ist dies mit Copy-on-Write getan, so dass es tolerierbar ist. Unix ist schließlich um die Gabel (2) herum gebaut, so dass es ziemlich schnell verwaltet werden muss. Beachten Sie, dass alle teilweise gepufferten I/O, offene Dateien und viele andere Dinge auch kopiert werden, sowie der Zustand des Programms, das im Frühjahr geladen wird, um sie auszugeben, was falsch wäre.

Ich habe ein paar Gedanken:

  • Sind Sie mit Action-Mailer? Es scheint, als wäre E-Mail mit AM oder Process.popen von etwas leicht gemacht. (Popen macht eine Verzweigung, aber es wird sofort von einer Exec gefolgt.)
  • sofort von diesem Zustand durch die Ausführung Process.exec eines anderen Ruby-Interpreter plus Ihre Funktionalität loszuwerden. Wenn es zu viel Status zu übertragen gibt oder Sie wirklich diese doppelten Dateideskriptoren verwenden müssen, können Sie etwas wie IO#popen stattdessen tun, damit Sie den Unterprozess senden können, um zu tun. Das System teilt die Seiten, die den Text des Ruby-Interpreters des Unterprozesses enthalten, automatisch mit dem Elternteil.
  • zusätzlich zu den oben genannten, möchten Sie vielleicht die Verwendung der daemons Edelstein betrachten. Während Ihr Rails-Prozess bereits ein Daemon ist, kann die Verwendung des Gems es einfacher machen, einen Hintergrund-Task als Batch-Job-Server laufen zu lassen und es einfach zu starten, zu überwachen, neu zu starten, wenn es bombardiert, und herunterzufahren. .
  • , wenn Sie Ausgang aus einem fork(2) ed subprocess Verwenden Sie dazu exit! statt exit
  • eine Message Queue und einem Daemon bereits eingerichtet, wie Sie tun, ein bisschen klingt wie eine gute Lösung für mich :-)
1

Beachten Sie, dass Sie JRuby on Rails nicht verwenden können, da fork() (noch) nicht implementiert ist.