Kürzlich haben ich und mein Programmierteam ein kleines Hindernis für den Anforderungsmechanismus der Anwendung entdeckt. Nach einigen Überprüfungen fand ich die Grundursache.
Der Thread-Pool zum Verarbeiten von Anforderungen für die Anwendung war voll und konnte keine zusätzlichen Anforderungen verarbeiten. Nach dem Ablegen der Threads stellte ich fest, dass der Thread-Stapel im Protokollschreibbereich blockiert war. Es ist kein neues Problem, dass der Thread-Stapel im Protokollschreibbereich blockiert ist, aber ich dachte früher, dies sei das Ergebnis von etwas anderem. Aufgrund früherer Erfahrungen haben wir daher angenommen, dass das Problem nicht im Protokollschreibbereich liegt.
Nachdem wir viele Fehlerbehebungs- und Frustrationsmaßnahmen durchgeführt hatten, ohne die Hauptursache des Problems zu finden, haben wir uns den Quellcode angesehen und versucht, Hinweise darauf zu erhalten, was das Problem verursacht hat. .. Ich habe festgestellt, dass mein Code eine Protokollsperre hat. Bei dieser Protokollsperre stellte ich fest, dass in ArrayBlockingQueue.put ein Block vom Thread-Stapel vorhanden war. Weitere Untersuchungen ergaben, dass es sich um eine Blockierungswarteschlange mit einer Länge von 1024 handelte. Dies bedeutet, dass nachfolgende Put-Anforderungen blockiert werden, wenn sich 1024 Objekte in dieser Warteschlange befinden.
Der Programmierer, der diesen Code schrieb, schien zu denken, dass, wenn die BlockingQueue voll war, und dass Daten verarbeitet werden sollten. Der betreffende Code ist unten.
if (blockingQueue.retainCapacity() < 1) { //todo } blockingQueue.put
Das Problem besteht hier aus zwei Hauptteilen.
Ein vollständiges Urteil geht direkt zu "setzen" statt zu "sonst".
Die Verarbeitungslogik lautet // todo ..., auch wenn die Warteschlange voll ist.
Der obige Code zeigt, dass dieser spezielle Programmierer mit der BlockingQueue-Schnittstelle nicht vertraut ist. Sie müssen diese Entscheidung nicht zuerst treffen, um dieses Ergebnis zu erhalten. Ein besserer Weg wäre die Verwendung von blockingQueue.offer. Wenn dies als "falsch" zurückgegeben wird, können Sie die entsprechende Ausnahmebehandlung implementieren.
BlockingQueue ist eine häufig verwendete Datenstruktur im Produktions- / Verbrauchermodus. Die am häufigsten verwendeten Typen sind ArrayBlockingQueue, LinkedBlockingQueue und SynchronousQueue.
Der Hauptunterschied zwischen ArrayBlockingQueue und LinkedBlockingQueue sind die Objekte, die in die Warteschlange gestellt werden. Einer wird für Arrays und der andere für verknüpfte Tabellen verwendet. Andere Unterschiede werden auch in den Code-Hinweisen erwähnt.
Verknüpfte Warteschlangen haben normalerweise einen höheren Durchsatz als Array-basierte Warteschlangen, weisen jedoch für die meisten gleichzeitigen Anwendungen eine schlechte vorhersagbare Leistung auf.
SynchronousQueue ist eine spezielle BlockingQueue. Es wird während des Angebots verwendet. Wenn derzeit kein anderer Thread aufgenommen oder abgefragt wird, schlägt das Angebot fehl. Es schlägt auch fehl, wenn während des Take kein anderer Thread gleichzeitig das Angebot ausführt. Dieser spezielle Modus eignet sich für Threads aus Warteschlangen und nicht festen Thread-Pools mit hohen Antwortanforderungen.
Online-Geschäftsszenarien erfordern einen Timeout-Mechanismus in allen Bereichen, in denen Parallelität und externer Zugriff blockiert sind. Ich weiß nicht, wie oft ich das Fehlen eines Timeout-Mechanismus als Ursache für ein großes Hindernis für das Online-Geschäft gesehen habe. Das Online-Geschäft konzentriert sich auf die schnelle Bearbeitung und Bearbeitung von Anfragen. Ein schneller Ausfall ist daher das wichtigste Prinzip beim Entwurf von Online-Geschäftssystemen und der Code-Programmierung. Nach diesem Prinzip besteht der offensichtlichste Fehler im obigen Code darin, Put anstelle von Offer zu verwenden, wobei der Timeout-Mechanismus verwendet wird. Alternativ sollte in unkritischen Szenarien das Angebot direkt verwendet werden, und das Ergebnis von "Falsch" kann dazu führen, dass direkte Ausnahmen ausgelöst oder protokolliert werden.
Für BlockingQueue-Szenarien müssen Sie zusätzlich zum Timeout-Mechanismus die Warteschlangenlänge begrenzen. Andernfalls wird standardmäßig Integer. MAX_VALUE verwendet. In diesem Fall führt ein Fehler im Code dazu, dass der Speicher gestoppt wird.
Wenn wir über BlockingQueue sprechen, erwähnen wir auch den am häufigsten verwendeten Bereich von BlockingQueue, den Thread-Pool.
ThreadPoolExecutor verfügt über einen BlockingQueue-Parameter. Wenn hier ArrayBlockingQueue oder LinkedBlockingQueue verwendet wird und sich coreSize und poolSize des Thread-Pools unterscheiden, bietet der Threadpool zuerst die BlockingQueue an, nachdem der coreSize-Thread belegt ist. Wird gesendet werden. Bei Erfolg endet der Prozess. Dieses Szenario entspricht jedoch nicht immer den Anforderungen des Online-Geschäfts.
Online-Unternehmen arbeiten in einer schnelllebigen Umgebung und erfordern eine schnelle Verarbeitung, anstatt Anforderungen in Warteschlangen zu stellen. Tatsächlich ist es für das Online-Geschäft am besten, wenn die Anforderungen überhaupt nicht in die Warteschlange gestellt werden. Diese Art von Online-Geschäftsstruktur kann leicht zerstört werden. Dies ist eine relativ einfache, aber gute Möglichkeit, Anforderungen, die die Kapazität des Systems überschreiten, direkt abzulehnen und stattdessen eine Fehlermeldung auszugeben. .. Aber es ist ein begrenzter Mechanismus.
Beachten Sie beim Schreiben von sehr gleichzeitigem und verteiltem Code, dass nicht nur das Systemdesign, sondern auch die Details des Codes beachtet werden müssen. Auf diese Weise können Sie die oben genannten Probleme vermeiden.
Recommended Posts