Lösung 1:
Ein "Vorschlagshammer"-Ansatz wäre jedoch ein Upgrade auf ein 64-Bit-Betriebssystem (dies ist 32-Bit), da das Layout der Zonen anders erfolgt.
OK, also werde ich hier versuchen zu beantworten, warum Sie hier einen OOM erlebt haben. Hier spielen mehrere Faktoren eine Rolle.
- Die Auftragsgröße der Anfrage und wie der Kernel bestimmte Auftragsgrößen behandelt.
- Die ausgewählte Zone.
- Die Wasserzeichen, die diese Zone verwendet.
- Fragmentierung in der Zone.
Wenn Sie sich das OOM selbst ansehen, ist eindeutig viel freier Speicher verfügbar, aber OOM-Killer wurde aufgerufen? Warum?
Die Auftragsgröße der Anfrage und wie der Kernel bestimmte Auftragsgrößen behandelt
Der Kernel weist Speicher nach Reihenfolge zu. Eine „Bestellung“ ist ein Bereich von zusammenhängendem RAM, der erfüllt werden muss, damit die Anforderung funktioniert. Ordnungen werden nach Größenordnungen (daher die Namensordnung) mit dem Algorithmus 2^(ORDER + 12)
geordnet . Also, Ordnung 0 ist 4096, Ordnung 1 ist 8192, Ordnung 2 ist 16384 und so weiter und so fort.
Der Kernel hat einen fest codierten Wert, der als "hochrangig" angesehen wird (> PAGE_ALLOC_COSTLY_ORDER
). Dies ist Ordnung 4 und höher (64 KB oder höher ist eine höhere Ordnung).
Hohe Ordnungen werden für Seitenzuweisungen anders erfüllt als niedrige Ordnungen. Eine hochrangige Zuweisung, wenn der Speicher nicht abgerufen werden kann, wird dies bei modernen Kerneln tun.
- Versuchen Sie, die Komprimierungsroutine für den Speicher auszuführen, um den Speicher zu defragmentieren.
- Nie Rufen Sie OOM-Killer an, um die Anfrage zu erfüllen.
Ihre Bestellgröße ist hier aufgeführt
Dec 27 09:19:05 2013 kernel: : [277622.359064] squid invoked oom-killer: gfp_mask=0x42d0, order=3, oom_score_adj=0
Order 3 ist die höchste der Low-Order-Anforderungen und ruft (wie Sie sehen) OOM-Killer auf, um zu versuchen, sie zu erfüllen.
Beachten Sie, dass die meisten Userspace-Zuweisungen keine höherwertigen Anfragen verwenden. Typischerweise ist es der Kernel, der zusammenhängende Speicherbereiche benötigt. Eine Ausnahme hiervon kann sein, wenn der Userspace Hugepages verwendet - aber das ist hier nicht der Fall.
In Ihrem Fall wird die Zuweisung der Reihenfolge 3 vom Kernel aufgerufen, der ein Paket in die Warteschlange des Netzwerkstapels stellen möchte - dazu ist eine 32-kb-Zuweisung erforderlich.
Die ausgewählte Zone.
Der Kernel teilt Ihre Speicherbereiche in Zonen ein. Dieses Zerhacken erfolgt, weil auf x86 bestimmte Speicherbereiche nur von bestimmter Hardware adressierbar sind. Ältere Hardware kann beispielsweise nur Speicher in der 'DMA'-Zone adressieren. Wenn wir Speicher zuweisen wollen, wird zuerst eine Zone ausgewählt und nur der freie Speicher aus dieser Zone wird bei der Zuordnungsentscheidung berücksichtigt.
Obwohl ich nicht ganz auf dem neuesten Stand des Wissens über den Zonenauswahlalgorithmus bin, besteht der typische Anwendungsfall nie darin, von DMA zuzuweisen, sondern normalerweise die niedrigste adressierbare Zone auszuwählen, die die Anforderung erfüllen könnte.
Während OOM werden viele Zoneninformationen ausgespuckt, die auch aus /proc/zoneinfo
entnommen werden können .
Dec 27 09:19:05 2013 kernel: : [277622.359382] DMA free:2332kB min:36kB low:44kB high:52kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15968kB managed:6960kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:8kB slab_unreclaimable:288kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? yes
Dec 27 09:19:05 2013 kernel: : [277622.359393] Normal free:114488kB min:3044kB low:3804kB high:4564kB active_anon:0kB inactive_anon:0kB active_file:252kB inactive_file:256kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:894968kB managed:587540kB mlocked:0kB dirty:0kB writeback:0kB mapped:4kB shmem:0kB slab_reclaimable:117712kB slab_unreclaimable:138616kB kernel_stack:11976kB pagetables:0kB unstable:0kB bounce:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:982 all_unreclaimable? yes
Dec 27 09:19:05 2013 kernel: : [277622.359404] HighMem free:27530668kB min:512kB low:48272kB high:96036kB active_anon:2634060kB inactive_anon:217596kB active_file:4688452kB inactive_file:1294168kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:36828872kB managed:36828872kB mlocked:0kB dirty:0kB writeback:0kB mapped:183132kB shmem:39400kB slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:430856kB unstable:0kB bounce:367564104kB free_cma:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
Die Zonen, die Sie haben, DMA, Normal und HighMem, weisen auf eine 32-Bit-Plattform hin, da die HighMem-Zone auf 64-Bit nicht vorhanden ist. Auch auf 64-Bit-Systemen wird Normal auf 4 GB und mehr abgebildet, während es auf 32-Bit bis zu 896 MB abbildet (obwohl der Kernel in Ihrem Fall meldet, dass er nur einen kleineren Teil als diesen verwaltet:- managed:587540kB
.)
Woher diese Zuordnung kam, kann man noch einmal in der ersten Zeile gfp_mask=0x42d0
erkennen sagt uns, welche Art von Zuordnung vorgenommen wurde. Das letzte Byte (0) sagt uns, dass dies eine Zuordnung aus der normalen Zone ist. Die gfp-Bedeutungen befinden sich in include/linux/gfp.h.
Die Wasserzeichen, die diese Zone verwendet.
Wenn der Speicher knapp wird, werden Aktionen zur Rückgewinnung durch das Wasserzeichen angegeben. Sie erscheinen hier:min:3044kB low:3804kB high:4564kB
. Wenn der freie Speicher „low“ erreicht, findet ein Swapping statt, bis wir den „high“-Schwellenwert überschreiten. Wenn der Speicher 'min' erreicht, müssen wir Zeug töten, um Speicher über den OOM-Killer freizugeben.
Fragmentierung in der Zone.
Um zu sehen, ob eine Anforderung für eine bestimmte Speicherordnung erfüllt werden kann, berücksichtigt der Kernel, wie viele freie Seiten und verfügbare jeder Ordnung sind. Dies ist lesbar in /proc/buddyinfo
. OOM-Killer-Berichte spucken zusätzlich auch die Buddyinfo aus, wie hier zu sehen:
Normal: 5360*4kB (UEM) 3667*8kB (UEM) 3964*16kB (UEMR) 13*32kB (MR) 0*64kB 1*128kB (R) 1*256kB (R) 0*512kB 0*1024kB 0*2048kB 0*4096kB = 115000kB
Damit eine Speicherzuweisung erfüllt ist, muss verfügbarer freier Speicher in der angeforderten Auftragsgröße oder eine höhere Zuordnung sein. Viele, viele freie Daten in den niedrigen Ordnungen und keine in den höheren Ordnungen zu haben, bedeutet, dass Ihr Gedächtnis fragmentiert ist. Wenn Sie eine sehr hochrangige Zuweisung erhalten, ist es möglich (selbst mit viel freiem Speicher), dass sie nicht zufrieden ist, da keine hochrangigen Seiten verfügbar sind. Der Kernel kann den Speicher defragmentieren (dies wird als Speicherkomprimierung bezeichnet), indem er viele Seiten niedriger Ordnung verschiebt, damit sie keine Lücken im adressierbaren RAM-Speicher hinterlassen.
OOM-Killer wurde aufgerufen? Warum?
Wenn wir also diese Dinge berücksichtigen, können wir Folgendes sagen:
- Es wurde versucht, eine zusammenhängende 32-kB-Zuweisung vorzunehmen. Aus der normalen Zone.
- In der ausgewählten Zone war genügend freier Speicherplatz vorhanden.
- Es war Speicher der Ordnung 3, 5 und 6 verfügbar
13*32kB (MR) 1*128kB (R) 1*256kB (R)
Also, wenn es gab freier Speicher, andere Befehle könnten der Bitte nachkommen. Was ist passiert?
Nun, die Zuweisung aus einer Bestellung ist mehr als nur die Überprüfung der Menge an freiem Speicher, der für diese Bestellung oder höher verfügbar ist. Der Kernel subtrahiert effektiv den Speicher aller niedrigeren Ordnungen von der gesamten freien Zeile und führt dann die minimale Wasserzeichenprüfung für das durch, was übrig bleibt.
Was in Ihrem Fall passiert, ist, unseren freien Speicher für diese Zone zu überprüfen, die wir tun müssen.
115000 - (5360*4) - (3667*8) - (3964*16) = 800
Diese Menge an freiem Speicher wird mit min
verglichen Wasserzeichen, das 3044 ist. Technisch gesehen haben Sie also keinen freien Speicherplatz mehr, um die angeforderte Zuordnung vorzunehmen. Und deshalb haben Sie OOM-Killer aufgerufen.
Behebung
Es gibt zwei Korrekturen. Ein Upgrade auf 64 Bit ändert Ihre Zonenpartitionierung so, dass „Normal“ 4 GB bis 36 GB beträgt, sodass Sie Ihre Speicherzuweisung nicht in eine Zone „standardmäßig“ verschieben, die so stark fragmentiert werden kann. Es ist nicht, dass Sie mehr adressierbaren Speicher haben, der dieses Problem behebt (weil Sie bereits PAE verwenden), sondern lediglich, dass die Zone, aus der Sie auswählen, mehr adressierbaren Speicher hat.
Der zweite Weg (den ich nie getestet habe) besteht darin, zu versuchen, den Kernel dazu zu bringen, Ihren Speicher aggressiver zu komprimieren.
Wenn Sie den Wert von vm.extfrag_threshold
ändern von 500 auf 100 ist es wahrscheinlicher, den Speicher zu komprimieren, um eine Zuordnung höherer Ordnung zu berücksichtigen. Obwohl ich noch nie mit diesem Wert herumgespielt habe - er hängt auch davon ab, was Ihr Fragmentierungsindex ist, der in /sys/kernel/debug/extfrag/extfrag_index
verfügbar ist . Ich habe im Moment keine Box mit einem Kernel, der neu genug ist, um zu sehen, was das mehr zu bieten hat.
Alternativ könnten Sie eine Art Cron-Job ausführen (das ist schrecklich, schrecklich hässlich), um den Speicher selbst manuell zu komprimieren, indem Sie in /proc/sys/vm/compact_memory
schreiben .
Ehrlich gesagt glaube ich nicht, dass es wirklich eine Möglichkeit gibt, das System so einzustellen, dass dieses Problem vermieden wird - es liegt in der Natur des Speicherzuordners, auf diese Weise zu arbeiten. Das Ändern der Architektur der von Ihnen verwendeten Plattform ist wahrscheinlich die einzige grundsätzlich lösbare Lösung.
Lösung 2:
Gleich zu Beginn:Sie sollten wirklich Entscheiden Sie sich für ein 64-Bit-Betriebssystem. Haben Sie einen guten Grund, hier bei 32-Bit zu bleiben?
Es ist schwierig, dieses Problem zu diagnostizieren, ohne sich das System genauer anzusehen, vorzugsweise zu dem Zeitpunkt, an dem es ausfällt, daher zielt mein (kurzer) Beitrag mehr oder weniger allgemein auf Speicherprobleme auf 32-Bit-Systemen ab. Habe ich erwähnt, dass die Umstellung auf 64-Bit das alles verschwinden lassen würde?
Ihr Problem ist dreifach.
Zunächst einmal ist selbst auf einem PAE-Kernel der Adressraum pro Prozess auf 4 GiB[1] begrenzt. Dies bedeutet, dass Ihre Squid-Instanz niemals mehr als 4 GB RAM pro Prozess verbrauchen kann. Ich bin mit Squid nicht so vertraut, aber wenn dies Ihr Haupt-Proxy-Server ist, reicht das möglicherweise sowieso nicht aus.
Zweitens wird auf einem 32-Bit-System mit riesigen RAM-Mengen viel Speicher in der sogenannten „ZONE_NORMAL“ verwendet, um Datenstrukturen zu speichern, die für die Verwendung des Speichers in ZONE_HIGHMEM benötigt werden. Diese Datenstruktur kann nicht selbst in ZONE_HIGHMEM verschoben werden, da der Speicher, den der Kernel für seine eigenen Zwecke verwendet, immer in ZONE_NORMAL (dh in den ersten 1GiB-ish) sein muss. Je mehr Speicher Sie in ZONE_HIGHMEM haben (in Ihrem Fall viel), desto mehr wird dies zu einem Problem, da der Kernel dann immer mehr Speicher von ZONE_NORMAL benötigt, um ZONE_HIGHMEM zu verwalten. Wenn die Menge an freiem Speicher in ZONE_NORMAL knapp wird, kann Ihr System bei einigen Aufgaben fehlschlagen, weil in ZONE_NORMAL viel ist von Dingen passiert auf einem 32-Bit-System. Alle Kernel-bezogenen Speicheroperationen, zum Beispiel;)
Drittens, selbst wenn noch etwas Speicher in ZONE_NORMAL vorhanden ist (ich habe Ihre Protokolle nicht im Detail durchgesehen), erfordern einige Speicheroperationen unfragmentierten Speicher. Wenn beispielsweise Ihr gesamter Speicher in sehr kleine Teile fragmentiert ist, werden einige Operationen, die mehr als das benötigen, fehlschlagen. [3] Ein kurzer Blick auf Ihre Protokolle zeigt eine ziemlich erhebliche Menge an Fragmentierung in ZONE_DMA und ZONE_NORMAL.
Bearbeiten:Die obige Antwort von Mlfe enthält eine hervorragende Erklärung, wie dies im Detail funktioniert.
Nochmals:Auf einem 64-Bit-System befindet sich der gesamte Speicher in ZONE_NORMAL. Auf 64-Bit-Systemen gibt es keine HIGHMEM-Zone. Problem gelöst.
Bearbeiten:Sie können hier [4] nachsehen, ob Sie oom-killer anweisen können, Ihre wichtigen Prozesse in Ruhe zu lassen. Das wird nicht alles lösen (wenn überhaupt), aber es könnte einen Versuch wert sein.
[1] http://en.wikipedia.org/wiki/Physical_address_extension#Design
[2] http://www.redhat.com/archives/rhelv5-list/2008-September/msg00237.html und https://access.redhat.com/site/documentation/en-US/Red_Hat_Enterprise_Linux/5/html /Tuning_and_Optimizing_Red_Hat_Enterprise_Linux_for_Oracle_9i_and_10g_Databases/sect-Oracle_9i_and_10g_Tuning_Guide-Hardware_Architectures_and_Linux_Kernels-a32_bit_Architecture_and_the_hugemem_Kernel.html
[3] http://bl0rg.krunch.be/oom-frag.html
[4] http://lwn.net/Articles/317814/
Lösung 3:
@MIfe hat bereits eine hervorragende Beschreibung darüber bereitgestellt, wie Speicherzuweisungen im Kernel gehandhabt werden, und Ihnen auch die richtige Lösung wie den Wechsel zu einem 64-Bit-Betriebssystem und böse Hacks wie die manuelle Speicherkomprimierung über /proc/sys/vm/compact_memory
bereitgestellt in cron
.
Meine 2 Cent wären ein weiterer Workaround, der Ihnen helfen könnte:
Ich habe festgestellt, dass Sie tcp_tso_segment
haben in Ihrem Kernel-Backtrace, so tun:
# ethtool -K ethX tso off gso off lro off
kann den Druck auf mm
verringern indem es gezwungen wird, niedrigere Ordnungen zu verwenden.
PS . eine Liste aller Offloads erhalten Sie unter # ethtool -k ethX
Lösung 4:
Die Panik entsteht, weil die Sysctl „vm.panic_on_oom =1“ gesetzt ist – die Idee ist, dass ein Neustart des Systems es in einen gesunden Zustand zurückversetzt. Sie können dies in sysctl.conf ändern.
Ganz oben lesen wir Squid Invoded Oom Killer. Sie können Ihre Squid-Konfiguration und die maximale Speichernutzung überprüfen (oder einfach zu einem 64-Bit-Betriebssystem wechseln).
/proc/meminfo zeigt eine hohe verwendete Speicherzone an, sodass Sie einen 32-Bit-Kernel mit 36 GB Speicher ausführen. Sie können auch sehen, dass der Kernel in der normalen Zone 982 Seiten ohne Erfolg gescannt hat, um Squids Speicherbedarf zu decken:
pages_scanned:982 all_unreclaimable? yes