Verwenden Threads virtuellen oder realen Speicher?

10

Ich habe versucht, meinen Linux-Server so zu optimieren, dass er 10.000 Threads pro Prozess verarbeitet, während dies derzeit nur 382 sind. Gemäß diesem Artikel wird die folgende Formel verwendet, um die insgesamt möglichen Threads herauszufinden:

number of threads = total virtual memory / (stack size*1024*1024)

Dies bedeutet, dass Threads alle ihre Daten im virtuellen Speicher speichern. Und nach meinem besten Wissen ist virtueller Speicher ein Swap-Speicherplatz auf einem Linux-Computer, der auf einer Festplatte als RAM oder Cache gespeichert ist.

Meine Frage ist also, ob unsere Threads Festplatten verwenden, um ihre Daten zu verarbeiten / zu speichern.

Wenn ja, wirkt sich dies nicht auf die Leistung aus? Können wir die Leistung verbessern, indem wir sie in RAM oder Cache einfügen? Wie?

Wenn nein, wie genau funktionieren Threads?

Aktualisieren:

Nach der Antwort von nutzlos ist der virtuelle Speicher ein System, das ungefähr Folgendes umfasst:

  • physischer Speicher (RAM)
  • Alle Swap-Dateien, die Sie angehängt haben
  • Hardware-Unterstützung für die Übersetzung virtueller in physische Adressen und die Ausgabe von Seitenfehlern, wenn eine virtuelle Adresse nicht im physischen Speicher verfügbar ist
  • (Kernel-) Softwareunterstützung für: Verwalten der von dieser Hardware verwendeten Nachschlagetabellen zur Behandlung dieser Seitenfehler durch Abrufen von Seiten aus dem Swap bei Bedarf

Somit befindet sich alles, was sich im virtuellen Speicher befindet, zusammen im RAM (Real Memory) und auf der Festplatte (Swap Files). Und wie James in seiner Antwort erklärt, trifft Kernel die Entscheidung für Ram vs HDD mithilfe von Algorithmen wie LRU.

dragosrsupercool
quelle
2
Wenn Ihr Server nicht über 10.000 CPU / Kerne verfügt, verschwenden Sie Ihre Zeit.
@ JarrodRoberson: Warum ist das so?
Dragosrsupercool
3
10.000 Threads sind kein guter Weg, um die Skalierung zu verbessern. Es ist ein guter Weg, um einen Server zum Crawlen zu bringen. Mehr als 1 Thread pro CPU oder Core führt nur dazu, dass der Serverkontext wechselt und langsamer und nicht schneller ausgeführt wird.
Insbesondere, wenn Sie "versuchen, meinen Linux-Server zu optimieren" sagen - was versuchen Sie zu optimieren? Wenn es sich um einen Durchsatz handelt, ist wahrscheinlich ein Thread pro CPU mit Multiplexing und nicht blockierenden E / A besser.
Nutzlos

Antworten:

12

Nach meinem besten Wissen ist virtueller Speicher Swap Space in einer Linux-Maschine

Nein, virtueller Speicher ist ein System, das ungefähr Folgendes umfasst:

  • physischer Speicher (RAM)
  • Alle Swap-Dateien, die Sie angehängt haben
  • Hardware-Unterstützung für die Übersetzung virtueller in physische Adressen und die Ausgabe von Seitenfehlern, wenn eine virtuelle Adresse nicht im physischen Speicher verfügbar ist
  • (Kernel) Software-Unterstützung für:
    • Verwalten der von dieser Hardware verwendeten Nachschlagetabellen
    • Behandeln Sie diese Seitenfehler, indem Sie Seiten bei Bedarf aus dem Swap ziehen

Es ist Sache des Kernels, sicherzustellen, dass der gewünschte virtuelle Speicher im RAM zwischengespeichert wird, wenn Sie dies möchten - es sei denn, Sie schreiben Ihre eigene VM-Schicht für den Benutzerbereich (wie dies bei Datenbanken häufig der Fall ist, iiuc).

Nutzlos
quelle
Ok, meine Annahme des virtuellen Speichers war falsch. Wie auch immer, eine kurze Folgefrage. Würde die vollständig geladene maximale Thread-Leistung beeinträchtigt, wenn der SWAP-Speicherplatz mehr als RAM ist?
Dragosrsupercool
@dragosrsupercool: Ihr Swap-Speicherplatz wird immer größer als der physische Speicher sein, andernfalls muss möglicherweise virtueller Speicher verwendet werden.
Bryan Oakley
1
@BryanOakley: Das ist nicht unbedingt wahr. Einige Betriebssysteme weisen jeder zugewiesenen virtuellen Seite eine Auslagerungsseite zu (dh die Auslagerung muss mindestens so groß wie die physische sein). Andere Betriebssysteme weisen eine Auslagerungsseite nur zu, wenn eine Seite aus dem physischen Speicher verschoben werden muss (dh der Auslagerungsvorgang kann geringer als der physische sein). Ersteres hat den Vorteil, dass bei erfolgreicher Zuweisung das Auslagern des Speichers immer erfolgreich ist. Letzteres hat den Vorteil, dass Sie keine großen Auslagerungsdateien pessimistisch zuordnen müssen, um relativ seltene Situationen zu berücksichtigen.
mcmcc
1
@dragosrsupercool, die Leistung wird nicht durch die Menge an RAM, Swap oder das Verhältnis zwischen ihnen beeinflusst, es sei denn, Sie haben wenig RAM und tatsächlich Paging. sar kann Sie über die Paging-Aktivität iirc informieren (aktiviert: sar -Bunter Linux).
Nutzlos
@Useless: Ich möchte die Anzahl der Threads erhöhen, bis ich den Arbeitsspeicher vollständig ausnehme und nicht mit dem Paging beginne.
Dragosrsupercool
14

Wenn der Thread tatsächlich ausgeführt wird, muss sich die aktuelle Anweisung und alle vom Thread verwendeten Variablen im physischen Speicher befinden.

Die meisten (tatsächlich fast alle) Programme befinden sich im virtuellen Speicher, und die meisten Programme verwenden den virtuellen Speicher zum Speichern von Variablen.

Virtuelle Adressen, die in Blöcken organisiert sind, die als Seiten bezeichnet werden (dies sind normalerweise 4096- oder 8192-Byte-Blöcke).

Zu jedem Zeitpunkt wird jeder Block des virtuellen Speichers irgendwo im realen Speicher oder auf der Festplatte in dem dafür reservierten "Swap Space" gespeichert.

Ihr Programmcode behandelt virtuelle Adressen, wenn Sie zu einer virtuellen Adresse verzweigen oder den Zugriff auf den Speicher an einer virtuellen Adresse anfordern. Das System (normalerweise auf Hardwareebene) sucht den aktuellen Speicherort der Adressanforderung und ordnet ihn Ihrer virtuellen Adresse zu. Wenn sich die Adresse derzeit auf der Festplatte befindet, wird sie in den realen Speicher verschoben und anschließend die Adresse zugeordnet.

Wenn der gesamte physische Speicher verwendet wird, wenn etwas ausgelagert wird, muss natürlich etwas anderes ausgelagert werden. Daher sucht das System nach der Seite "Am wenigsten verwendet" und kopiert diese auf die Festplatte, bevor die angeforderte Seite kopiert wird.

In modernen Systemen gibt es verschiedene Optimierungen und Tricks im Zusammenhang mit virtuellem Speicher.

  • Adressen werden "pro Prozess" zugeordnet, sodass beispielsweise alle C-Programme in einer Linux-Box den "Haupt" -Prozess an derselben Adresse starten.
  • Dies kann es mehreren 32-Bit-Prozessen ermöglichen, viel mehr als 4 GB auf einem Computer zu belegen und zu verwenden, da eine virtuelle 32-Bit-Adresse einer realen 64-Bit-Adresse zugeordnet werden kann.
  • Wenn Prozesse beendet werden oder der Speicher anderweitig "frei" ist, markiert das System die Seiten nur als frei, sie werden niemals zurück auf die Auslagerungsdiskette kopiert.
  • In ähnlicher Weise greift das System nur auf eine freie Seite im realen Speicher zu, wenn ein neuer Speicherblock angefordert wird. Nein, es findet eine Festplatten-E / A statt.
  • Die Funktionen "Ruhezustand" und "Ruhezustand" erzwingen, dass der gesamte Speicher in den Auslagerungsbereich kopiert wird, damit alle aktuellen Prozesse und der aktuelle Speicherinhalt beim Aufwecken neu erstellt werden können.
James Anderson
quelle
3
Die "Alle C-Programme in einer Linux-Box starten [main] an derselben Adresse" scheinen die Randomisierung des Adressraum-Layouts nicht zu berücksichtigen. Das wird heutzutage immer häufiger verwendet, um verschiedene Stack-Smashing-Angriffsschemata zu vereiteln. Ansonsten gute Antwort, also +1.
Ein Lebenslauf
7

Zunächst müssen Sie mehr über den Computerspeicher lesen , da Ihnen anscheinend die Kenntnisse auf diesem Gebiet fehlen.

Ein Ausführungsthread ist die kleinste Verarbeitungseinheit, die von einem Betriebssystem geplant werden kann. Die Implementierung von Threads und Prozessen unterscheidet sich von Betriebssystem zu Betriebssystem, in den meisten Fällen ist jedoch ein Thread in einem Prozess enthalten. Innerhalb desselben Prozesses können mehrere Threads vorhanden sein und Ressourcen wie den Speicher gemeinsam nutzen, während verschiedene Prozesse diese Ressourcen nicht gemeinsam nutzen.

Threads werden also den verfügbaren Speicher verwenden - unabhängig davon, welche Art von Speicher verfügbar ist. Wie viele Threads Sie starten können, hängt von der Speichergröße ab und davon, wie viel Speicher pro Thread benötigt wird. Wenn der Thread Heap verwendet (nicht nur Stack), benötigt er mehr Speicher. In diesem Fall können Sie weniger Threads starten.

BЈовић
quelle
@VJonvic: +1 für grundlegende Thread-Erklärung.
Dragosrsupercool
6

Die einfache Antwort auf Ihre Frage lautet: Sie verwenden virtuellen Speicher. Alles verwendet virtuellen Speicher mit Ausnahme einiger weniger Prozesse, die sich auf das Betriebssystem beziehen.

Wenn Ihr Thread (oder ein beliebiger Thread in einem beliebigen Prozess) tatsächlich ausgeführt wird, verwendet er physischen Speicher. Die diesem Prozess zugeordneten Speicherseiten werden in den physischen Speicher eingelagert, in dem der Prozessor seine Arbeit erledigt.

Bryan Oakley
quelle
3

Der virtuelle Speicher ist Ihr RAM plus Ihr Swap-Speicher. Virtuell bedeutet nur, dass die Adresse, die Ihr Programm sieht, sich von der Adresse unterscheidet, die der RAM-Chip sieht. Wenn Sie im Swap auf den Speicher zugreifen müssen, wird er vom Betriebssystem zuerst in den Arbeitsspeicher verschoben. Wenn Sie keinen Austausch wünschen, deaktivieren Sie ihn einfach. Wenn Sie genug RAM haben, brauchen Sie es nicht wirklich.

Abgesehen davon ist das Erhöhen auf 10.000 Threads keine "Optimierung", es sei denn, Sie haben einen 10.000-Kern-Prozessor. Sobald Sie über genügend Threads verfügen, um alle Kerne zu verbrauchen, sowie ein oder zwei Ersatzkerne, wenn diese Threads blockiert sind, verringert das Hinzufügen weiterer Threads die Leistung aufgrund des Switching-Overheads und der Cache-Fehler. Möglicherweise möchten Sie immer noch mehr Threads verwenden, wenn dies Ihre Programmlogik vereinfacht, aber Sie werden die Leistung abwägen.

Karl Bielefeldt
quelle
Ja, 10.000 sind zu viel, da mein Server eine 32-Bit-Single-Core-Maschine ist. Eigentlich sind die Threads keine totale CPU-Sache. Sie sind Crawler-Threads, daher würden sie manchmal auf eine Serverantwort warten. Ich möchte sicherstellen, dass die CPU voll belegt ist, aber nicht über- oder unterlastet. Aber ich verstehe immer noch nicht, wie ich wissen kann, ob die CPU frei oder voll belegt ist. Gibt es ein Werkzeug oder einen Befehl?
Dragosrsupercool
Ich denke, Sie können diese Informationen aus dem topBefehl erhalten.
Karl Bielefeldt
@KarlBieledeldt: Ja, das war genau das, wonach ich gesucht habe. Eine weitere Folgefrage: Ich hatte gerade die Idee, zu crawlen, dass ich behalten kann, wenn ein Thread eine Anfrage nach URLs senden kann, während der andere Thread die Serverantwort empfängt CPU-Auslastung hoch ohne zu viele Threads. Ist das möglich? Möchten Sie eine Anfrage von einem Thread senden, während Sie die Antwort auf dem anderen Thread erhalten?
Dragosrsupercool
2

Optimiere meinen Linux-Server für 10.000 Threads pro Prozess

Wie andere erklärten, ist dies im Allgemeinen falsch. Ein Thread ist eine kostspielige Ressource , insbesondere weil er über einen eigenen Aufrufstapel verfügt (normalerweise ein Megabyte) und weil es sich um eine vom Kernel planbare Aufgabe handelt. Threads sind noch teurer als geöffnete Dateideskriptoren .

Lesen Sie Betriebssysteme: Drei einfache Teile (frei herunterladbares Lehrbuch).

Als Faustregel gilt, dass Sie nicht viele Threads und schon gar nicht viele ausführbare Threads haben möchten. Die Anzahl der ausführbaren Threads sollte im Allgemeinen höchstens der Anzahl der Kerne (oder einem kleinen Vielfachen davon) entsprechen, also höchstens etwa einem Dutzend. Die Anzahl der Threads in einem Prozess kann etwas größer sein. Wenn Sie also keinen sehr expansiven Server haben (mit vielen Prozessorsockeln und -kernen), möchten Sie nicht mehr als ein Dutzend ausführbare Threads und hundert Threads (die meisten davon inaktiv) in Ihrem Prozess (auf Ihrem Desktop) haben. .

Unter Linux sind Threads und Prozesse sehr ähnlich (da beide vom Klon (2) erstellt werden können ) und beide vom Kernel geplante Aufgaben sind. Tatsächlich plant der Kernel-Scheduler Aufgaben, die Threads innerhalb eines Multithread-Prozesses oder der einzelne Haupt-Thread eines Single-Thread-Prozesses (in diesem Fall werden Sie diesen einzelnen Thread als "Prozess" bezeichnen) oder Kernel-Threads sein können. Sie möchten wahrscheinlich nicht mehr als tausend planbare Aufgaben auf Ihrem Desktop-System haben.

Unter Linux ist ein Prozess einfach eine Gruppe von Threads, die denselben virtuellen Adressraum verwenden (und einige andere Dinge gemeinsam nutzen, z. B. die Dateideskriptortabelle usw.). Einige Prozesse haben nur einen Thread.

Ein virtueller Adressraum wird von Wikipedia als definiert

"die Reihe von Bereichen virtueller Adressen, die ein Betriebssystem einem Prozess zur Verfügung stellt"

(Siehe auch diese Antwort, in der erklärt wird, dass die Terminologie nicht universell ist und in einigen Microsoft-Dokumentationen eine andere und inkompatible Definition verwendet wird.)

Unter Linux ist proc (5) hilfreich, um den virtuellen Adressraum einiger Prozesse zu verstehen. Versuchen Sie beide
cat /proc/self/mapsund cat /proc/$$/mapsin einem Terminal. Siehe auch dies und pmap (1) & ps (1) & top (1) .

Alle User-Space-Programme werden in einem bestimmten Prozess ausgeführt und verwenden virtuellen Speicher, sodass jeder Prozess seinen eigenen virtuellen Adressraum hat. Der physische RAM ist eine Ressource, die vom Linux-Kernel verwaltet wird, und Anwendungen haben keinen direkten Zugriff auf den RAM (außer durch mmap (2) -ing /dev/mem, siehe mem (4) ).

Ein Prozess verwendet also nicht direkt RAM. Es verwendet virtuellen Speicher und verfügt über einen eigenen virtuellen Adressraum. Der Kernel verwendet Paging physischen RAM zu verwalten Seiten und den virtuellen Adressraum und die Verfahren liefern Abstraktionen . Zu jeder Zeit (auch wenn Ihr Prozess inaktiv ist oder ausgeführt wird) kann der Kernel einige Seiten ausblenden (z. B. sie auf der Festplatte austauschen). Der Kernel konfiguriert die MMU (und behandelt Hardware- Ausnahmen bei Seitenfehlern in einigen Interrupt-Handlern , indem er entweder die Seite von der Festplatte abruft oder einen Segmentierungsfehler an den Prozess weitergibt, siehe Signal (7) ).

Sie könnten grüne Threads über System-Threads haben (aber grüne Thread-Bibliotheken sind schwer zu implementieren und zu debuggen). Schauen Sie sich die in Go verwendeten Goroutinen an, um ein ausgefallenes Beispiel zu finden. Siehe auch setcontext (3) .

Manchmal kann Ihr System mit Thrashing experimentieren . Dies geschieht, wenn der gesamte virtuelle Speicher (der von allen Prozessen benötigt wird) den verfügbaren physischen RAM um einen großen Faktor überschreitet. Dann reagiert Ihr Computer nicht mehr. Lesen Sie mehr über die Größe des residenten Satzes , das Anforderungs-Paging , den Arbeitssatz , die Speicherüberlastung und die ASLR .

Siehe auch -für Linux- Gabel (2) , Klon (2) , mmap (2) , madvise (2) , posix_fadvise (2) , mlock (2) , execve (2) , Anmeldeinformationen (7) , pthreads (7) , Futex (7) , Fähigkeiten (7) .

Basile Starynkevitch
quelle