Mindmap-Galerie Grundlegende Java-Zusammenfassung, Web-Framework, verteilte Architektur, Datenstruktur und Algorithmus sowie Kernwissen (verteilt, Big Data, Microservices)
Java-Grundkenntnisse, J2EE-Kenntnisse, Java-Web-Framework, Java-Multithreading-Kenntnisse, Java-Kernideen, RPC, verteilte Architektur, Microservices, Big Data Hive, MySQL-Optimierung, verteilte Sperren, Lastausgleich, Datenstrukturen und Algorithmen usw., P7 Zusammenfassung der Java-Kernkenntnisse der Ebene, Superzusammenfassung.
Bearbeitet um 2022-05-27 16:06:38Welche Preismethoden gibt es für Projektunteraufträge im Rahmen des EPC-Generalvertragsmodells? EPC (Engineering, Procurement, Construction) bedeutet, dass der Generalunternehmer für den gesamten Prozess der Planung, Beschaffung, Konstruktion und Installation des Projekts verantwortlich ist und für die Testbetriebsdienste verantwortlich ist.
Die Wissenspunkte, die Java-Ingenieure in jeder Phase beherrschen müssen, werden ausführlich vorgestellt und das Wissen ist umfassend. Ich hoffe, es kann für alle hilfreich sein.
Das Software-Anforderungs-Engineering ist ein Schlüsselkapitel für Systemanalytiker. Zu den Kapiteln „Anforderungserhebung“ und „Anforderungsanalyse“ gehören häufig Veröffentlichungen.
Welche Preismethoden gibt es für Projektunteraufträge im Rahmen des EPC-Generalvertragsmodells? EPC (Engineering, Procurement, Construction) bedeutet, dass der Generalunternehmer für den gesamten Prozess der Planung, Beschaffung, Konstruktion und Installation des Projekts verantwortlich ist und für die Testbetriebsdienste verantwortlich ist.
Die Wissenspunkte, die Java-Ingenieure in jeder Phase beherrschen müssen, werden ausführlich vorgestellt und das Wissen ist umfassend. Ich hoffe, es kann für alle hilfreich sein.
Das Software-Anforderungs-Engineering ist ein Schlüsselkapitel für Systemanalytiker. Zu den Kapiteln „Anforderungserhebung“ und „Anforderungsanalyse“ gehören häufig Veröffentlichungen.
Java-Grundlagen und Kernwissens-Framework
Grundprinzipien
JVM (Java Virtual Machine)
Prinzip
Arbeitsweise
Cross-Plattform-Prinzip
So erreichen Sie Plattformunabhängigkeit: Einmal kompilieren, überall ausführen
Kompilierzeit
Javac-Kompilierungsanweisung
Anweisungen zur Javap-Dekompilierung
Java-Quellcode wird zunächst in Bytecode kompiliert und dann von JVMs auf verschiedenen Plattformen analysiert. Wenn Java auf verschiedenen Plattformen ausgeführt wird, konvertiert sie den Bytecode in Maschinenanweisungen für eine bestimmte Plattform An
Warum konvertiert JVM den Quellcode zur Ausführung nicht direkt in Maschinencode?
Vorbereitung: Für jede Ausführung sind verschiedene Prüfungen erforderlich
Kompatibilität: Andere Sprachen können ebenfalls in Bytecode analysiert werden
Speichermodell
Speichermodelldiagramm
Thread exklusiv
Programm zähler
Ein kleiner Speicherplatz, der der Zeilennummernindikator des vom aktuellen Thread ausgeführten Bytecodes ist (Bytecode-Anweisungen, Verzweigungen, Schleifen, Sprünge, Ausnahmebehandlung und andere Informationen).
Jeder Thread muss über einen unabhängigen Programmzähler verfügen. Diese Art von Speicher wird auch „Thread-privater“ Speicher genannt.
Java Virtual Machine-Stack
Thread privat, die Methode erstellt bei der Ausführung eine Stapelrahmen-Datenstruktur.
Wird hauptsächlich zum Speichern lokaler Variablentabellen, Operationsstapel, dynamischer Links, Methodenexporte usw. verwendet.
Wenn jeder Thread erstellt wird, erstellt die JVM einen entsprechenden virtuellen Maschinenstapel dafür.
Die Größe der Stapelspeicherteilung bestimmt direkt, wie viele Threads ein JVM-Prozess erstellen kann.
Thread-Sharing
MetaSpace
Der Unterschied zwischen MetaSpace und permanenter Generierung (vor der PermGen JDK7-Version)
Der Metaspace nutzt lokalen Speicher und die permanente Generierung nutzt JVM-Speicher.
Vorteile von MetaSpace im Vergleich zu PermGen
Der String-Konstantenpool verfügt über eine permanente Generierung, die anfällig für Leistungsprobleme und Speicherüberläufe ist.
Die Größe von Klassen und Methoden ist schwer zu bestimmen, was es schwierig macht, die Größe der permanenten Generation anzugeben.
Die permanente Generierung führt zu unnötiger Komplexität des GC
Erleichtert die Integration von HotSpot mit anderen JVMs wie Jrockit
Haufen
Der Zuordnungsbereich der Objektinstanz
Der Unterschied zwischen Heap und Stack (Speicherzuweisungsstrategie)
Java-Speicherzuweisungsstrategie
statischer Speicher
Der Laufzeitspeicherbedarf jedes Datenziels wird zur Kompilierzeit bestimmt.
Stapelspeicher
Die Datenbereichsanforderungen sind zur Kompilierungszeit unbekannt und werden vor dem Moduleintritt zur Laufzeit bestimmt.
Heap-Speicher
Es kann nicht zur Kompilierungszeit oder vor der Ausführung des Moduleintrags ermittelt werden und wird dynamisch zugewiesen.
Der Unterschied zwischen Heap und Stack im Java-Speichermodell
Kontakt: Beim Verweisen auf ein Objekt oder Array speichert die im Stapel definierte Variable die erste Adresse des Ziels im Heap.
der Unterschied
Führungsstil
Stapel automatisch freigegeben
Heap erfordert GC
Größe des Raumes
Der Stapel ist kleiner als der Heap
Fragmentbezogen
Die vom Stapel erzeugte Fragmentierung ist viel kleiner als die des Heaps
Zuweisung
Der Stapel unterstützt statische Zuweisung und dynamische Zuweisung
Der Heap unterstützt nur die dynamische Zuordnung
Effizienz
Stack ist effizienter als Heap
Methodenbereich
Vor jdk1.8
PermGen
lokaler Speicher
jdk1.8
Metaraum
JVM-Klassenlademechanismus
Klassenlader
Starten Sie den Klassenlader
Erweiterungsklassenlader
Anwendungslader
Modell der elterlichen Delegation
Der Prozess von der Klassenkompilierung bis zur Ausführung
Der Compiler kompiliert die .java-Quelldatei in eine .class-Bytecodedatei
ClassLoader konvertiert .class-Bytecodedateien in Class<?>-Objekte in der JVM
JVM verwendet das Class<?>-Objekt, um es in ein ?-Objekt zu instanziieren
Was ist ClassLoader?
ClassLoader spielt in Java eine sehr wichtige Rolle. Es funktioniert hauptsächlich in der Ladephase der Klassendatei und sein Hauptarbeitsprinzip besteht darin, den binären Datenstrom der Klasse von außerhalb des Systems abzurufen. Es ist die Kernkomponente von Java. ClassLoader ist für das Laden des Binärdatenstroms in der Klassendatei in das System verantwortlich und übergibt ihn dann zur Verbindung, Initialisierung und anderen Vorgängen an die Java Virtual Machine.
ClassLoader-Typen (vier Typen)
BootstrapClassLoader
In C geschrieben, lädt die Kernbibliothek Java.*
ExtClassLoader
In Java geschrieben, laden Sie die Erweiterungsbibliothek javax.*
AppClassLoader
In Java geschrieben, das Verzeichnis, in dem sich der Loader befindet
Benutzerdefinierter ClassLoader
In Java geschrieben, angepasstes Laden
OSGI (dynamisches Modellierungssystem)
Garbage Collection (GC)
GC-Typ
Kleiner GC/Junger GC
Haupt-GC/Voll-GC
Full GC ist langsamer als Major GC, wird jedoch seltener ausgeführt
Lösen Sie die Bedingung „Vollständiger GC“ aus
Zu wenig Platz in der alten Generation
Nicht genügend Speicherplatz in der permanenten Generation (vor JDK7)
CMS GC scheint die Hochstufung fehlgeschlagen zu sein, Fehler im gleichzeitigen Modus
Minor GC wird in einen Bereich befördert, in dem die durchschnittliche Größe der alten Generation größer ist als der verbleibende Raum der alten Generation.
System.gc() wird im Programm explizit aufgerufen, um die JVM daran zu erinnern, die junge und alte Generation zu recyceln.
Heap-Speicher
Junge Generation
Wenn ein Objekt erstellt wird, erfolgt die Speicherzuweisung zuerst in der jungen Generation
Objekte werden kurz nach ihrer Erstellung nicht mehr verwendet und die meisten werden vom GC der jungen Generation schnell bereinigt.
Alte Generation
Große Objekte können direkt in der alten Generation erstellt werden
Wenn ein Objekt in der jungen Generation lange genug überlebt, ohne bereinigt zu werden, wird es in die alte Generation kopiert.
Der Raum der alten Generation ist im Allgemeinen größer als der der jungen Generation und kann mehr Objekte speichern.
Wenn in der alten Generation nicht genügend Speicher vorhanden ist, wird Full GC ausgeführt.
permanente Generation
Bezieht sich auf den permanenten Speicherbereich des Speichers, in dem hauptsächlich Klassen- und Metadateninformationen gespeichert werden.
Die Klasse wird beim Laden in den permanenten Bereich verschoben und der GC bereinigt den permanenten Generierungsbereich nicht.
Der permanente Generierungsbereich füllt sich, wenn die Anzahl der geladenen Klassen zunimmt, und schließlich wird eine OOM-Ausnahme (Out of Memory) ausgelöst.
In Java 8 wurde die permanente Generation entfernt und durch einen Bereich namens „Metadatenbereich“ (Metaspace) ersetzt.
Der Metaspace befindet sich nicht in der virtuellen Maschine, sondern nutzt lokalen Speicher.
Schematische Darstellung
Logikdiagramm
Recycling-Algorithmus
Mark-and-Sweep-Algorithmus
Zuerst markieren, dann löschen, ohne das Objekt zu bewegen Der Vorteil liegt in der schnellen Ausführung Der Nachteil besteht darin, dass es zu einer Speicherfragmentierung kommt. Wenn ein großes Objekt zugewiesen werden muss, kann kein ausreichend großer zusammenhängender Speicher gefunden werden, was einen weiteren GC auslöst.
Unterteilt in Objektfläche und Freifläche
Auf der Objektoberfläche entstehen Objekte
Nach der Reinigung werden überlebende Objekte von der Objektseite auf die freie Seite kopiert.
Entfernen Sie alle Objekte auf der Objektoberfläche
Geeignet für die junge Generation
Vorteil: 1. Lösen Sie das Problem der Fragmentierung 2. Weisen Sie den Speicher der Reihe nach zu, einfach und effizient 3. Geeignet für Szenarien mit geringer Objektüberlebensrate
Mangel
Sie müssen es in Stücke teilen und kopieren.
Mark-Collation-Algorithmus
Vermeiden Sie Speicherunterbrechungen
Es ist nicht erforderlich, zwei Swaps einzurichten
Geeignet für Szenarien mit hoher Objektüberlebensrate
Geeignet für ältere Menschen
Generationssammlungsalgorithmus
Eine Kombination von Garbage-Collection-Algorithmen
Entsprechend den unterschiedlichen Lebenszyklen von Objekten werden unterschiedliche Garbage-Collection-Algorithmen verwendet, um verschiedene Bereiche zu unterteilen.
Zweck: Verbesserung der JVM-Recyclingeffizienz
Beurteilung des Objektüberlebens
Referenzzählung
Barrierefreiheitsanalyse
GC-Wurzeln
Objekte, auf die von lokalen Variablentabellen im Stapel der virtuellen Maschine verwiesen wird
im Methodenbereich
Objekt, auf das durch die statische Klassenvariable verwiesen wird
Objekt, auf das durch eine Konstante verwiesen wird
Von JNI referenzierte Objekte im lokalen Methodenstapel
Was passiert, wenn es nicht erreichbar ist?
finalisieren()
Junge Generation – möglichst schnell Objekte mit kurzen Lebenszyklen sammeln
Aufteilung des Speicherplatzes Eden-Bezirk Zwei Überlebenszonen
Benutzen Sie jedes Mal einen Eden-Bereich und einen Survivor-Bereich
Jedes Mal, wenn ein kleinerer GC ausgelöst wird, wird das Alter um 1 erhöht.
Wenn das Alter standardmäßig auf 15 Jahre eingestellt ist, wird das Objekt in die alte Generation aufgenommen.
Das Alter der alten Generation kann über -XX:MaxTenuringThreshold angepasst werden
Wenn das erstellte Objekt relativ groß ist und nicht von Enden oder Survivor aufgenommen werden kann, tritt es direkt in das Alter ein.
So fördern Sie ein Objekt bei der alten Generation
Objekte, die nach einer bestimmten Anzahl von Minderjährigen überleben
Überlebensobjekt, das nicht losgelassen werden kann
Wenn der Enden-Bereich nicht untergebracht werden kann, wird direkt ein MinorGC gestartet und die Objekte im Eden-Bereich werden gelöscht.
Das neu generierte große Objekt steuert die Größe des großen Objekts über -XX: PretenuerSizeThreshold
Häufig verwendete Tuning-Parameter
-XX: SurvivorRatio
Das Verhältnis von Eden Area zu Surivor beträgt standardmäßig 8:1
-XX:NewRatio
Verhältnis der Speichergröße zwischen alter und junger Generation
-XX:MaxTenuringThreshold
Der maximale Schwellenwert für die Anzahl der GC-Zeiten, mit denen ein Objekt von der jungen Generation zur alten Generation befördert wird.
Müllsammler der neuen Generation
Stopp die Welt
Die JVM hat die Ausführung des Programms aufgrund der Ausführung von GC gestoppt.
Passiert in jedem GC-Algorithmus
Die meisten GC-Optimierungen verbessern die Programmleistung, indem sie die Zeit verkürzen, in der Stop-the-World auftritt.
Sicherheitspunkt Sicherheitspunkt
Punkte, an denen sich Objektreferenzbeziehungen während des Analyseprozesses nicht ändern
Wo Savepoint generiert wird: Methodenaufruf, Schleifenausbruch, Ausnahmesprung usw.
Wählen Sie den sicheren Punkt entsprechend aus. Wenn Sie zu wenige auswählen, wird die Wartezeit des GC zu lang. Wenn Sie zu viele auswählen, erhöht sich die Auslastung des laufenden Programms.
JVM-Betriebsmodus
Server
Die schwergewichtige virtuelle Maschine hat weitere Optimierungen am Programm vorgenommen. Startet langsamer, läuft schneller
Klient
Leicht, schnell zu starten, langsam zu laufen
Gängige Müllsammler in der jungen Generation
Die Beziehung zwischen Garbage Collectors
Es besteht eine Verbindung zwischen Garbage Collectors, was darauf hinweist, dass sie zusammen verwendet werden können.
Serieller Kollektor (-XX:UseSerialGC, Kopieralgorithmus)
Single-Thread-Sammlung: Wenn die Garbage Collection durchgeführt wird, müssen alle Arbeitsthreads angehalten werden.
Einfach und effizient, der Standard-Collector der jungen Generation im Client-Modus
ParNew-Kollektor (-XX: UseParNewGC, Kopieralgorithmus)
Die Multithread-Sammlung, andere Verhaltensweisen und Eigenschaften sind dieselben wie beim seriellen Kollektor
Die Single-Core-Ausführungseffizienz ist nicht so gut wie bei Serial und bietet nur Vorteile, wenn sie auf mehreren Kernen ausgeführt wird.
Parallel Scavenge Collector (-XX:UseParallelGC, Kopieralgorithmus)
Verstehen Sie zunächst, dass Durchsatz = laufende Benutzercodezeit / (laufende Benutzercodezeit Garbage Collection-Zeit)
Anstatt auf die Pausenzeit des Benutzer-Threads zu achten, achten Sie mehr auf den Systemdurchsatz.
Es ist vorteilhaft, den Standardkollektor der jungen Generation im Servermodus unter Multi-Core auszuführen
Adaptive Anpassungsrichtlinie (-XX:UseAdaptiveSizePolicy)
Überlassen Sie die Aufgabe der Speicheroptimierung der virtuellen Maschine
Müllsammler der alten Generation
Serial Old Collector (-XX:UseSerialOldGC, Mark-Collation-Algorithmus)
Multithreading, Durchsatz zuerst
SMS-Sammler (-XX: UseConcMarkSweepGC, Mark-Sweep-Algorithmus)
Der Garbage-Collection-Thread kann fast gleichzeitig mit dem Worker-Thread arbeiten, also fast oder nicht vollständig, wodurch die Pausenzeit so weit wie möglich verkürzt wird
Initialisierungs-Tag: Stop-the-World
Erfordert eine kurze Pause
Parallelitätsmarkierung: Gleichzeitige Traceback-Markierung, das Programm wird nicht angehalten
Vorbereinigung der Parallelität: Finden Sie Objekte, die während der gleichzeitigen Markierungsphase von der jungen Generation zur alten Generation befördert wurden
Anmerkung: Halten Sie die virtuelle Maschine an und scannen Sie den CMS-Heap nach verbleibenden Objekten
Erfordert eine kurze Pause
Gleichzeitige Bereinigung: Der Garbage-Collection-Thread wird gleichzeitig mit dem Benutzer-Thread ausgeführt, um markierten Müll zu bereinigen.
Bereinigen Sie Müllobjekte und das Programm wird nicht angehalten.
Parallelität zurücksetzen: Setzen Sie die Datenstruktur des CMS-Kollektors zurück
Ausführungsprozess des CMS-Kollektors
dreifarbige Markierungsmethode
Wenn der aktuelle Knoten und alle seine untergeordneten Knoten die Markierung abgeschlossen haben, ist der aktuelle Knoten schwarz. Wenn der aktuelle Knoten die Markierung abgeschlossen hat und alle untergeordneten Knoten die Markierung nicht abgeschlossen haben, sind die nicht markierten Knoten des aktuellen Knotens weiß.
Es kann zu einer falschen Kennzeichnung oder Falschbeschriftung kommen.
cms verwendet den Inkrementellen Update-Algorithmus
G1 verwendet SATB (Snapshot-at-the-Begining), auch Snapshot genannt
G1-Kollektor (Garbage First) (-XX: UseG1GC, Kopiermarkierungs-Sortierungsalgorithmus)
Funktionen des Garbage First-Sammlers
Parallelität und Parallelität
Sammlung nach Generation
räumliche Integration
vorhersehbare Pausen
Teilen Sie den gesamten Java-Speicher in mehrere gleich große Bereiche auf
Die junge und die alte Generation sind nicht mehr räumlich getrennt
Steuern Sie die Pausenzeit sehr genau, um eine Garbage Collection mit geringer Pause zu erreichen, ohne den Durchsatz zu beeinträchtigen.
Um eine vollflächige Garbage Collection zu vermeiden, wird der Heap-Speicher in mehrere unabhängige Bereiche fester Größe unterteilt und der Fortschritt der Garbage Collection in diesen Bereichen verfolgt.
Basierend auf dem Mark-Compact-Algorithmus tritt keine Speicherfragmentierung auf.
#Ändern Sie den Standard-Garbage Collector export JAVA_OPTS='-XX: UseG1GC'
JDK11s neuer Garbage Collector Epsilon GC
JDK11s neuer Garbage Collector ZGC
Java Garbage Collector – FAQ
Ist die finalize()-Methode von Object dieselbe wie der Destruktor von C?
Im Gegensatz zum Destruktor von C, dessen Aufruf deterministisch ist, ist sein Aufruf undefiniert.
Platzieren Sie nicht referenzierte Objekte in der F-Queue-Warteschlange
Die Methodenausführung kann jederzeit beendet werden
Geben Sie eine exklusive letzte Chance zur Wiedergeburt
Welche Funktionen haben starke Referenzen, weiche Referenzen, schwache Referenzen und virtuelle Referenzen in Java?
Starke Referenz
Die häufigste Referenz: Object = new Object()
Wenn nicht genügend Speicherplatz vorhanden ist, wird ein OutOfMemoryError ausgelöst, um das Programm zu beenden, und Objekte mit starken Referenzen werden nicht recycelt.
Schwächen Sie die Referenz, indem Sie das Objekt auf Null setzen, damit es recycelt werden kann
Weiche Referenz
Das Objekt befindet sich in einem nützlichen, aber unnötigen Zustand
Nur wenn nicht genügend Speicherplatz vorhanden ist, fordert der GC den Speicher des referenzierten Objekts zurück.
Kann verwendet werden, um speichersensitives Tell-Caching zu implementieren
String str = new String("abc");//starke Referenz SfotReferenct<String> softRef = new SoftReference<String>(Str);//soft reference
Schwache Referenz
Unwesentliche Objekte, schwächer als weiche Referenzen
Wird während der GC recycelt
Die Wahrscheinlichkeit einer Wiederverwertung ist ebenfalls gering, da die GC-Thread-Priorität relativ niedrig ist.
Geeignet zum Verweisen auf Objekte, die gelegentlich verwendet werden und keinen Einfluss auf die Speicherbereinigung haben
String str = new String("abc");//starke Referenz WeakReferenct<String> schwachRef = new WeakReference<String>(Str);//Schwäche Referenz
PhantomReference
Bestimmt nicht den Lebenszyklus des Objekts
Kann jederzeit vom Müllsammler abgeholt werden
Verfolgen Sie die Aktivität von Objekten, die vom Müllsammler recycelt werden, und fungieren Sie als Wächter
Muss in Verbindung mit der Referenzwarteschlange ReferenceQueue verwendet werden
String str = new String("abc"); ReferenceQueue queue = new ReferenceQueue(); PhantomReference ref = new PhantomReference(str,queue);
Referenzwarteschlange
Es gibt keine tatsächliche Speicherstruktur, und die Speicherlogik basiert auf der Beziehung zwischen internen Knoten, um sie auszudrücken
Speichert zugehörige Soft-Referenzen, schwache Referenzen und virtuelle Referenzen, die GCed sind
JVM-Sperre
Klassifizierung von Schlössern
synchronisiert
Implementierungsklasse der Lock-Schnittstelle
Modul
JMM (Java-Speichermodus)
Acht Hauptoperationen der Gedächtnisinteraktion
Sperre: Wirkt auf Variablen im Hauptspeicher und markiert eine Variable als Thread-exklusiv.
entsperren: Eine Variable, die auf den Hauptspeicher wirkt. Sie gibt eine Variable frei, die sich in einem gesperrten Zustand befindet. Nur die freigegebene Variable kann von anderen Threads gesperrt werden.
lesen (lesen): Wirkt auf Hauptspeichervariablen. Es überträgt den Wert einer Variablen aus dem Hauptspeicher in den Arbeitsspeicher des Threads, um ihn in nachfolgenden Ladeaktionen zu verwenden.
Laden: Eine Variable, die auf den Arbeitsspeicher einwirkt. Sie überträgt den Lesevorgang von der Hauptspeichervariablen in den Arbeitsspeicher.
Verwendung (Verwendung): Wirkt auf Variablen im Arbeitsspeicher. Immer wenn die virtuelle Maschine auf einen Wert trifft, der verwendet werden muss, wird diese Anweisung verwendet.
zuweisen (Zuweisung): Wirkt auf eine Variable im Arbeitsspeicher und fügt einen von der Ausführungs-Engine empfangenen Wert in eine Kopie der Variablen im Arbeitsspeicher ein.
speichern (Speicher): Wirkt auf Variablen im Hauptspeicher. Es überträgt den Wert einer Variablen vom Arbeitsspeicher in den Hauptspeicher für die spätere Schreibverwendung.
Schreiben: Wirkt auf Variablen im Hauptspeicher. Der durch den Speichervorgang aus dem Arbeitsspeicher erhaltene Wert wird in die Variable im Hauptspeicher eingefügt.
Acht Regeln
1. Einer der Lese- und Lade-, Speicher- und Schreibvorgänge darf nicht alleine auftreten. Selbst wenn Sie „read“ verwenden, müssen Sie laden, und wenn Sie „store“ verwenden, müssen Sie schreiben.
2. Der Thread darf seine letzte Zuweisungsoperation nicht verwerfen, dh nachdem sich die Daten der Arbeitsvariablen geändert haben, muss der Hauptspeicher informiert (sichtbar) werden.
3. Einem Thread ist es nicht gestattet, nicht zugewiesene Daten vom Arbeitsspeicher zurück in den Hauptspeicher zu synchronisieren.
4. Im Hauptspeicher muss eine neue Variable erstellt werden, und der Arbeitsspeicher darf eine nicht initialisierte Variable nicht direkt verwenden. Das heißt, bevor eine Variable für Verwendungs- oder Speichervorgänge verwendet werden kann, muss sie Zuweisungs- und Ladevorgängen unterzogen werden.
5. Nur ein Thread kann gleichzeitig eine Variable sperren. Nach mehrmaligem Sperren müssen Sie zum Entsperren die gleiche Anzahl an Entsperrungen durchführen.
6. Wenn eine Sperroperation für eine Variable ausgeführt wird, wird der Wert dieser Variablen im gesamten Arbeitsspeicher gelöscht. Bevor die Ausführungs-Engine diese Variable verwendet, muss sie neu geladen oder zugewiesen werden, um den Wert der Variablen zu initialisieren.
7. Wenn eine Variable nicht gesperrt ist, kann sie nicht entsperrt werden. Sie können auch keine Variable entsperren, die von einem anderen Thread gesperrt ist.
8. Bevor eine Variable entsperrt wird, muss die Variable wieder mit dem Hauptspeicher synchronisiert werden.
Prinzipien des Linux-Kernels
Linux-Architektur
Kernel, Shell, Dateisystem und Anwendungen. Kernel, Shell und Dateisystem bilden zusammen die Grundstruktur des Betriebssystems
Linux-Dateisystem
Linux-Shell
Die Shell ist die Benutzeroberfläche des Systems und bietet Benutzern eine Schnittstelle zur Interaktion mit dem Kernel. Es empfängt vom Benutzer eingegebene Befehle und sendet sie zur Ausführung an den Kernel. Es handelt sich um einen Befehlsinterpreter. Darüber hinaus weist die Shell-Programmiersprache viele Merkmale gewöhnlicher Programmiersprachen auf. In dieser Programmiersprache geschriebene Shell-Programme haben die gleiche Wirkung wie andere Anwendungen.
1. Bourne Shell: Entwickelt von Bell Labs.
2. BASH: Es ist die Bourne Again Shell von GNU. Sie ist die Standard-Shell auf dem GNU-Betriebssystem. Die meisten Linux-Distributionspakete verwenden diese Shell.
3. Korn Shell: Es handelt sich um eine Weiterentwicklung von Bourne Shell und ist in den meisten Aspekten mit Bourne Shell kompatibel.
4. C Shell: Es handelt sich um die BSD-Version der SUN Company Shell.
Linux Kernel
Der Linux-Kernel ist eines der größten Open-Source-Projekte der Welt. Der Kernel ist die unterste Ebene leicht austauschbarer Software, die mit Computerhardware verbunden ist. Es ist für die Verbindung aller im „Benutzermodus“ laufenden Anwendungen mit der physischen Hardware verantwortlich und ermöglicht es Prozessen, die als Server bezeichnet werden, mithilfe der Interprozesskommunikation (IPC) Informationen voneinander zu erhalten. Der Kernel ist der Kern des Betriebssystems und verfügt über viele der grundlegendsten Funktionen. Er ist für die Verwaltung der Prozesse, des Speichers, der Gerätetreiber, Dateien und Netzwerksysteme verantwortlich und bestimmt die Leistung und Stabilität des Systems. Der Linux-Kernel besteht aus folgenden Teilen: Speicherverwaltung, Prozessverwaltung, Gerätetreiber, Dateisystem und Netzwerkverwaltung
Speicherverwaltung
Prozessmanagement
Dateisystem
Gerätetreiber
Netzwerkschnittstelle (NET)
Benutzermodus und Kernelmodus
Anwendungen können nicht direkt auf Hardwareressourcen zugreifen und müssen über die von der Kernel-SCI-Schicht bereitgestellte Schnittstelle auf Hardwareressourcen zugreifen.
Netzwerkprinzipien
Netzwerkprotokoll
HTTP
HTTP-Anfrage- und Antwortformat
Anfragetyp
ERHALTEN
So stellen Sie eine Get-Anfrage
Anfrage direkt über die Adressleiste des Browsers
Anfragen über Hyperlinks
Formular Formularmethode = „get“
Merkmale von Get-Anfragen
Die angeforderten Parameter werden direkt nach der URL gespleißt. Das Spleißformat ist url?key=value&key=value
Da die Anforderungsparameter nach der URL platziert werden, ist die von allen Anforderungen übertragene Datenmenge begrenzt und beträgt im Allgemeinen nicht mehr als 4 KB.
Da die Anforderungsparameter direkt nach der URL platziert werden, ist dies relativ unsicher.
VORNEHM
So stellen Sie eine noble Anfrage
Formular Formularmethode = „Post“
Merkmale schicker Anfragen
Die Anfrageparameter werden im Anfragetext platziert
Da die Anfrageparameter im Anfragetext platziert werden, ist die Menge der angeforderten Daten im Allgemeinen nicht begrenzt.
Da die Anforderungsparameter im Anforderungstext platziert werden: relativ sicher
Der Unterschied zwischen GET- und POST-Anfragen
HTTP-Nachrichtenebene
Die GET-Anfrage fügt die Anforderungsinformationen in die URL ein, und die POST-Anforderung fügt den Anforderungsinhalt in den Nachrichtentext ein.
Datenbankebene
GET-Anfragen sind idempotent und sicher, POST-Anfragen nicht.
andere Aspekte
GET kann zwischengespeichert und gespeichert werden, POST jedoch nicht
http-Anfrage
Anforderungszeile
Anforderungsheader
Erlauben
Welche Anfragemethoden unterstützt der Server?
Inhaltslänge
Die Länge des Anforderungstexts in Bytes
Inhaltstyp
Mime Typ
Inhaltskodierung
Legen Sie den von den Daten verwendeten Kodierungstyp fest
Läuft ab
Die Ablaufzeit des Antworttextes, eine GMT-Zeit, die die Gültigkeitszeit des Caches angibt
Anforderungstext
Die Zusammensetzung der http-Antwort
Antwortzeile, Anforderungszeile Statusinformationen zum Protokollstatuscode Antwort-Header, Anforderungs-Header Schlüsselwert Übergeben Sie serverseitige Informationen an den Client, z. B. Antwortformat und Codierung Antworttext, Anforderungstext Übertragen von Antwort-HTML-Daten
HTTP-Umleitung und -Weiterleitung
Weiterleitung (Seitensprung)
Was ist Umleitung?
Wenn der Browser zum ersten Mal den Webserver anfordert, gibt der Webserver einen 302-Statuscode und eine URL-Adresse an den Browser zurück. Wenn der Browser den 302-Statuscode und die folgende Adresse empfängt, sendet er sofort eine weitere Anfrage an den Server für die Adresse nach 302. Der Prozess des erneuten Antwortens. 302 Standorte
Response.sendRedirect("Adresse")
Merkmale
Es handelt sich im Wesentlichen um ein Verhalten des Browsers mit zwei Anfragen und zwei Antworten. Die Adresse in der Adressleiste ändert sich
Die Request- und Response-Objekte beider Requests sind neu.
Die Umleitungstechnologie kann nicht nur Anfragen innerhalb des Projekts lokalisieren, sondern auch Anfragen außerhalb des Projekts.
Vorwärts (Seitensprung)
Was ist Weiterleitung?
Wenn der Browser eine Anfrage an ein Servlet des Webservers stellt, übergibt das Servlet die noch nicht abgeschlossene Arbeit zur Verarbeitung an das nächste Servlet.
Transponder besorgen
RequestDispatcher DS=request.getRequestDispatcher("weitergeleitete Adresse")
Nach vorne
ds.forward(Anfrage,Antwort)
Merkmale
Es handelt sich im Wesentlichen um ein Verhalten auf dem Server mit einer Anfrage und einer Antwort. Die Adresse in der Adressleiste ändert sich nicht
Anforderungs- und Antwortobjekte teilen
Eine Weiterleitung ist nur projektintern möglich
HTTP-Caching und Proxyserver
Cookie-Mechanismus
Der Unterschied zwischen Cookie und Sitzung
Cookies sind spezielle Informationen, die vom Server an den Client gesendet und auf dem Client in Textform gespeichert werden. Wenn der Client erneut eine Anfrage stellt, wird das Cookie zurückgesendet. Nachdem der Server es empfangen hat, analysiert er das Cookie und generiert Inhalte, die dem Client entsprechen.
Sitzung ist ein serverseitiger Mechanismus, der Informationen auf dem Server speichert Analysieren Sie Clientanfragen und bedienen Sie Sitzungs-IDs, wobei Sie bei Bedarf Statusinformationen speichern
Die Sitzung existiert auf dem Server und Cookies werden auf dem Client gespeichert. Sitzung ist sicherer als Cookie Wenn Sie erwägen, den Serverdruck zu reduzieren, sollten Sie Cookies verwenden
Digitale Signatur und Zertifizierung
Unterschriften und Zertifikate
Bei HTTPS verwendet der Server den privaten Schlüssel zum Signieren und der Browser verwendet dann den öffentlichen Schlüssel des Zertifikats zur Überprüfung
Das Zertifikat muss zuerst von der Zertifizierungsstelle überprüft werden und dann muss der öffentliche Schlüssel verwendet werden, um den vom Client generierten symmetrischen Schlüssel zu schützen.
Digitales SSL-Zertifikat
3 weitere wichtige Attribute: Organisationsinformationen, öffentlicher Schlüssel und Gültigkeitszeit
Zeichnen Sie öffentliche Schlüssel und Organisationsinformationen im X.509-Format auf
OpenSSL
Robustes, kommerzielles und voll ausgestattetes Toolkit für die Protokolle Transport Layer Security (TLS) und Secure Sockets Layer (SSL).
Es handelt sich außerdem um eine allgemeine Passwortbibliothek für die Konvertierung von Zertifikatsformaten.
Authentifizierungsschritte
1) Serverzertifikatauthentifizierung (der Browser meldet den symmetrischen Schlüssel)
2) Verschlüsselte Kommunikation (kein Zertifikat erforderlich)
HTTPS und SSL/TLS
SSL/TLS
HTTPS verwendet die SSL/TLS-Technologie
Sein Kern ist die symmetrische Verschlüsselung und die asymmetrische Verschlüsselungstechnologie
TLS basiert auf der Protokollspezifikation SSL 3.0 und ist eine Folgeversion von SSL 3.0
SSL-Technologie
Eine Technologie zur Gewährleistung der Kommunikationssicherheit im C/S-Modus, die auf der Technologie digitaler Zertifikate basiert
Kann Manipulationssicherheit, verschlüsselte Kommunikation und komprimierte Kommunikation gewährleisten
Kommunikationsprozess
1) Der Client sendet eine Kommunikationsanfrage
SSL-Versionsnummer, Verschlüsselungsparameter, Sitzungs-ID
2) Der Server antwortet mit einer Antwort
SSL-Versionsnummer, Verschlüsselungsparameter, Sitzungs-ID und andere Informationen. Öffentliches Schlüsselzertifikat
3) Der Client verwendet den öffentlichen Schlüssel der Zertifizierungsstelle, um das Zertifikat des öffentlichen Schlüssels des Servers zu überprüfen. Wenn das Zertifikat des Servers ungültig ist, wird eine Ausnahme ausgelöst und die Fortsetzung der Sitzung verweigert.
4) Der Client sendet den symmetrischen Schlüsselsitzungsschlüssel der Sitzung an den Server
5) Beide Parteien verwenden den Sitzungsschlüssel für die verschlüsselte Kommunikation
Verschlüsselung
Symmetrische Verschlüsselung
Sowohl die Verschlüsselung als auch die Entschlüsselung verwenden denselben Schlüssel
asymmetrische Verschlüsselung
Der zur Verschlüsselung verwendete Schlüssel und der zur Entschlüsselung verwendete Schlüssel sind unterschiedlich
Hash-Algorithmus
Konvertieren Sie Daten beliebiger Länge in einen Wert fester Länge. Der Algorithmus ist irreversibel
Digitale Unterschrift
Beweisen Sie, dass eine Nachricht oder ein Dokument von einer bestimmten Person ausgestellt/bestätigt wurde
HTTPS-Datenübertragungsprozess
Der Browser sendet Informationen zu unterstützten Verschlüsselungsalgorithmen an den Server
Der Server wählt eine Reihe von Verschlüsselungsalgorithmen aus, die vom Browser unterstützt werden, und sendet sie in Form eines Zertifikats an den Browser zurück.
Der Browser überprüft die Gültigkeit des Zertifikats und sendet die verschlüsselten Informationen basierend auf dem öffentlichen Schlüssel des Zertifikats an den Server.
Der Server verwendet den privaten Schlüssel, um die Nachricht zu entschlüsseln, den Hash zu überprüfen und die Antwortnachricht zurück an den Browser zu verschlüsseln.
Der Browser entschlüsselt die Antwortnachricht, überprüft die Authentizität der Nachricht und verschlüsselt dann die Interaktionsdaten.
Der Unterschied zwischen HTTP und HTTPS
HTTPS muss ein Zertifikat von der Zertifizierungsstelle beantragen, HTTP nicht
HTTPS-Verschlüsselungstextübertragung, HTTP-Klartextübertragung
Die Verbindungsmethoden sind unterschiedlich. HTTPS verwendet standardmäßig Port 443 und HTTP verwendet standardmäßig Port 80.
HTTPS = HTTP-Verschlüsselung, Authentifizierung, Integritätsschutz, sicherer als HTTP
Ist HTTPS wirklich sicher?
Der Browser füllt standardmäßig http:// aus. Die Anfrage muss umgeleitet werden und es besteht die Gefahr einer Entführung.
HSTS-Optimierung (HTTP Strict Transport Security).
TCP
TCP-Protokoll und Flusskontrolle
Das TCP/IP-Modell umfasst Hunderte miteinander verbundener Protokolle wie TCP, IP, UDP, Telnet, FTP und SMTP.
Unter diesen sind TCP und IP die beiden am häufigsten verwendeten zugrunde liegenden Protokolle.
So stellen Sie die Zuverlässigkeit des TCP-Protokolls sicher
Der Unterschied zwischen TCP und UDP
Einführung in UDP
UDP-Nachrichtenstruktur
Quellport
Zielhafen
Länge
Prüfsumme
UDP-Funktionen
nicht verbindungsorientiert
Behält den Verbindungsstatus nicht bei und unterstützt das Senden derselben Informationen an mehrere Clients
Der Datenheader ist mit nur 8 Byte sehr kurz und der zusätzliche Overhead ist gering
Der Durchsatz wird durch die Datengenerierungsrate, Übertragungsrate und Maschinenleistung stark begrenzt
Best-Effort-Lieferung, aber keine Garantie für eine zuverlässige Lieferung, keine Notwendigkeit, komplexe Link-Statustabellen zu pflegen
Paketorientiert, es ist nicht erforderlich, die von der Anwendung übermittelten Pakete aufzuteilen oder zusammenzuführen
Unterschiede zwischen TCP und UDP
Verbindungs orientiert
TCP-verbindungsorientiert
UDP paketorientiert
Zuverlässigkeit
TCP stellt die Zuverlässigkeit sicher, indem es dreimal winkt
UDP garantiert keine Datenzuverlässigkeit
Ordentlichkeit
TCP verfügt über eine Sequenznummer, um die Ordnungsmäßigkeit der Datenübertragung sicherzustellen.
UDP übernimmt keine Garantie
Geschwindigkeit
TCP hat viel Arbeit geleistet, um die Zuverlässigkeit und Ordnung von Daten usw. sicherzustellen, daher ist es langsam.
UDP-Block
Größe
TCP ist ein Schwergewicht
UDP ist leichtgewichtig
TCP-Schiebefenster
RTT und RTO
RTT
Die Zeit, die benötigt wird, um ein Datenpaket zu senden, um eine Bestätigung von der anderen Partei zu erhalten
RTO
Neuübertragungsintervall
Beziehung zu TCP und HTTP
Das TCP/IP-Protokoll wird zum Transport von Stream-Format-Sockets verwendet. TCP wird verwendet, um die Richtigkeit der Daten sicherzustellen. IP wird verwendet, um zu steuern, wie die Daten das Ziel von der Quelle erreichen.
Das HTTP-Protokoll basiert auf verbindungsorientierten Sockets, da die Daten korrekt sein müssen
Das zugrunde liegende Implementierungsprinzip
Der Rückgabewert des Sockets unter UNIX/Linux ist der Dateideskriptor, und zum Übertragen von Daten können normale Dateioperationsfunktionen verwendet werden.
Windows behandelt den Socket als Netzwerkverbindung und muss die speziell für den Socket entwickelte Datenübertragungsfunktion aufrufen.
Typ
Internet-Steckdose
Stream-Sockets (Stream-Format-Sockets)
Bedeutung
Wird auch als „verbindungsorientierter Socket“ bezeichnet und basiert auf dem TCP-Protokoll
Ist ein zuverlässiger, bidirektionaler Kommunikationsdatenfluss, bei dem Daten fehlerfrei einen anderen Computer erreichen und bei Beschädigung oder Verlust erneut gesendet werden können.
Besonderheit
Die Daten verschwinden während der Übertragung nicht
Die Daten werden der Reihe nach übertragen
Das Senden und Empfangen von Daten erfolgt nicht synchron
Im Streaming-Format-Socket befindet sich ein Puffer (d. h. ein Zeichenarray), und die vom Socket übertragenen Daten werden im Puffer gespeichert.
Das empfangende Ende liest die Daten nicht unbedingt sofort nach dem Empfang. Das empfangende Ende liest möglicherweise alles auf einmal, nachdem der Puffer gefüllt ist.
Übertragung
TCP-Socket
Der Puffer existiert unabhängig und wird beim Erstellen des Sockets automatisch generiert.
Durch das Schließen des Sockets werden auch weiterhin im Ausgabepuffer verbleibende Daten übertragen
Durch das Schließen des Sockets gehen die Daten im Eingabepuffer verloren
Der Standardwert ist der Blockierungsmodus
Datagram-Sockets (Datagramm-Format-Sockets)
Bedeutung
Auch „verbindungsloser Socket“ genannt, basierend auf dem UDP-Protokoll
Übertragen Sie Daten einfach ohne Datenprüfung. Wenn die Daten während der Übertragung beschädigt werden oder nicht auf einen anderen Computer gelangen, gibt es keine Möglichkeit, dies zu beheben.
Besonderheit
Der Schwerpunkt liegt eher auf der schnellen Übertragung als auf der Reihenfolge der Übertragung
Übertragene Daten können verloren gehen oder beschädigt werden
Begrenzen Sie die Datengröße pro Übertragung
Daten werden synchron gesendet und empfangen
Übertragung
Verwenden Sie das IP-Protokoll für das Routing und das UDP-Protokoll (User Datagram Protocol) für die Datenübertragung
Anwendung: QQ-Voice-Video-Chat, Live-Übertragung
Vergleichen
Die verbindungslose Socket-Übertragung ist effizient, aber unzuverlässig und birgt das Risiko, dass Pakete verloren gehen und Daten beschädigt werden.
Angeschlossene Steckdosen sind sehr zuverlässig und narrensicher, allerdings ist die Übertragungseffizienz gering und verbraucht viele Ressourcen.
Unix-Socket (Pfadname des lokalen Knotens)
X.25-Socket (CCITT X.25-Adresse)
Datenübertragungsprozess
drei Händeschütteln
Wenn Sie connect() zum Herstellen einer Verbindung verwenden, senden Client und Server drei Pakete aneinander.
vier Händeschütteln
Zum Herstellen einer Verbindung ist ein Drei-Wege-Handshake erforderlich, zum Trennen ist ein Vier-Wege-Handshake erforderlich.
Defekter Link
Für ein ordnungsgemäßes Herunterfahren verwenden Sie bitte „shutdown()“
Mögliche Probleme
Daten-Sticky-Paket
High- und Low-Bits (Big Endian und Little Endian)
Big Endian: Das höherwertige Byte wird in der niederwertigen Adresse gespeichert (hochwertiges Byte zuerst).
Little Endian: Das höherwertige Byte wird in der höherwertigen Adresse gespeichert (niederwertiges Byte zuerst).
Betriebssystem
Einstufung
Laut Echtzeit
Time-Sharing-Betriebssystem
nicht in Echtzeit
Echtzeit-Betriebssystem
Weiche Echtzeit
Akzeptieren Sie gelegentliche Verstöße gegen die Zeitregeln
hart in Echtzeit
Die Verarbeitung muss innerhalb genau festgelegter Ereignisse abgeschlossen sein
andere
Netzwerkbetriebssystem
Verteiltes Betriebssystem
Betriebssystem eines Personalcomputers
Windows, MaxOS, Linux, UNIX
Kategorie
Mikrocontroller
Ein-Chip-Mikrocomputer, auch bekannt als Mikrocontroller-Einheit MCU
Ein Mikrocomputer mit einer Zentraleinheit, Speicher, Timern/Zählern, verschiedenen Ein- und Ausgabeschnittstellen usw., alles integriert auf einem integrierten Schaltkreischip
Eingebettetes System
Ein in ein mechanisches oder elektrisches System eingebettetes Computersystem mit speziellen Funktionen und Echtzeit-Rechenfunktionen
Das eingebettete System wird oft zur effizienten Steuerung vieler gängiger Geräte eingesetzt und ist in der Regel ein komplettes Gerät, das digitale Hardware und mechanische Komponenten enthält.
Eingebettetes Linux
Dies ist die allgemeine Bezeichnung für eine Art eingebettetes Betriebssystem. Diese Art von Betriebssystem basiert auf dem Linux-Kernel und ist für die Verwendung in eingebetteten Geräten konzipiert.
Es ist im Wesentlichen dasselbe wie das auf dem Computer ausgeführte Linux-System. Es nutzt hauptsächlich die Aufgabenplanung, Speicherverwaltung, Hardware-Abstraktion und andere Funktionen im Linux-Kernel.
RTOS (Echtzeitbetriebssystem)
Es wird auch als Echtzeitbetriebssystem bezeichnet, läuft nacheinander, verwaltet Systemressourcen und bietet eine konsistente Grundlage für die Entwicklung von Anwendungen
Programmierrahmen
Frühlings-Familieneimer
Frühlingsrahmen
Merkmale
Umkehrung der Kontrolle (IoC)
Abhängigkeitsinjektion (DI)
Lose Kopplung durch Abhängigkeitsinjektion und Schnittstellenorientierung
Aspektorientiert (AOP)
Deklarative Programmierung basierend auf Aspekten und Trägheit
Reduzieren Sie Boilerplate-Code mit Aspekten und Vorlagen
Anwendungsszenarien
Autoritätsauthentifizierung
Automatisches Caching
Fehlerbehandlung
debuggen
Protokoll
Angelegenheiten
Bohnenorientiert (BOP)
Leichte und minimal aufdringliche Programmierung basierend auf POJOs
Sping ist hinsichtlich Größe und Kosten leichtgewichtig. Das vollständige Sping-Framework kann in einer Datei mit einer Größe von nur mehr als 1 MB verwendet werden.
Der von Spring benötigte Verarbeitungsaufwand ist ebenfalls vernachlässigbar
Nicht aufdringlich: Normalerweise hängen Objekte in Spring-Anwendungen nicht von bestimmten Spring-Klassen ab.
Container
Ansicht auf hoher Ebene
Containerschnittstelle
BeanFactory
Es wird als HashMap verstanden, der Schlüssel ist BeanName und der Wert ist die Bean-Instanz.
Normalerweise stehen nur die beiden Funktionen Registrierung (Put) und Erwerb (Get) zur Verfügung
Unterstützt sowohl Singleton-Modelle als auch Prototyp-Modelle
Anwendungskontext
„Anwendungskontext“ repräsentiert alle Funktionen des gesamten großen Containers
Es wird eine Aktualisierungsmethode definiert, um den gesamten Container zu aktualisieren, d. h. alle Beans neu zu laden/aktualisieren
rahmen
Einfache Komponenten können konfiguriert und zu komplexen Anwendungen kombiniert werden
In Spring werden Anwendungsobjekte deklarativ zusammengestellt, typischerweise in einer XML-Datei
Bietet viele Grundfunktionen (Transaktionsverwaltung, Persistenz-Framework-Integration usw.) und überlässt die Entwicklung der Anwendungslogik den Entwicklern
Gemeinsame Module
Federkern
Bietet die Erstellung von IOC-Containerobjekten und die Verarbeitung abhängiger Objektbeziehungen
Kern
IOC
Allgemeine Anmerkungen
Anmerkungen auf Klassenebene
@Komponente
@Regler
@Service
@Repository
@Aufbau
@ComponentsScan
@Bohne
@Umfang
Anmerkungen auf Methodenvariablenebene
@Autowire
@Qualifier
@Ressource
@Wert
@Cacheable
@CacheEvict
Drei Injektionsmethoden
Konstruktorinjektion
Nutzen
Stellen Sie sicher, dass Abhängigkeiten unveränderlich sind (letztes Schlüsselwort)
Stellen Sie sicher, dass Abhängigkeiten nicht leer sind (was uns die Überprüfung erspart)
Stellen Sie sicher, dass der an den Client zurückgegebene (aufrufende) Code in einem vollständig initialisierten Zustand ist
Vermeiden Sie zirkuläre Abhängigkeiten
Verbesserte Wiederverwendbarkeit des Codes
Schnittstelleninjektion
Setter-Injektion
AOP
Umsetzungsprinzip
dynamischer Proxy
JDK-Implementierung
Es muss mindestens eine Schnittstelle implementiert werden
CGlib
ASM betreibt die Bytecode-Implementierung, um Unterklassen der Zielklasse zu generieren
statischer Proxy
Kompilierzeit Weben
Klasse laden Weben
Schlüsselwörter
Verbindungspunkt
Pointcut
Beratung
Vor der Beratung
Nach rückkehr beratung
Nach der Wurfberatung
Nach (endlich) Beratung
Rund um Beratung
Einführung
Zielobjekt
AOP-Proxy
Aspekt
Weberei
Methode zur Verwirklichung
Anmerkung
@AspectJ
@Pointcut
@Vor
@Nach
@Um
Konfigurationsdatei
Häufige Anwendungen
Angelegenheiten
Protokoll
Berechtigungen
Ressourcenabstraktion
Datenvalidierung und -transformation
Frühlingsausdruckssprache
Kernbehälter
BeanFactory
BeanFactory ist die Infrastruktur des Spring-Frameworks und steht Spring selbst gegenüber
ApplicationContext ist für Entwickler gedacht, die das Spring-Framework verwenden
Die BeanDefinitionRegistry-Schnittstelle bietet eine Methode zum manuellen Registrieren von BeanDefinition-Objekten beim Container.
Die Schnittstelle des Eltern-Kind-Kaskaden-IoC-Containers. Der untergeordnete Container kann über die Schnittstellenmethode auf den übergeordneten Container zugreifen.
AutowireCapableBeanFactory automatische Verkabelung
SingletonBeanRegistry registriert zur Laufzeit eine Singleton-Bean
Wie die IOC-Kontrollumkehr implementiert wird
XML-Konfigurationsmethode
Anmerkungsmethode
Automatische Montagemethode
Spring Web-Modul
Bietet Unterstützung für Struts, Springmvc und unterstützt die WEB-Entwicklung
SpringMVC
Annotationsimplementierung für Servlet 3.0
ServletContainerInitializer-Container-Initialisierung
ServletRegistration-Registrierung
FilterRegisteration-Filter
ServletContext
Leistung im tatsächlichen Kampf
Basierend auf asynchronem Servlet3.0
Callableasync
DeferredResultasync
Spring Web MVC
Allgemeine Anmerkungen
Anmerkungen auf Klassenebene
@EnableWebMvc
@SessionAttributes
Anmerkungen auf Methodenvariablenebene
@RequestBody
@ResponseBody
@RequestMapping
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
@ModelAttribute
@RequestParam
@RequestHeader
@RestController
@PathVariable
@ControllerAdvice
@CookieValue
@CrossOrigin
@Gültig
@Bestätigt
@ExceptionHandler
Kernkomponenten
DispatcherServlet
HandlerMapping
HandlerAdapter
ViewResolver
···
Frühlingswebfluss
Grundlagen des Reaktors
Lambda
Mono
Fluss
Kern
Web-MVC-Anmerkungen
Funktionsdeklaration
RouteFunction
Asynchron, nicht blockierend
Szenen, die verwendet werden sollen
Datenzugriff
Transaktionsverarbeitung
JDBC-Vorlage
prüfen
Gerätetest
Integrationstests
Frühlingsdaten
JPA
Redis
MongoDB
Couchbase
Kassandra
ElasticSearch
Neo4j
…
Frühlingssicherheit
OAuth2.0
CAS
WEB-Sicherheit
Autorisieren
Authentifizierung
Verschlüsselung
…
Frühlings-AOP
Spring bietet aspektorientierte Programmierung, die die Transaktionsverwaltung für eine bestimmte Schicht bereitstellen kann, beispielsweise das Hinzufügen einer Transaktionssteuerung zur Serviceschicht.
Frühlings-DAO
Stellt eine sinnvolle Ausnahmehierarchie für die JDBC-DAO-Abstraktionsschicht bereit
Frühlings-ORM
Eingebunden in mehrere ORM-Frameworks, einschließlich JDO, Hibernate und iBatis SQL Map
Frühlings-JEE
Unterstützung für J2EE-Entwicklungsspezifikationen, einschließlich Unternehmensdiensten wie JNDl, EJB, elektronischen Komponenten, Internationalisierung, Verifizierung und Planungsfunktionen
Frühlingskontext
Ist eine Konfigurationsdatei, die Kontextinformationen für das Spring-Framework bereitstellt
Frühlingssitzung
Frühlingsintegration
Spring REST-Dokumente
Frühling AMQP
FanoutExchange (veröffentlichen/abonnieren)
Art des Austauschs
Ausschwärmen
Broadcast, Übermittlung von Nachrichten an alle an die Börse gebundenen Warteschlangen
Direkte
Gezielt wird die Nachricht an die Warteschlange übermittelt, die dem angegebenen Routing-Schlüssel entspricht.
Thema
Platzhalter, übergeben Sie die Nachricht an die Warteschlange, die dem Routing-Muster (Routing-Muster) entspricht.
Überschriften
Verwenden Sie Header, um zu entscheiden, an welche Warteschlangen Nachrichten gesendet werden sollen (dies wird selten verwendet).
Datenzugriff
Transaktionen
DAO-Unterstützung
JDBC
ORM
Marshalling von XML
Hauptverpackung des Glases
Bohnen
Grundlegende Implementierung von Spring IOC, einschließlich Zugriff auf Konfigurationsdateien, Erstellen und Verwalten von Beans usw.
Kontext
Bietet erweiterte Dienste für grundlegende IOC-Funktionen und bietet zusätzlich Unterstützung für viele Dienste auf Unternehmensebene
Kern
Das Kernwerkzeugpaket von Spring. Andere Pakete hängen von diesem Paket ab
Ausdruck
Frühlingsausdruckssprache
Instrument
Springs Proxy-Schnittstelle zum Server
orm
Integrieren Sie ORM-Implementierungen von Drittanbietern wie Hibernate, Ibatis, JDO und die JPA-Implementierung von Spring
Frühlings-Websocket
Stellen Sie Socket-Kommunikation und Push-Funktion auf der Webseite bereit
Frühlingstest
Einfache Kapselung von Testframeworks wie JUNIT
Allgemeine Anmerkungen
Bean-Anmerkungen
@Component-Komponente, keine klare Rolle
@Service wird in der Geschäftslogikschicht (Serviceschicht) verwendet.
@Repository wird in der Datenzugriffsschicht (Dao-Schicht) verwendet.
@Controller wird in der Präsentationsschicht verwendet, Controller-Deklaration (C)
Java-Konfigurationsklasse
@Configuration deklariert die aktuelle Klasse als Konfigurationsklasse, was der Spring-Konfiguration in XML-Form (für die Klasse) entspricht.
Die @Bean-Annotation befindet sich auf der Methode und erklärt, dass der Rückgabewert der aktuellen Methode eine Bean ist, die die Methode in XML ersetzt (wird für die Methode verwendet).
@ComponentScan wird zum Scannen von Komponenten verwendet, was (in der Klasse) in XML entspricht
@WishlyConfiguration ist die kombinierte Annotation von @Configuration und @ComponentScan, die diese beiden Annotationen ersetzen kann.
Aspekt (AOP) bezogen
@Aspect deklariert einen Aspekt (auf der Klasse)
@After wird ausgeführt, nachdem die Methode ausgeführt wurde (auf der Methode)
@Before wird ausgeführt, bevor die Methode ausgeführt wird (auf der Methode)
@Around wird vor und nach der Ausführung der Methode ausgeführt (auf der Methode).
@PointCut deklariert Pointcuts
@Annotation aktivieren
@EnableAspectJAutoProxy
Aktivieren Sie die Spring-Unterstützung für AspectJ-Proxys (für Klassen).
@EnableAsync aktiviert die Unterstützung für asynchrone Methoden
@EnableScheduling aktiviert die Unterstützung für geplante Aufgaben
@EnableWebMvc aktiviert die Web-MVC-Konfigurationsunterstützung
@EnableConfigurationProperties ermöglicht die Unterstützung für @ConfigurationProperties-Annotationskonfigurations-Beans
@EnableJpaRepositories aktiviert die Unterstützung für das SpringData JPA Repository
@EnableTransactionManagement aktiviert die Unterstützung für annotierte Transaktionen
@EnableTransactionManagement aktiviert die Unterstützung für annotierte Transaktionen
@EnableCaching aktiviert die Unterstützung für das Annotations-Caching
Frühlingspanorama
SpringBoot
Enthält Module
Einzelanwendung
eingebetteter Container
Abhängigkeitsmanagement
Übereinstimmung ist größer als Konfiguration
Umweltmanagement
Protokollverwaltung
Konfigurationsmanagement
automatische Konfiguration
Management Funktionen
Haltepunkt
RBI
Monitor
Entwicklertools und CLI
Allgemeine Anmerkungen
Anmerkungen auf Klassenebene
@SpringBootApplication
@RestController
@EnableAutoConfiguration
@EntityScan
Anmerkungen auf Methodenvariablenebene
Drei Hauptmerkmale
Automatische Montage von Komponenten
webMVC
Unterstützte Template-Engines
FreeMarker
Groovig
Thymianblatt
Schnurrbart
JSP
webFlux
Unterstützte Template-Engines
FreeMarker
Thymianblatt
Schnurrbart
JDBC
···
Eingebetteter Webcontainer (keine Bereitstellung von War-Dateien erforderlich)
Kater
Anlegestelle
Sog
Produktionsbereitschaftsfunktionen
Stellen Sie solide Starter-Abhängigkeiten bereit, um die Build-Konfiguration zu vereinfachen
Bereitstellung betrieblicher Funktionen
Gesundheitsuntersuchung
Indikatorinformationen
Externalisierte Konfiguration
Keine Codegenerierung, keine XML-Konfiguration erforderlich
Automatische Montage
Implementierung
Aktivieren Sie Autowiring-@EnableAutoConfiguration/@SpringBootApplication
Implementieren Sie die automatische Assembly-XXXAutoConfiguration
Konfigurieren Sie die automatische Assembly-Implementierung-META-INFO/spring.factories
Erweiterungspunkt
SpringApplication
Automatische Konfiguration
Diagnoseanalysator
Eingebetteter Container
Fabriklademechanismus
Konfigurationsquellen (Eigenschaftsquellen)
Endpunkte
Überwachung und Management (JMX)
Ereignis/Listener
SpringCloud
Gemeinsame Komponenten
Spring Cloud GateWay
Service-Gateway
Spring-Cloud-Starter-Gateway
Route
Prädikat
Filter
Spring Cloud-Konfiguration
Dienst-Konfiguration
Konfigurationsserver
spring-cloud-config-server
@EnableConfigServer
Klient
spring-cloud-starter-config
Spring Cloud-Konsul
Dienstregistrierung/Dienstkonfiguration
Frühlingswolkenstrom
ereignisgesteuert
Quelle
Waschbecken
Prozessor
Bindemittel
Frühlings-Wolkenbinder-Kaninchen
Frühlings-Wolkenbinder-Kafka
Spring-Cloud-Binder-Kafka-Streams
(Funktionen und Dienste) Spring Cloud-Funktion
Funktion
Verbraucher
Anbieter
Anwendungen
spring-cloud-function-web
Spring-Cloud-Funktionsstream
Spring Cloud-Sicherheit
Servicesicherheit
Frühlingswolkendetektiv
Verfolgung und Visualisierung der Serviceanrufkette mit Zipkin
Klient
Spring-Cloud-Starter-Sleuth
Spring-Cloud-Starter-Zipkin
Zipkin-Server
io.zipkin.java.zipkin-server
@EnableZipkinServer
Spring Cloud OpenFeign
Für erholsame Anrufe zwischen Diensten (REST-Client)
spring-cloud-starter-openfegin
@EnableFeginClient
Frühlingswolke Netflix
Service-Governance
Eureka-Serviceerkennung
Kundendienst)
Spring-Cloud-Starter-Netflix-Eureka-Client
@EnableEurekaClient
EurekaServer
Spring-Cloud-Starter-Netflix-Eureka-Server
@EnableEurekasServer
Hystrix-Sicherung
Klient
Spring-Cloud-Starter-Netflix-Hystrix-Client
@EnableCircuitBreaker
Turbinen-Aggregationsdienst
Spring-Cloud-Starter-Netflix-Turbine
@EnableTurbine
DashBoard-Backend
Spring-Cloud-Starter-Netflix-Hystrix-Dashboard
@EnableHystrixDashboard
Zuul-Gateway-Dienst
Spring-Cloud-Starter-Netflix-Zuul
@EnableZuulProxy > @EnableZuulServer
SideCar-Service
Spring-Cloud-Starter-Netflix-Sidecar
@EnableSidecar
Load-Balancing des Ribbion-Clients
Spring-Cloud-Starter-Netflix-Ribbion
Laderegeln
Zufällige Regeln
Die meisten verfügbaren Regeln
Regeln für die Trainingsrotation
Wiederholen Sie die Implementierung
Client-Konfiguration
Verfügbarkeitsfilterregeln
RT-Gewichtsregeln
Umgehen Sie regionale Regeln
(Aufgaben-Framework) Spring Cloud-Aufgabe
Spring-Cloud-Starter-Aufgabe
@EnableTask
(Nachrichtenbus) Spring Cloud Bus
spring-cloud-starter-bus-amqp
Spring-Cloud-Starter-Bus-Kafka
Spring Cloud-Leistungsschalter
Service-Fehlertoleranz
(Administratorkonsole) Spring Cloud Admin
de.codecentric.spring-boot-admin-starter-server
@EnableAdminServer
Spring Cloud-Datenfluss
Armaturenbrett
Anwendung
Starter für die Spring Cloud Stream-App
Starter der Spring Cloud Task-App
Server
Bereitsteller
(Microservice-Vertrag) Spring Cloud-Vertrag
Spring-Cloud-Starter-Vertragsverifizierer
Spring-Cloud-Starter-Vertrag-Stub-Runner
ORM-Framework
JDBC
Datenbanktreibertyp
JDBC-ODBC-Brücke
Nativer API-Java-Treiber
JDBC-Netzwerk reiner Java-Treiber
Nativer, reiner Java-Protokolltreiber
MyBatis
Definition
Ausgezeichnetes Persistenzschicht-Framework, das benutzerdefiniertes SQL, gespeicherte Prozeduren und erweiterte Zuordnung unterstützt
Vermeidet fast den gesamten JDBC-Code und die manuelle Einstellung von Parametern und den Abruf von Ergebnismengen
Architekturdiagramm
verwenden
Zwei SQL-Konfigurationsmethoden
XML-Konfigurationsmethode
Anmerkungsanmerkungsmethode
Die Konfiguration konfiguriert jedes Element
Eigenschaften
Einstellung
TypAliase
Typhandler
Objektfabrik
Plugins
Umgebungen
Datenbankanbieter
Mapper
Seitennummerierung
pageHelper
Batch-Operationen
Union-Abfrage
Mögliche Fallstricke
Übereinstimmung von jdbcType und Datenbankfeldtyp
Ruhezustand(Nhibernate)
Kann in Java-Clientprogrammen verwendet werden
Kann in Servlet/JSP-Webanwendungen verwendet werden
Das Hibernate-Framework kann CMP in der Java EE-Architektur unter Verwendung von EJB ersetzen
SpringData
Spring Data JDBC
Spring Data JPA
SQL-Generierung
Spleißen Sie SQL nach Methodennamen
Anfragen
finden
lesen
erhalten
Abfrage
Strom
Erste
Spitze
zählen
existiert
Unterscheidbar
Sortieren nach
löschen
entfernen
löschen
andere
IsBetween/Between
IsNotNull/NotNull
IsNull/Null
IsLessThan/LessThan
IsLessThanEqual/LessThanEqual
IsGreaterThan/GreaterThan
IsGreaterThanEqual/GreaterThanEqual
IsBefore/Before
IsAfter/After
IsNotLike/NotLike
IsLike/Like
IsStartingWith/StartingWith/StartsWith
IsEndingWith/EndingWith/EndsWith
IsNotEmpty/NotEmpty
IsEmpty/Empty
IsNotContaining/NotContaining/NotContains
IsContaining/Containing/Contains
IsNotIn/NotIn
IsIn/In
IsNear/Near
IsWithin/Innerhalb
MatchesRegex/Matches/Regex
IsTrue/True
IsFalse/False
IstNicht/Nicht
Ist/Gleich
@Abfrage
JPQL
Natives SQL
Programmatisch
JPA verfügt über häufig verwendete APIs
JpaRepository<T, ID>
finde alle
findAllById
Rette alle
saveAndFlush
deleteInBatch
deleteAllInBatch
getOne
PagingAndSortingRepository<T, ID>
finde alle
CrudRepository<T, ID>
speichern
Rette alle
finde alle
findById
existiertById
zählen
deleteById
löschen
alles löschen
andere
spülen
Frühlingsdaten Mongodb
Spring Data Redis
Spring Data Elasticsearch
Spring Data Apache Solr
Spring Data Apache Hadoop
andere
EclipseLink
iBATIS
Der Vorgänger von MyBatis
JFinal
Morphium
JavaWeb-Entwicklungsframework
Web-Framework
Netty
Es handelt sich um ein NIO-Netzwerk-Framework für die effiziente Entwicklung von Netzwerkanwendungen.
Threading-Modell
Architekturdiagramm
Unterschiede zu Tomcat
Netty unterstützt nicht nur das HTTP-Protokoll, sondern auch mehrere Protokolle der Anwendungsschicht wie SSH, TLS/SSL usw.
Tomcat muss der Servlet-Spezifikation folgen. Vor Servlet 3.0 wurde das synchrone Blockierungsmodell verwendet.
Netty hat einen anderen Fokus als Tomcat. Es muss nicht durch die Servlet-Spezifikation eingeschränkt werden und maximiert die NIO-Funktionen.
Mina
Es handelt sich um das zugrunde liegende NIO-Framework des Apache-Verzeichnisservers (Netty ist eine aktualisierte Version von Mina).
Grizzly
MVC-Framework
Streben
Streben2
JSF (Java Server Faces)
WebWork
Xwork1
WebWork2
Rahmenkombination
SSM-Framework
SpringMVC Spring Mybatis
Webschicht (springmvc), Serviceschicht (spring) und DAO-Schicht (mybatis)
SSMM-Framework
Spring SpringMVC Mybatis MySQL
SSH-Framework
Strukturiert den Frühlingsschlaf
Datenbankverbindungspool
C3P0
DBCP
Druide
HikariCP
proxool
Tomcat JDBC-Pool
BoneCP
Tapisserie
Andere Frameworks
Caching-Framework
Ehcache
Bietet Speicher, Festplattendateispeicherung und verteilte Speichermethoden usw.
Schnell, einfach, geringer Verbrauch, geringe Abhängigkeit, starke Skalierbarkeit, unterstützt Objekt- oder Serialisierungscache, unterstützt Cache- oder Elementungültigmachung
Strukturdiagramm
Jeder CacheManager kann mehrere Caches verwalten, und jeder Cache kann mehrere Elemente auf Hash-Weise verwalten.
Element: Wird zum Speichern echter Cache-Inhalte verwendet
Caching-Strategie
TTL
LRU
redis
Koffein
Infinispan
Protokollverarbeitung
Log4j
sl4j
Persistenzschicht-Framework
Überwintern
Hibernate ermöglicht eine einfache Kapselung des Codes für den JDBC-Zugriff auf die Datenbank, wodurch der mühsame und sich wiederholende Code der Datenzugriffsschicht erheblich vereinfacht wird.
Mybatis
Sicherheitsrahmen
Frühlingssicherheit
Shiro
Computer-Framework
Sturm
Nimbus
Aufsicht
Arbeiter
Testamentsvollstrecker
Aufgabe
Topologie
Tülle
Bolzen
Tupel
Stream-Gruppierung
Mischen
Felder
Alle
Global
Keiner
Direkte
Lokal oder Shuffle
JStorm
Spark-Streaming
Flink
Blinken
Job-Framework (geplante Aufgaben)
Quarz
Allgemeine Anmerkungen
@DisallowConcurrentExecution
Komponenten
JobDetail
Auslösen
SimpleTrigger
CronTrigger
Kalender
Zeitplan
ElasticJob
Frühlingsaufgabe
Validierungsrahmen
Validator für den Ruhezustand
Oval
Verteilte Architektur
Zwischenspeicher
Cache-Ebene
Caching-Technologie
[Server] Verteilter Cache
【CDN】Dynamische Caching-Technologie
CSI (Client Side Includes)
Fügen Sie den Inhalt einer anderen Seite dynamisch über Iframe, Javascript, Ajax usw. ein.
Die Seite kann weiterhin in eine statische HTML-Seite umgewandelt werden, und wenn Dynamik erforderlich ist, kann sie dynamisch über Iframe, Javascript oder Ajax geladen werden.
Relativ einfach und erfordert keine Änderungen und Konfigurationen auf der Serverseite
Nicht förderlich für die Suchmaschinenoptimierung (Iframe-Methode), Javascript-Kompatibilitätsprobleme und clientseitige Caching-Probleme können zu vorzeitigen Updates führen
SSI (Serverseitige Einbindung)
Laden Sie verschiedene Module über SSI-Kommentarzeilenbefehle und bauen Sie sie in HTML ein, um den Inhalt der gesamten Website zu aktualisieren.
Die entsprechenden Dateien jedes Moduls werden über SSI aufgerufen und schließlich zu einer HTML-Seite zusammengesetzt, die Servermodulunterstützung erfordert.
Es ist nicht auf bestimmte Sprachen beschränkt und relativ universell. Es benötigt lediglich die Unterstützung eines Webservers oder Anwendungsservers wie Ngnix, Apache, IIS usw.
SSI kann nur auf dem aktuellen Server geladen werden und kann Dateien auf anderen Servern nicht direkt einbinden (d. h. es kann nicht domänenübergreifend eingebunden werden).
ESI (Edge Side Includes)
Verwenden Sie eine einfache Auszeichnungssprache, um Inhaltsfragmente in Webseiten zu beschreiben, die beschleunigt werden können und nicht
Kann zum Zwischenspeichern ganzer Seiten oder Seitenfragmente verwendet werden, meist ausgeführt auf Cache-Servern oder Proxy-Servern.
Derzeit gibt es relativ wenige Softwareprogramme, die ESI unterstützen, und offizielle Updates sind etwas langsam, sodass es nicht weit verbreitet ist.
Caching-Algorithmus (Seitenersetzungsalgorithmus)
FIFO (First in First out)
als Erster rein, als erster raus
LFU (Am wenigsten häufig verwendet)
Verwenden Sie ein Array zum Speichern von Datenelementen, verwenden Sie eine Hashmap, um die entsprechende Position jedes Datenelements im Array zu speichern, und entwerfen Sie dann eine Zugriffshäufigkeit für jedes Datenelement. Wenn das Datenelement getroffen wird, erhöht sich die Zugriffshäufigkeit automatisch Der Zugriff wird eliminiert, wenn Daten mit der geringsten Häufigkeit eliminiert werden
LRU
Cache-Elemente haben einen Zeitstempel. Wenn die Cache-Kapazität erschöpft ist und Platz zum Zwischenspeichern neuer Elemente geschaffen werden muss, werden die Elemente aus dem Cache gelöscht, deren Zeitstempel am weitesten von der aktuellen Zeit entfernt sind.
Szenen, die verwendet werden sollen
1) Halten Sie es mit der Datenstruktur in der Datenbank konsistent und speichern Sie es so, wie es ist.
2) Zwischenspeicherung von Listensortierungs- und Paging-Szenarien
3) Cache zählen
4) Rekonstruieren Sie den Dimensionscache
5) Größerer Cache für detaillierte Inhaltsdaten
Caching-Problem
Unter Cache-Penetration versteht man das Abfragen von Daten, die nicht in einer Datenbank vorhanden sein dürfen
Lösung
Erkennen Sie wichtige Spezifikationen und fangen Sie böswillige Angriffe ab
Wenn das aus der Datenbank abgefragte Objekt leer ist, wird es auch in den Cache gestellt. Legen Sie eine kürzere Cache-Ablaufzeit fest, z. B. 60 Sekunden.
Unter Cache-Lawine versteht man den zentralisierten Ablauf von Caches in einem bestimmten Zeitraum.
Unterschiedliche Warenkategorien haben unterschiedliche Cache-Zeiträume. Produkte derselben Kategorie plus Zufallsfaktor
Ein Cache-Ausfall bedeutet, dass ein Schlüssel sehr heiß ist und sich eine große Parallelität auf den Zugriff auf diesen Punkt konzentriert.
Wenn der Schlüssel abläuft, durchbricht die kontinuierliche große Parallelität den Cache und fordert direkt die Datenbank an.
Ermöglicht, dass der Cache niemals abläuft
Caching-Lösungen in Aktion
Caching-Konzept
SpringCache-Nutzung
Cache-Konsistenzstrategie
Cache-Lawinenszenario
Cache-Penetrationslösung
Drei große Widersprüche
Cache-Echtzeit- und Konsistenzprobleme
echtzeit-Strategie
Die Anwendung ruft die Daten zunächst aus dem Cache ab. Wenn sie diese nicht erhält, ruft sie die Daten aus der Datenbank ab.
Während des Schreibvorgangs werden die Daten in der Datenbank gespeichert. Nach Erfolg wird der Cache ungültig gemacht.
Problem mit der Cache-Penetration
Asynchrone Strategie
lesen
1) Wenn es beim Lesen nicht gelesen werden kann, greift es nicht direkt auf die Datenbank zu und gibt Fallback-Daten zurück.
2) Stellen Sie ein Datenladeereignis in die Nachrichtenwarteschlange, lesen Sie die Datenbank asynchron und aktualisieren Sie sie im Cache
erneuern
Aktualisieren Sie zuerst die Datenbank und dann den Cache asynchron
Aktualisieren Sie zuerst den Cache und dann die Datenbank asynchron
Hoher gleichzeitiger Zugriff auf die Datenbank zwischenspeichern
Timing-Strategie
Die Anwendung greift nur auf den Cache zu, nicht auf die Datenbank
Teilen Sie ein ganzes Datenelement zum Zwischenspeichern in mehrere Teile auf und unterscheiden Sie zwischen häufig aktualisierten und selten aktualisierten Teilen.
Verteilter Speicher
Traditioneller Netzwerkspeicher
NAS
Ein Netzwerkserver, der Speicherfunktionen und ein Dateisystem bereitstellt
Protokoll
KMU
NFS
AFS
SAN
Es wird nur Blockspeicher bereitgestellt und das Dateisystem wird vom Client verwaltet.
Protokoll
FibreChannel
iSCSI
ATA über Etherent (AoE)
HyperSCSI
Objektspeicher
Zugangsformular
Zugriff über REST-Webservice-Objekte
Wird über vordefinierte HTTP-Methoden verarbeitet
ERHALTEN
Holen Sie sich eine Netzwerkressource
SETZEN
Erstellen oder ersetzen Sie eine Netzwerkressource
POST
Wird zum Erstellen einer Ressource verwendet. Wenn sie bereits vorhanden ist, wird ein Fehler gemeldet.
LÖSCHEN
Löschen Sie eine Netzwerkressource
Metadatendienst
Objekt-Hashwert
Der Objektspeicher verwendet den Hashwert des Objekts als global eindeutige Kennung
Verwenden Sie eine Hash-Funktion mit hohen Ziffern, um Hash-Werte zu berechnen und sicherzustellen, dass Daten mit unterschiedlichem Inhalt unterschiedliche Hash-Werte haben.
Service-Architektur
ElasticSearch
http
Haltepunkt-Upload
Hochverfügbarer Datenspeicher
MySQL-Hochleistungsspeicherpraxis
Fortgeschrittene Mycat-Praxis
FastDFS-Praxis zur verteilten Dateispeicherung
Praxis der Dateispeicherung
Praxis der Dateisynchronisierung
Praxis der Dateiabfrage
Verteilte Bereitstellungspraxis
Verteilte Transaktionen
Isolationsstufe
Es wird die Standardisolationsstufe der Datenbank verwendet
MySQL verwendet standardmäßig wiederholbares Lesen
Oracle verwendet standardmäßig das Lesen von Commits (Read Committed).
SÄURE
Atomarität
Atomarität bedeutet, dass ein Ding eine unteilbare Arbeitseinheit ist und alle Vorgänge in dem Ding stattfinden oder nicht.
Konsistenz
Die Integrität der Daten vor und nach der Transaktion muss konsistent sein
Isolationsisolation
Wenn mehrere Benutzer auf die Datenbank zugreifen, können die von der Datenbank für jeden Benutzer geöffneten Transaktionen nicht durch Daten anderer Transaktionen beeinträchtigt werden, und mehrere gleichzeitige Transaktionen müssen voneinander isoliert werden.
Haltbarkeit
Sobald eine Sache übermittelt wird, sind die Änderungen an den Daten in der Datenbank dauerhaft, und selbst wenn die Datenbank ausfällt, hat dies keine Auswirkungen auf die Daten.
Eigenschaften der Transaktionsweitergabe
Garantiert in derselben Transaktion PROPAGATION_REQUIRED unterstützt die aktuelle Transaktion. Wenn sie nicht existiert, erstellen Sie eine neue (Standard). PROPAGATION_SUPPORTS unterstützt die aktuelle Transaktion. Wenn sie nicht vorhanden ist, wird die Transaktion nicht verwendet. PROPAGATION_MANDATORY unterstützt die aktuelle Transaktion. Wenn sie nicht vorhanden ist, wird eine Ausnahme ausgelöst. Garantiert nicht in derselben Transaktion PROPAGATION_REQUIRES_NEW Wenn eine Transaktion vorhanden ist, unterbrechen Sie die aktuelle Transaktion und erstellen Sie eine neue Transaktion PROPAGATION_NOT_SUPPORTED Im nicht-transaktionalen Modus ausführen. Wenn eine Transaktion vorhanden ist, unterbrechen Sie die aktuelle Transaktion PROPAGATION_NEVER wird im nicht-transaktionalen Modus ausgeführt und löst eine Ausnahme aus, wenn eine Transaktion vorhanden ist PROPAGATION_NESTED Wenn die aktuelle Transaktion existiert, wird die verschachtelte Transaktion ausgeführt
Verteiltes Transaktions-Framework
2Stk
3 STÜCK
JOTM
Atomikos
Verteilter Cluster
Master-Slave-Replikation
Lese- und Schreibtrennung
Lastverteilung
Verteilte Sperre
Merkmale verteilter Sperren
gegenseitige Ausschließlichkeit
Nur ein Thread hält gleichzeitig die Sperre
Wiedereintritt
Derselbe Thread auf demselben Knoten kann die Sperre erneut erwerben, nachdem er die Sperre erworben hat.
Sperrzeitüberschreitung
Wie die Sperre im JUC-Paket unterstützt sie eine Sperrzeitüberschreitung, um einen Deadlock zu verhindern.
Hohe Leistung und hohe Verfügbarkeit
Das Sperren und Entsperren muss effizient sein und gleichzeitig eine hohe Verfügbarkeit gewährleisten, um einen Ausfall verteilter Sperren zu verhindern.
Verfügt über blockierende und nicht blockierende Funktionen
Kann rechtzeitig aus dem blockierten Zustand aufwachen
Implementierung einer verteilten Sperre
Datenbankbasiert
Prüfen Sie selbst die Umsetzung
Basierend auf Redis
Basierend auf zooKeeper
Prüfen Sie selbst die Umsetzung
Redis-Implementierung
So implementieren Sie das Sperren
Verwendung des setnx-expire-Befehls (falscher Ansatz)
Weil die setnx-Expire-Operation nicht atomar ist
public boolean tryLock(String key,String requset,int timeout) { Langes Ergebnis = jedis.setnx(key, requset); // Wenn Ergebnis = 1, ist die Einstellung erfolgreich, andernfalls schlägt die Einstellung fehl if (result == 1L) { return jedis.expire(key, timeout) == 1L; } anders { falsch zurückgeben; } }
Verwenden Sie das Lua-Skript (einschließlich Setnx- und Expire-Anweisungen).
public boolean tryLock_with_lua(String key, String UniqueId, int seconds) { String lua_scripts = "if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then" "redis.call('expire',KEYS[1],ARGV[2]) return 1 else return 0 end"; List<String> keys = new ArrayList<>(); List<String>-Werte = new ArrayList<>(); schlüssel.add(schlüssel); Werte.add(UniqueId); Werte.add(String.valueOf(Sekunden)); Objektergebnis = jedis.eval(lua_scripts, Schlüssel, Werte); //Bestimmen Sie, ob es erfolgreich ist return result.equals(1L); }
Verwenden Sie den Befehl „set key value [EX seconds][PX milliseconds][NX|XX] (richtiger Ansatz).
Ab Version 2.6.12 fügt Redis dem SET-Befehl eine Reihe von Optionen hinzu: SET-Schlüsselwert[EX Sekunden][PX Millisekunden][NX|XX] EX Sekunden: Ablaufzeit in Sekunden festlegen PX-Millisekunden: Ablaufzeit in Millisekunden festlegen NX: Wert nur festlegen, wenn der Schlüssel nicht vorhanden ist XX: Wert nur festlegen, wenn Schlüssel vorhanden ist
public boolean tryLock_with_set(String key, String UniqueId, int seconds) { return „OK“.equals(jedis.set(key, UniqueId, „NX“, „EX“, seconds)); }
Der Wert muss eindeutig sein. Wir können dazu die UUID verwenden und eine zufällige Zeichenfolge festlegen, um die Einzigartigkeit sicherzustellen. Wenn der Wert keine zufällige Zeichenfolge, sondern ein fester Wert ist, können folgende Probleme auftreten: 1. Client 1 erhält die Sperre erfolgreich 2. Client 1 hat zu lange einen Vorgang blockiert 3. Der eingestellte Schlüssel läuft ab und die Sperre wird automatisch aufgehoben. 4. Client 2 erhält die Sperre, die derselben Ressource entspricht 5. Client 1 erholt sich von der Blockierung. Da der Wert derselbe ist, wird die von Client 2 gehaltene Sperre aufgehoben, wenn der Sperrfreigabevorgang ausgeführt wird, was zu Problemen führt.
Im Allgemeinen müssen wir beim Aufheben der Sperre den Wert überprüfen
Die Verwendung des Befehls „set key value [EX seconds][PX milliseconds][NX|XX] scheint in Ordnung zu sein, aber im Redis-Cluster-Modus können immer noch Probleme auftreten.
Client A erhält die Sperre für den Master. Zu diesem Zeitpunkt ist der Master-Knoten nicht synchronisiert Beim erneuten Erwerb der Sperre wird es mehrere geben. Der Client hat die Sperre erhalten.
Implementierungsmethode freischalten
Zum Entsperren müssen wir den Wert von value überprüfen. Wir können den Schlüssel nicht direkt verwenden, da jeder Client ihn entsperren kann. Beim Entsperren müssen wir also überprüfen, ob der Wert unser eigener ist, und ihn anhand des Werts beurteilen.
public boolean releaseLock_with_lua(String key,String value) { String luaScript = "if redis.call('get',KEYS[1]) == ARGV[1] then " "return redis.call('del',KEYS[1]) else return 0 end"; return jedis.eval(luaScript, Collections.singletonList(key), Collections.singletonList(value)).equals(1L); }
redssion
Redlock
Umsetzungsprinzip
Ermitteln Sie die aktuelle Unix-Zeit in Millisekunden.
Probieren Sie 5 Instanzen nacheinander mit demselben Schlüssel und aus
Ein eindeutiger Wert (z. B. UUID) erhält die Sperre. Wenn der Client eine Sperre von Redis anfordert, sollte er ein Netzwerkverbindungs- und Antwort-Timeout festlegen, das kürzer als die Ablaufzeit der Sperre sein sollte. Wenn die automatische Ablaufzeit Ihrer Sperre beispielsweise 10 Sekunden beträgt, sollte das Zeitlimit zwischen 5 und 50 Millisekunden liegen. Dadurch kann vermieden werden, dass sich das serverseitige Redis aufhängt und der Client immer noch auf das Antwortergebnis wartet. Wenn der Server nicht innerhalb der angegebenen Zeit antwortet, sollte der Client versuchen, so schnell wie möglich eine Sperre von einer anderen Redis-Instanz zu erhalten.
Der Client verwendet die aktuelle Zeit abzüglich der Zeit, zu der er mit dem Erwerb der Sperre begonnen hat (die in Schritt 1 aufgezeichnete Zeit), um die Zeit zu ermitteln, die zum Erwerb der Sperre verwendet wurde.
Die Sperre gilt genau dann als erfolgreich, wenn die Sperre von der Mehrheit (N/2 1, hier sind 3 Knoten) der Redis-Knoten erhalten wird und die Nutzungsdauer kürzer als die Ablaufzeit der Sperre ist.
Wenn das Schloss erworben wurde, ist die tatsächliche Gültigkeitszeit des Schlüssels gleich der Gültigkeitszeit minus der Zeit, die für den Erwerb des Schlosses aufgewendet wurde (das in Schritt 3 berechnete Ergebnis).
Wenn der Erwerb der Sperre aus irgendeinem Grund fehlschlägt (die Sperre wird nicht auf mindestens N/2 1 Redis-Instanzen erworben oder die Zeit für den Erwerb der Sperre hat die effektive Zeit überschritten), sollte der Client dies tun
Entsperren Sie alle Redis-Instanzen (auch wenn einige Redis-Instanzen überhaupt nicht erfolgreich gesperrt wurden, verhindert dies, dass einige Knoten die Sperre erhalten, der Client erhält jedoch keine Antwort und die Sperre kann für einen bestimmten Zeitraum nicht erneut erworben werden).
Verwendung
Pom vorstellen
<!-- https://mvnrepository.com/artifact/org.redisson/redisson --> <Abhängigkeit> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.3.2</version> </Abhängigkeit>
Holen Sie sich die Sperre
Der Code zum Erlangen der Sperre lautet redLock.tryLock() oder redLock.tryLock(500, 10000, TimeUnit.MILLISECONDS). Der endgültige Kernquellcode von beiden ist der folgende Code, aber die Standard-Lease-Zeit (leaseTime) des ersteren Der Erwerb der Sperre beträgt LOCK_EXPIRATION_INTERVAL_SECONDS, also 30 Sekunden:
Config config = new Config(); config.useSentinelServers().addSentinelAddress("127.0.0.1:6369", "127.0.0.1:6379", "127.0.0.1:6389") .setMasterName("masterName") .setPassword("password").setDatabase(0); RedissonClient redissonClient = Redisson.create(config); // Sie können auch getFairLock(), getReadWriteLock() RLock redLock = redissonClient.getLock("REDLOCK_KEY"); boolean isLock; versuchen { isLock = redLock.tryLock(); // Wenn die Sperre nicht innerhalb von 500 ms erhalten werden kann, wird davon ausgegangen, dass die Sperrenerfassung fehlgeschlagen ist. 10000 ms oder 10 s ist die Ablaufzeit der Sperre. isLock = redLock.tryLock(500, 10000, TimeUnit.MILLISECONDS); if (isLock) { //TODO, wenn die Sperre erfolgreich ist, etwas tun; } } Catch (Ausnahme e) { } Endlich { // Egal was passiert, am Ende muss es freigeschaltet werden redLock.unlock(); }
KEYS[1] ist Collections.singletonList(getName()), was den Schlüssel der verteilten Sperre darstellt, nämlich REDLOCK_KEY; ARGV[1] ist internalLockLeaseTime, die Lease-Zeit der Sperre. Der Standardwert beträgt 30 Sekunden. ARGV[2] ist getLockName(threadId), der einzige Wert, der beim Erwerb der Sperre festgelegt wird, also die UUID threadId:
Eindeutige ID
Ein sehr wichtiger Punkt bei der Implementierung verteilter Sperren ist, dass der Wert des Satzes eindeutig sein muss. Wie stellt der Wert von Redisson die Eindeutigkeit des Werts sicher? Die Antwort ist UUID threadId
protected final UUID id = UUID.randomUUID(); String getLockName(long threadId) { Rückgabe-ID: „threadId; }
Freischalten
Der Code zum Aufheben der Sperre lautet redLock.unlock()
Lastverteilung
Vierschichtiger Lastausgleich vs. siebenschichtiger Lastausgleich
Layer-4-Lastausgleich (Zieladresse und Port-Switching)
F5: Hardware-Load-Balancer, sehr funktionell, aber sehr teuer.
Ivs: Schwergewichtige vierschichtige Ladesoftware.
Nginx: Leichte vierschichtige Ladesoftware mit Caching-Funktion und flexiblen regulären Ausdrücken.
haproxy: simuliert Layer-4-Weiterleitung und ist flexibler.
Siebenschichtiger Lastausgleich (Content Switching)
haproxy: integrierte Lastausgleichstechnologie, unterstützt vollständig siebenschichtigen Proxy, Sitzungsschutz, Markierung und Routenübertragung:
nginx: Es verfügt nur über bessere Funktionen im HTTP-Protokoll und im Mail-Protokoll und seine Leistung ist ähnlich wie bei haproxy:
Apache: schlechte Funktionalität
MySQL-Proxy: Die Funktion ist akzeptabel.
Algorithmus/Strategie für den Lastausgleich
Round Robin
Gewichteter Round Robin
Zufälliges Gleichgewicht (zufällig)
Gewichteter Zufallssaldo
Reaktionsgeschwindigkeitsbalance (Reaktionszeit-Erkennungszeit)
Geringstes Verbindungsgleichgewicht
Rechenleistungsbilanz (CPU, Speicher)
DNS-Antwortausgleich (Flash DNS)
Hash-Algorithmus
IP-Adress-Hashing (um eine stabile Client-Server-Korrespondenz sicherzustellen)
URL-Hash
ICH GEGEN
LVS-Prinzip
LVS-NAT-Modus
①. Der Client sendet die Anforderung an den Front-End-Load-Balancer. Die Quelladresse der Anforderungsnachricht ist CIP (Client-IP), im Folgenden zusammenfassend als CIP bezeichnet, und die Zieladresse ist VIP (Load-Balancer-Front-End-Adresse). , im Folgenden zusammenfassend als VIP bezeichnet).
② Nachdem der Load Balancer die Nachricht empfangen und festgestellt hat, dass die Anforderung für eine in der Regel vorhandene Adresse gilt, ändert er die Zieladresse der Client-Anforderungsnachricht in die RIP-Adresse des Back-End-Servers und sendet die Nachricht entsprechend der Algorithmus.
⑧ Nachdem die Nachricht an den realen Server gesendet wurde, antwortet dieser auf die Anfrage und sendet die Antwortnachricht an LVS zurück, da die Zieladresse der Nachricht selbst ist.
④. Dann ändert lvs die Quelladresse dieser Nachricht auf den lokalen Computer und sendet sie an den Client.
Merkmale
1. Die NAT-Technologie erfordert, dass die Anforderungsnachricht und die Antwortnachricht über LB neu geschrieben werden. Daher gibt es bei relativ großen Website-Besuchen einen relativ großen Engpass im LB-Lastausgleichsplaner, der im Allgemeinen maximal 10 bis 20 Einheiten beträgt sind erforderlich
2. Sie müssen nur eine 1P-Adresse des öffentlichen Netzwerks auf dem LB konfigurieren.
3. Die Gateway-Adresse jedes internen Realserver-Servers muss die Intranet-Adresse des Scheduler-LB sein.
4. Der NAT-Modus unterstützt die Übersetzung von IP-Adressen und Ports. Das heißt, der vom Benutzer angeforderte Port und der Port des realen Servers stimmen möglicherweise nicht überein.
Vorteil
Die physischen Server im Cluster können jedes Betriebssystem verwenden, das TCP/IP unterstützt, nur der Load Balancer benötigt eine gültige IP-Adresse
Mangel
Die Skalierbarkeit ist begrenzt. Wenn Serverknoten (normale PC-Server) zu stark wachsen, wird der Load Balancer zum Flaschenhals des gesamten Systems, da alle Anforderungspakete und Antwortpakete durch den Load Balancer fließen.
Wenn zu viele Serverknoten vorhanden sind, laufen viele Datenpakete auf dem Load Balancer zusammen und die Geschwindigkeit nimmt ab!
LVS DR-Modus (LAN schreibt MAC-Adresse neu)
①. Der Client sendet die Anfrage an den Front-End-Load-Balancer. Die Quelladresse der Anfragenachricht ist CIP und die Zieladresse ist VIP.
② Nachdem der Load Balancer die Nachricht empfängt und feststellt, dass die Anforderung für eine Adresse gilt, die in der Regel vorhanden ist, ändert er die Quell-MAC-Adresse der Client-Anforderungsnachricht in seine eigene DIP-MAC-Adresse und ändert die Ziel-MAC in die RIP Geben Sie die MAC-Adresse ein und senden Sie dieses Paket an RS.
③. Wenn RS feststellt, dass der Ziel-MAC in der Anforderungsnachricht er selbst ist, empfängt er die Nachricht. Nach der Verarbeitung der Anforderungsnachricht sendet er die Antwortnachricht über die lo-Schnittstelle an die ETHO-Netzwerkkarte und sendet sie direkt an den Client .
Merkmale
1. Die Weiterleitung wird durch Ändern der Ziel-MAC-Adresse des Datenpakets im Scheduler LB implementiert. Beachten Sie, dass die Quelladresse immer noch die CIP und die Zieladresse immer noch die VIP-Adresse ist.
2. Die angeforderte Nachricht durchläuft den Scheduler, während die als RS-Antwort verarbeitete Nachricht nicht den Scheduler-LB durchlaufen muss, sodass die Nutzungseffizienz sehr hoch ist, wenn die Menge des gleichzeitigen Zugriffs groß ist (im Vergleich zum NAT-Modus).
3. Da der DR-Modus die Weiterleitung über den Mechanismus zum Umschreiben der MAC-Adresse implementiert, können sich alle RS-Knoten und der Scheduler-LB nur in einem LAN befinden.
4. Der RS-Host muss die VIP-Adresse an die LO-Schnittstelle binden (32-Bit-Maske) und die ARP-Unterdrückung konfigurieren.
5. Das Standard-Gateway des RS-Knotens muss nicht als LB konfiguriert werden, sondern direkt als Gateway der Route der oberen Ebene konfiguriert werden, wodurch der RS direkt aus dem Netzwerk herausgehen kann.
Vorteil
Wie TUN (Tunnelmodus) verteilt der Load Balancer nur Anfragen und Antwortpakete werden über eine separate Routing-Methode an den Client zurückgesendet. Im Vergleich zu VS-TUN erfordert VS-DR keine Tunnelstruktur, sodass die meisten Betriebssysteme als physische Server verwendet werden können.
Der DR-Modus ist sehr effizient, die Konfiguration ist jedoch etwas komplizierter, sodass Unternehmen, die keine besonders großen Besuche haben, stattdessen Haproxy/Nginx verwenden können. Wenn Sie 1000–2000 W PV pro Tag oder weniger als 10.000 gleichzeitige Anfragen haben, können Sie die Verwendung von haproxy/nginx in Betracht ziehen.
Mangel
Alle RS-Knoten und Scheduler-LB können sich nur in einem LAN befinden
LVS-TUN-Modus (P-Kapselung, netzwerkübergreifendes Segment)
① Der Client sendet die Anfrage an den Front-End-Load-Balancer. Die Quelladresse der Anfragenachricht ist CIP und die Zieladresse ist VIP.
② Nachdem der Load Balancer die Nachricht empfängt und feststellt, dass die Anforderung für eine in der Regel vorhandene Adresse gilt, kapselt er eine IP-Nachricht in den Header der Client-Anforderungsnachricht und ändert die Quelladresse in DIP und die Zieladresse. Wechseln Sie zu RIP und senden Sie dieses Paket an RS.
③ Nach Erhalt der Anforderungsnachricht entpackt RS zunächst die erste Kapselungsschicht und stellt dann fest, dass die Zieladresse des IP-Headers der VIP auf seiner eigenen lo-Schnittstelle ist, sodass die Anforderungsnachricht verarbeitet und die Antwort gemeldet wird. Die Datei wird über die lo-Schnittstelle an die ethO-Netzwerkkarte gesendet und direkt an den Client gesendet.
Merkmale
1. Der TUNNEL-Modus muss VIP-IP-Adressen auf allen Realserver-Maschinen binden
2. TUNNEL-Modus vip ------> Die Paketkommunikation des Realservers erfolgt über den TUNNEL-Modus und kann kommunizieren, unabhängig davon, ob es sich um ein internes oder ein externes Netzwerk handelt. Daher ist es nicht erforderlich, dass /vs vip und realserver vorhanden sind demselben Netzwerksegment.
3. Im TUNNEL-Modus sendet Realserver das Paket direkt an den Client und nicht an Ivs.
4. Der TUNNEL-Modus verwendet den Tunnelmodus und ist daher schwierig zu bedienen und zu warten. Daher wird er im Allgemeinen nicht verwendet.
Vorteil
Der Load Balancer ist nur für die Verteilung von Anforderungspaketen an Backend-Knotenserver verantwortlich, während RS Antwortpakete direkt an Benutzer sendet.
Durch die Reduzierung des großen Datenflusses im Load Balancer stellt der Load Balancer nicht mehr den Engpass des Systems dar und kann eine große Menge an Anfragen verarbeiten. Auf diese Weise kann ein Load Balancer auf viele RSs verteilt werden. Und es kann durch die Ausführung im öffentlichen Internet in verschiedenen Regionen verbreitet werden.
Mangel
Der RS-Knoten im Tunnelmodus erfordert eine legale IP. Diese Methode erfordert, dass alle Server das „IP-Tunneling“-Protokoll (IPEncapsulation) unterstützen. Der Server ist möglicherweise auf einige Linux-Systeme beschränkt.
LVS FULLNAT-Modus
1. Wenn das Paket von LVS an RS übertragen wird, wird die Quelladresse vom Client 1P durch die interne IP von LVS ersetzt. Intranet-IPs können über mehrere Switches über VLANs hinweg kommunizieren. Die Zieladresse wird von VIP auf RS IP geändert.
2. Wenn RS das empfangene Paket verarbeitet und nach der Verarbeitung zurückkehrt, ändert es die Zieladresse in LVS-IP, die ursprüngliche Adresse in RSIP und sendet das Paket schließlich an die Intranet-IP von LVS zurück.
3. Nachdem LVS das Paket empfangen hat, ändert es auf der Grundlage der Änderung der Quelladresse im NAT-Modus die Zieladresse in dem von RS gesendeten Paket von der LVS-Intranet-IP zum 1P des Clients und ändert die ursprüngliche Adresse in VIP.
Zusammenfassen
1. Für den FULL NAT-Modus müssen sich LBIP und Realserver-IP nicht im selben Netzwerksegment befinden.
2. Da die Quell-IP aktualisiert werden muss, ist die Leistung im vollständigen NAT-Modus normalerweise 10 % geringer als im NAT-Modus.
Bleib am Leben
Keepalive wurde ursprünglich für LVS entwickelt und wurde speziell zur Überwachung des Status jedes Dienstknotens von LVS verwendet. Später wurde die Funktion von vrrp hinzugefügt, sodass es zusätzlich zu LVS auch als Hochverfügbarkeitssoftware für andere Dienste verwendet werden kann ( Nginx, Haproxy)
VRRP ist die Abkürzung für Virtual Router Redundancy Protocol. Das Aufkommen von VRRP besteht darin, den Single Point of Failure beim statischen Routing zu beheben. Es kann den unterbrechungsfreien und stabilen Betrieb des Netzwerks gewährleisten.
Nginx-Reverse-Proxy-Lastausgleich
upstream_module und Gesundheitserkennung
pproxy_pass-Anfrageweiterleitung
HAProxy
Verteilte Koordination und Entladung
Zookeeper-Kommandant für verteilte Umgebungen
Erste Schritte mit zk
Grundlagen der ZK-Entwicklung
Zookeeper-Anwendungspraxis
Protokoll- und Algorithmusanalyse
Nginx-Offloading mit hoher Parallelität für Fortgeschrittene
Nginx-Installation
Forward- und Reverse-Proxy
Nginx-Prozessmodell
Kernkonfigurationsstruktur
Protokollkonfiguration und Signatur
Standortregeln
Verwendung von Rewrite
Trennung von Bewegung und Stille
Domänenübergreifende Konfiguration
Cache-Konfiguration, Gzip-Konfiguration
https-Konfiguration
Probleme durch horizontale Ausdehnung
ICH GEGEN
keepalived
verteilte Konsistenz
Raft-Algorithmus
Merkmale
Schreiben Sie basierend auf dem Quorum in die Datenbank
Die Hälfte der Schreibvorgänge aus der Datenbank sind erfolgreich, was bedeutet, dass der Vorgang erfolgreich ist.
Die Master-Bibliothek schreibt das Protokoll und überträgt es an die Slave-Bibliothek
Drei Arten von Protokollen: BinLog, RedoLog, UndoLog
Wahl basierend auf Protokollvergleich
Bestimmen Sie, wessen Protokoll das aktuellste ist (basierend auf dem Protokollindex in der Abstimmungsanforderung anderer Knoten und Ihrem eigenen Protokollindex).
Rollenklassifizierung
Führer
Kandidat (Leiterkandidat)
Anhänger
Nachrichtentyp
Anfrage abstimmen
Fordern Sie andere Knoten auf, für sich selbst zu stimmen (im Allgemeinen vom Kandidaten ausgestellt)
AppendEntries
Wird für die Protokollreplikation verwendet und gibt die dem Protokoll hinzugefügten Einträge an. Wird für den Heartbeat verwendet, wenn die Anzahl der Einträge 0 beträgt
Gesendet vom Anführer
Praktische Umsetzung gängiger verteilter Lösungen
Transaktionskonzept
Transaktionen und Sperren
Hintergrund verteilter Transaktionen
X/OpenDTP-Transaktionsmodell
Standardmäßige verteilte Transaktionen
Verteilte Transaktionslösungen
Zweiphasen-Commit
BASE-Theorie und flexible Angelegenheiten
TCC-Schema
Ausgleichsplan
Asynchronität garantiert und Best Effort
Single-Sign-On-Lösung
Problemhintergrund von Single Sign-On
Probleme mit domänenübergreifenden Seiten
Lösung zur domänenübergreifenden Sitzungsfreigabe
Sitzungsverlängerung
Lösung für die verteilte Aufgabenplanung
So verwenden Sie die Quarzplanung
Elastic-Job-Beispiel
Schwierigkeiten bei der verteilten Planung
Angepasste verteilte Planung für Quarzcluster
Verteiltes Framework und Middleware
Verteilte Anrufe
RPC (Fernanruf)
Erholsam
Middleware
Caching/Persistenz
Verteilter Cache
Redis (Remote-Wörterbuchserver)
Objektbeziehungen
Strukturdiagramm
Gedächtnisklassifizierung
Objektgedächtnis
Pufferspeicher
Client-Pufferung
AOF-Puffer
Backlog-Puffer kopieren
Wird hauptsächlich zur Master-Slave-Synchronisation verwendet.
eigene Erinnerung
Speicherverbrauch des untergeordneten Redis-Erstellungsprozesses bei Verwendung von AOF/RDB
Speicherfragmentierung
Optionale Allokatoren sind jemalloc, glibc, tcmalloc, der Standardwert ist jemalloc
Lösung mit hoher Speicherfragmentierung: Datenausrichtung, sicherer Neustart (hohe Verfügbarkeit/Master-Slave-Umschaltung)
Strategie zur Speicherrückgewinnung
Faules Löschen
Abgelaufene Schlüssel-Wert-Paare werden nicht aktiv gelöscht, sondern es wird darauf gewartet, dass der Client den Schlüssel liest. Wenn eine Zeitüberschreitung vorliegt, wird das Schlüssel-Wert-Paar-Objekt gelöscht und dann leer zurückgegeben.
Geplante Aufgaben löschen
Pipeline
Redis verwendet ein Client-Server-Modell (CS) und einen TCP-Server mit Anforderungs-/Antwortprotokoll. Das bedeutet, dass eine Anfrage normalerweise die folgenden Schritte durchläuft:
Der Client sendet eine Abfrageanforderung an den Server und wartet auf die Socket-Rückgabe, normalerweise im Blockierungsmodus, und wartet auf die Antwort des Servers.
Der Server verarbeitet den Befehl und gibt die Ergebnisse an den Client zurück.
Das TCP-Protokoll wird verwendet, um den Redis-Client und den Redis-Server zu verbinden. Ein Client kann mehrere Anforderungsbefehle über eine Socket-Verbindung initiieren. Nachdem jeder Anforderungsbefehl ausgegeben wurde, blockiert der Client normalerweise und wartet darauf, dass der Redis-Server den Anforderungsbefehl verarbeitet. Daher wird das Ergebnis über eine Antwortnachricht an den Client zurückgegeben Warten Sie, bis der vorherige Befehl ausgeführt wird
Pipeline kann mehrere Befehle gleichzeitig senden und die Ergebnisse nach der Ausführung sofort zurückgeben. Pipeline reduziert die Umlaufverzögerungszeit, indem sie die Anzahl der Kommunikationen zwischen Client und Redis reduziert. Das Prinzip der Pipeline-Implementierung ist die Warteschlange Die Reihenfolge der Daten wird nach dem First-In-First-Out-Prinzip sichergestellt. Die Standardanzahl der Synchronisierungen in Pipeline beträgt 53, was bedeutet, dass die Daten übermittelt werden, wenn 53 Daten in arges akkumuliert sind. Der Vorgang ist in der folgenden Abbildung dargestellt: Der Client kann drei Befehle in einer TCP-Nachricht zusammenfassen und zusammen senden, und der Server kann die Verarbeitungsergebnisse der drei Befehle in einer TCP-Nachricht zusammenfassen und zurückgeben.
Es ist zu beachten, dass Befehle im Pipeline-Modus gepackt und gesendet werden und Redis die Verarbeitungsergebnisse aller Befehle vor der Verarbeitung zwischenspeichern muss. Je mehr Befehle Sie packen, desto mehr Speicher verbraucht der Cache. Es ist also nicht so, dass es umso besser ist, je mehr Befehle Sie packen. Das konkrete Maß an Angemessenheit muss je nach Situation geprüft werden.
Da es bei der Kommunikation zu Netzwerkverzögerungen kommt, beträgt die Paketübertragungszeit zwischen Client und Server 0,125 Sekunden. Dann dauert die Ausführung der oben genannten drei Befehle und sechs Nachrichten mindestens 0,75 Sekunden. Selbst wenn Redis 100 Befehle pro Sekunde verarbeiten kann, kann unser Client auf diese Weise nur vier Befehle pro Sekunde ausgeben. Dadurch wird die Rechenleistung von Redis offensichtlich nicht vollständig ausgenutzt.
Anwendbare Szene
Bei einigen Systemen müssen möglicherweise sehr hohe Anforderungen an die Zuverlässigkeit gestellt werden. In diesem Fall ist dieses Szenario nicht geeignet.
In anderen Systemen können Daten stapelweise auf Redis geschrieben werden, wodurch ein gewisser Anteil an Schreibfehlern möglich ist. Wenn beispielsweise 10.000 Einträge auf einmal in Redis eingegeben werden, spielt es möglicherweise keine Rolle, ob zwei Einträge fehlschlagen. In Zukunft wird es einen Kompensationsmechanismus geben. Wenn beispielsweise im Massen-SMS-Szenario 10.000 Nachrichten gleichzeitig gesendet und gemäß dem ersten Modus implementiert werden, dauert die Antwort lange Wenn die Anfrage beim Client eingeht, wird eine Ausnahme ausgelöst, wenn die Zeitüberschreitung 5 Sekunden beträgt und die Echtzeitanforderungen für Gruppentextnachrichten nicht so hoch sind Zu diesem Zeitpunkt ist es am besten, eine Pipeline zu verwenden.
Pipelining vs. Scripting
Große Pipeline-Anwendungsszenarien können effizienter durch Redis-Skripte (Redis-Version >= 2.6) gehandhabt werden, die einen Großteil der Arbeit auf der Serverseite erledigen. Einer der großen Vorteile von Skripten besteht darin, dass sie Daten mit minimaler Latenz lesen und schreiben können, wodurch Vorgänge wie Lesen, Berechnen und Schreiben sehr schnell erfolgen (Pipeline kann in diesem Fall nicht verwendet werden, da der Client die vom Client zurückgegebenen Ergebnisse lesen muss). Befehl, bevor Sie ihn schreiben).
„Anwendungen senden manchmal EVAL- oder EVALSHA-Befehle in der Pipeline. Redis unterstützt diesen Fall explizit durch den Befehl SCRIPT LOAD (der garantiert, dass EVALSHA erfolgreich aufgerufen wird).
Redis-Clusterlösung
twemproxy
Redis-Cluster (Redis-Cluster)
Redis-Cluster verwendet eine zentrumslose Struktur. Jeder Knoten speichert Daten und den gesamten Clusterstatus, und jeder Knoten ist mit allen anderen Knoten verbunden.
Strukturelle Eigenschaften
Alle Redis-Knoten sind miteinander verbunden (PING-PONG-Mechanismus) und intern wird ein Binärprotokoll verwendet, um Übertragungsgeschwindigkeit und Bandbreite zu optimieren.
Der Ausfall eines Knotens wird erst dann wirksam, wenn mehr als die Hälfte der Knoten im Cluster Ausfälle erkennen.
Der Client ist direkt mit dem Redis-Knoten verbunden, ohne dass eine Zwischen-Proxy-Schicht erforderlich ist. Der Client muss sich nicht mit allen Knoten im Cluster verbinden, sondern nur mit jedem verfügbaren Knoten im Cluster.
redis-cluster ordnet alle physischen Knoten dem Steckplatz [0-16383] zu (nicht unbedingt gleichmäßig verteilt), und der Cluster ist für die Aufrechterhaltung des Knotenwerts <->Steckplatz<-> verantwortlich. (Hash-Ring) 2 hoch 14
Der Redis-Cluster ist vorab in 16384 Buckets unterteilt. Wenn ein Schlüsselwert im Redis-Cluster platziert werden muss, wird der Bucket, in dem ein Schlüssel platziert wird, basierend auf dem Wert von CRC16 (Schlüssel) Mod 16384 bestimmt.
Redis-Cluster-Knotenzuordnung
Jetzt haben wir drei Hauptknoten: A, B und C. Dabei kann es sich um drei Ports auf einer Maschine oder um drei verschiedene Server handeln. Wenn dann 16384 Slots mithilfe von Hash-Slots zugewiesen werden, betragen die von den drei Knoten angenommenen Slot-Intervalle
Knoten A deckt 0-5460 ab;
Knoten B deckt 5461-10922 ab;
Knoten C deckt 10923-16383 ab.
Daten abrufen
Wenn ein Wert gespeichert ist, befolgen Sie den Algorithmus des Redis-Cluster-Hash-Slots: CRC16('key')384 = 6782. Dann wird der Speicher dieses Schlüssels B zugewiesen. Wenn ich eine Verbindung zu einem beliebigen Knoten (A, B, C) herstelle und den Schlüssel „Schlüssel“ erhalten möchte, verwende ich ebenfalls diesen Algorithmus und springe dann intern zu Knoten B, um die Daten abzurufen.
Neuen Masterknoten hinzufügen
Fügen Sie einen neuen Knoten D hinzu. Die Methode des Redis-Clusters besteht darin, einen Teil des Steckplatzes von der Vorderseite jedes Knotens zu nehmen und ihn auf D zu platzieren.
Knoten A deckt 1365-5460 ab
Knoten B deckt 6827-10922 ab
Knoten C deckt 12288-16383 ab
Knoten D umfasst 0-1364, 5461-6826, 10923-12287
Masterknoten löschen
Das Löschen eines Knotens erfolgt auf ähnliche Weise. Sie können den Knoten löschen, nachdem die Verschiebung abgeschlossen ist.
Redis-Cluster-Master-Slave-Modus
Um die hohe Verfügbarkeit von Daten sicherzustellen, hat der Redis-Cluster den Master-Slave-Modus hinzugefügt. Ein Master-Knoten entspricht einem oder mehreren Slave-Knoten. Wenn der Master-Knoten hängt. Nach einem Ausfall wird einer der Slave-Knoten als Master-Knoten ausgewählt, um sicherzustellen, dass der Cluster nicht hängen bleibt.
Die Master-Slave-Struktur von Redis kann einen Master, mehrere Slaves oder eine Kaskadenstruktur verwenden.
Aufbau eines Redis-Clusters
Es sollte mindestens eine ungerade Anzahl von Knoten im Cluster geben, also mindestens drei Knoten, jeweils mit mindestens einem Backup-Knoten
Die Master-Slave-Struktur von Redis kann einen Master, mehrere Slaves oder eine Kaskadenstruktur verwenden.
Master-Slave-Synchronisation
Daten können vom Master-Server mit jedem Slave-Server synchronisiert werden, und der Slave-Server kann ein Master-Server sein, der mit anderen Servern verbunden ist. Da der Publish/Subscribe-Mechanismus vollständig implementiert ist, kann die Slave-Datenbank, wenn sie den Baum irgendwo synchronisiert, einen Kanal abonnieren und den vollständigen Nachrichtenveröffentlichungsdatensatz des Master-Servers empfangen. Die Synchronisierung ist hilfreich für die Skalierbarkeit und Datenredundanz von Lesevorgängen.
Arbeitsprinzip
Vollständige Synchronisierung
Die vollständige Redis-Synchronisierung erfolgt im Allgemeinen während der Slave-Initialisierungsphase. Zu diesem Zeitpunkt müssen alle Daten auf dem Master kopiert werden.
1. Der Slave-Server stellt eine Verbindung zum Master-Server her und sendet den SYNC-Befehl.
2. Nachdem der Hauptserver die SYNC-Benennung erhalten hat, beginnt er mit der Ausführung des BGSAVE-Befehls, um eine RDB-Datei zu generieren, und verwendet den Puffer, um alle danach ausgeführten Schreibbefehle aufzuzeichnen;
3. Nachdem der Master-Server BGSAVE ausgeführt hat, sendet er Snapshot-Dateien an alle Slave-Server und zeichnet während des Sendezeitraums weiterhin die ausgeführten Schreibbefehle auf;
4. Nachdem Sie die Snapshot-Datei vom Server erhalten haben, verwerfen Sie alle alten Daten und laden Sie den empfangenen Snapshot.
5. Nachdem der Master-Server-Snapshot gesendet wurde, beginnt er mit dem Senden des Schreibbefehls im Puffer an den Slave-Server.
6. Der Slave-Server schließt das Laden des Snapshots ab, beginnt mit dem Empfang von Befehlsanfragen und führt Schreibbefehle aus dem Master-Server-Puffer aus.
Nach Abschluss der oben genannten Schritte sind alle Vorgänge der Dateninitialisierung vom Slave-Server abgeschlossen. Der Slave-Server kann nun Leseanfragen von Benutzern empfangen.
Inkrementelle Synchronisierung
Die inkrementelle Redis-Synchronisierung bezieht sich auf den Prozess der Synchronisierung der auf dem Master-Server durchgeführten Schreibvorgänge mit dem Slave-Server, wenn der Redis-Slave initialisiert wird und normal funktioniert.
Inkrementelle Replikation bedeutet im Wesentlichen, dass der Master-Server jedes Mal, wenn er einen Schreibbefehl empfängt, denselben Schreibbefehl an den Slave-Server sendet und der Slave-Server denselben Schreibbefehl empfängt und ausführt.
Redis Master-Slave-Synchronisationsstrategie
Wenn die Master-Slave-Verbindung beginnt, wird eine vollständige Synchronisierung durchgeführt, und nach Abschluss der Synchronisierung wird eine inkrementelle Synchronisierung durchgeführt.
Bei Bedarf kann der Slave jederzeit eine vollständige Synchronisierung einleiten
Die Redis-Strategie besteht darin, zuerst eine inkrementelle Synchronisierung durchzuführen und dann eine vollständige Synchronisierung durchzuführen, wenn die Synchronisierung fehlschlägt.
Hinweis: Wenn mehrere Slaves getrennt werden, müssen sie neu gestartet werden. Beim Neustart wird automatisch eine Synchronisierung gesendet, um den Master-Server zur vollständigen Synchronisierung anzufordern. Wenn mehrere Slaves gleichzeitig angezeigt werden, führt dies zu einem starken Anstieg der Master-E/A Ausfallzeit.
Hohe Verfügbarkeit unter der Redis Sentinel-Architektur
Wenn der Master auflegt, ist es notwendig, den Slave-Knoten manuell zum Master-Knoten hochzustufen und gleichzeitig die Geschäftspartei zu benachrichtigen, die Master-Knotenadresse zu ändern. Diese Art der Fehlerbehandlungsmethode ist für bestimmte Anwendungsszenarien nicht akzeptabel. Redis bietet in Version 2.8 eine Sentinel-Architektur, um dieses Problem zu lösen
Umsetzungsprinzip
Drei geplante Überwachungsaufgaben
Alle 10 Sekunden sendet jeder Sentinel-Knoten den Info-Befehl an den Master-Knoten und den Slave-Knoten, um die neueste Topologiestruktur zu erhalten
Alle 2 Sekunden sendet jeder Sentinel-Knoten die Beurteilung des aktuellen Sentinel-Knotens über den Master-Knoten und die Informationen des aktuellen Sentinel-Knotens an den _sentinel_:hello-Kanal des Redis-Datenknotens. Gleichzeitig abonniert jeder Sentinel-Knoten diesen Kanal, um mehr über andere Sentinel-Knoten und deren Beurteilung des Master-Knotens zu erfahren
Sentinel sendet alle 1 Sekunde einen Ping-Befehl an den Master-Knoten und den Slave-Knoten, um eine Heartbeat-Überprüfung durchzuführen, um zu bestätigen, ob diese Knoten derzeit erreichbar sind.
Subjektiv offline
Denn jede Sekunde sendet jeder Sentinel-Knoten einen Ping-Befehl an den Master-Knoten, den Slave-Knoten und andere Sentinel-Knoten zur Heartbeat-Erkennung. Wenn diese Knoten länger als nach Millisekunden nicht effektiv reagieren, wird der Sentinel-Knoten dies tun Der Knoten führt eine Fehlerbestimmung durch. Dieses Verhalten wird als subjektives Offlineverhalten bezeichnet.
Ziel offline
Wenn der Knoten, den Sentinel subjektiv offline geht, der Master-Knoten ist, fragt der Sentinel-Knoten andere Sentinel-Knoten nach ihrer Beurteilung des Master-Knotens. Wenn die Anzahl <Quorum> überschreitet, bedeutet dies, dass sich die meisten Sentinel-Knoten nicht sicher sind Der Master-Knoten trifft eine einstimmige Entscheidung, sodass der Sentinel-Knoten davon ausgeht, dass tatsächlich ein Problem mit dem Master-Knoten vorliegt. Zu diesem Zeitpunkt wird der Sentinel-Knoten eine objektive Entscheidung treffen, offline zu gehen.
Wahl des Leader-Sentinel-Knotens
Der Raft-Algorithmus geht davon aus, dass s1 (Sentinel-1) das Ziel als erster offline abschließt. Er sendet einen Befehl an die anderen Sentinel-Knoten und fordert dazu auf, der Anführer zu werden Auf Anfrage anderer Sentinel-Knoten stimmt er der Anfrage von s1 zu. Wenn s1 feststellt, dass seine Stimmenzahl größer oder gleich einem bestimmten Wert ist, wird er zum Anführer.
Failover
1. Der führende Sentinel-Knoten wählt einen Knoten aus den Slave-Knoten als neuen Master-Knoten aus
2. Die obige Auswahlmethode ist der Slave-Knoten mit der höchsten Replikationsähnlichkeit zum Master-Knoten.
3. Der führende Sentinel-Knoten ermöglicht es anderen Slave-Knoten, Slave-Knoten des neuen Master-Knotens zu werden.
4. Die Sentinel-Sammlung verwandelt den ursprünglichen Master-Knoten in einen Slave-Knoten, behält ihn im Auge und weist ihn an, den neuen Master-Knoten zu kopieren, wenn er wiederhergestellt ist.
Hohe Verfügbarkeit unter Redis Cluster (Cluster)
Umsetzungsprinzip
Subjektiv offline
Jeder Knoten im Cluster sendet regelmäßig Ping-Nachrichten an andere Knoten, und die empfangenden Knoten antworten mit Ping-Nachrichten. Wenn die Kommunikation innerhalb der Cluster-Node-Timeout-Zeit weiterhin fehlschlägt, betrachtet der sendende Knoten den empfangenden Knoten als fehlerhaft und markiert den empfangenden Knoten als subjektiv offline (pfail).
Ziel offline
Wenn ein Knoten feststellt, dass ein anderer Knoten subjektiv offline ist, folgt der entsprechende Knotenstatus der Nachricht und verbreitet sich innerhalb des Clusters.
Angenommen, Knoten a markiert Knoten b als subjektiv offline. Nach einer gewissen Zeit sendet Knoten a den Status von Knoten b über Nachrichten an andere Knoten und analysiert den PFail-Status von b im Nachrichtentext. Knoten b wird hinzugefügt.
Wenn ein bestimmter Knoten c den pfail-Status von Knoten b erhält und mehr als die Hälfte der Slot-Master-Knoten Knoten b als pfail-Status markiert haben, wird der fehlerhafte Knoten b als objektiv offline markiert;
Senden Sie eine pfail-Nachricht an den Cluster, die alle Knoten im Cluster benachrichtigt, den fehlerhaften Knoten b als objektiv offline zu markieren und sofort wirksam wird. Außerdem wird der Slave-Knoten über den fehlerhaften Knoten b benachrichtigt, um den Failover-Prozess auszulösen.
Erholung
Prüfung der Berechtigung
Wenn der Slave-Knoten länger als eine bestimmte Zeit vom Master-Knoten getrennt ist, ist er nicht berechtigt.
Vorbereitung auf die Wahlzeit
Wenn der Slave-Knoten für ein Failover geeignet ist, wartet er eine gewisse Zeit, bevor er mit der Auswahl beginnt.
Unter allen Slave-Knoten des fehlerhaften Knotens startet der Slave-Knoten mit dem größten Replikationsoffset zuerst die Wahl (am besten mit den Daten des Master-Knotens übereinstimmend), und dann startet der zweitgrößte Knoten die Wahl ... und der Rest Slave Knoten warten, bis ihre Wahlzeit erreicht ist, bevor sie Wahlen durchführen.
Eine Wahl einleiten
Nur der Master-Knoten, der den Slot hält, verfügt über eine eindeutige Stimme. Wenn N/2 1 Master-Knoten, der die Slot-Stimmen hält, vom Slave-Knoten gesammelt werden, kann der Slave-Knoten den Vorgang des Ersetzens des Master-Knotens durchführen.
Wahlabstimmung
Ersetzen Sie den Masterknoten
Wenn genügend Stimmen vom Slave-Knoten gesammelt wurden, wird der Austausch des Master-Knotenvorgangs ausgelöst.
Der aktuelle Slave-Knoten bricht die Replikation ab und wird zum Master-Knoten
Entziehen Sie die Slots, die für den ausgefallenen Master verantwortlich sind, und delegieren Sie diese Slots an sich selbst
Senden Sie eine eigene Pong-Nachricht an den Cluster, um alle Knoten im Cluster darüber zu informieren, dass der aktuelle Slave-Knoten zum Master-Knoten geworden ist und die Slot-Informationen des ausgefallenen Master-Knotens übernommen hat.
asynchrone Warteschlange
Liste als Warteschlange verwenden
RPUSH fungiert als Produzent zum Erzeugen von Nachrichten und LPOP fungiert als Konsument zum Konsumieren von Nachrichten.
Nachteile: Es gibt keine Warteschlange und Sie können es direkt nutzen, wenn es einen Wert gibt. Make-up: Sie können LOOP über den Schlafmechanismus auf der Anwendungsebene aufrufen, um es erneut zu versuchen. Wenn Sie den Sleep-Mechanismus nicht verwenden, können Sie BLPOP key[key..] timeout zum Blockieren verwenden, bis sich eine Nachricht in der Warteschlange befindet oder eine Zeitüberschreitung auftritt.
Ein Produzent entspricht einem Konsumenten
Wie man einmal produziert und es mehreren Verbrauchern zur Verfügung stellt
pub/sub: Themenabonnementmodus
Der Absender (pub) sendet die Nachricht und der Abonnent (sub) empfängt die Nachricht.
Abonnenten können beliebig viele Kanäle abonnieren
Nachteile: Nachrichten sind zustandslos und es kann nicht garantiert werden, dass sie erreichbar sind.
So implementieren Sie eine Verzögerungswarteschlange
Verwenden Sie Sortiersatz
Nehmen Sie den Zeitstempel als Ergebnis
Der Nachrichteninhalt wird als Schlüssel zum Aufrufen von zadd verwendet, um die Nachricht zu erstellen.
Der Verbraucher verwendet die Anweisung zrangeBysocre, um vor N Sekunden abgefragte Daten zur Verarbeitung abzurufen.
Redis-Persistenz
Persistenzmodus RDB (Redis-Datenbank)
Prinzip
RDB-Persistenz bezieht sich auf das Schreiben eines Snapshots des Datensatzes im Speicher innerhalb eines bestimmten Zeitintervalls auf die Festplatte. Der eigentliche Vorgang besteht darin, einen untergeordneten Prozess zu verzweigen, zuerst den Datensatz in eine temporäre Datei zu schreiben und dann die vorherige Datei zu ersetzen Das Schreiben ist erfolgreich und wird mit binärer Komprimierung gespeichert.
Vorteil
1. Sobald Sie diesen Ansatz übernehmen, enthält Ihre gesamte Redis-Bibliothek nur noch eine Datei, was sich perfekt für die Dateisicherung eignet. Sie planen beispielsweise, stündlich Daten von 24 Stunden und täglich Daten von 30 Tagen zu synchronisieren. Mit dieser Konfiguration können wir im Falle eines katastrophalen Ausfalls problemlos Daten wiederherstellen.
2. Für die Notfallwiederherstellung ist RDB eine sehr gute Wahl, da wir problemlos eine separate Datei komprimieren und diese dann auf andere Speichermedien kopieren können.
3. Maximieren Sie die Leistung des Redis-Dienstprozesses. Wenn Sie die Persistenz starten, müssen Sie nur einen untergeordneten Prozess auslagern und den Rest dem untergeordneten Prozess überlassen, um den Persistenzvorgang abzuschließen, wodurch die Leistung des Dienstprozesses erheblich verringert wird IO-Operationen.
4. Im Vergleich zum AOF-Mechanismus ist die RDB-Starteffizienz höher, wenn der Datensatz groß ist
Mangel
1. Wenn Sie eine hohe Datenverfügbarkeit sicherstellen möchten, also Datenverluste weitestgehend vermeiden möchten, ist RDB nicht die beste Wahl, denn wenn das System vor einer bestimmten Persistenzzeit ausfällt, werden die nicht gespeicherten Daten gelöscht Die Festplatte geht verloren.
2. Da der untergeordnete Fork-Prozess zur Unterstützung von Festplattenpersistenzvorgängen verwendet wird, kann es bei relativ großen Datensätzen dazu führen, dass der Server die Bereitstellung für Hunderte von Millisekunden oder sogar 1 Sekunde einstellt.
Aufbau
Redis speichert den Snapshot des Datensatzes in der Datei dump.rdb. Darüber hinaus können wir die Häufigkeit von Redis-Server-Dump-Snapshots über die Konfigurationsdatei ändern. Nachdem wir die Datei 6379.conf geöffnet haben, suchen wir nach „save“ und können die folgenden Konfigurationsinformationen sehen:
save 900 1 #Wenn sich nach 900 Sekunden (15 Minuten) mindestens eine Taste ändert, wird der Speicherauszug gelöscht.
save 300 10 #Wenn sich nach 300 Sekunden (5 Minuten) mindestens 10 Schlüssel geändert haben, sichern Sie den Speicher-Snapshot.
save 60 10000 #Wenn sich nach 60 Sekunden (1 Minute) mindestens 10000 Schlüssel geändert haben, sichern Sie den Speicher-Snapshot.
Während der Ausführung des Befehls „bgsave“ blockiert nur der untergeordnete Prozess „fork“ den Server. Der gesamte Prozess blockiert daher den Server. Daher wurde „save“ grundsätzlich abgebrochen und die Verwendung von „save“ muss im Online-Modus eliminiert werden Umfeld;
Persistenzmethode AOF (nur Datei anhängen)
Prinzip
Die AOF-Persistenz zeichnet alle vom Server verarbeiteten Schreib- und Löschvorgänge in Form eines Protokolls auf. Abfragevorgänge werden nicht aufgezeichnet, sondern in Textform. Sie können die Datei öffnen, um detaillierte Vorgangsaufzeichnungen anzuzeigen.
Vorteil
Dieser Mechanismus kann eine höhere Sicherheit, also Datenpersistenz, bringen
Es stehen drei Synchronisationsstrategien zur Verfügung
Jede Sekunde synchronisieren
Die Synchronisierung pro Sekunde ist ebenfalls ein asynchroner Vorgang, der sehr effizient ist. Bei einem Dienstausfall gehen nur die Daten der vorherigen Sekunde verloren.
Synchronisieren Sie jede Änderung
Es kann als synchrone Persistenz und geringe Effizienz verstanden werden.
Nicht mehr synchronisiert
Da dieser Mechanismus den Anhängemodus zum Schreiben von Protokolldateien verwendet, wird der vorhandene Inhalt in der Protokolldatei auch bei einer Ausfallzeit während des Schreibvorgangs nicht zerstört. Wenn wir bei diesem Vorgang jedoch nur die Hälfte der Daten schreiben und ein Systemabsturz auftritt, können wir vor dem nächsten Start von Redis das Tool redis-check-aof verwenden, um das Datenkonsistenzproblem zu lösen.
Wenn das Protokoll zu groß ist, kann Redis den Umschreibemechanismus automatisch aktivieren. Das heißt, Redis schreibt im Anhängemodus kontinuierlich geänderte Daten in die alte Festplattendatei. Gleichzeitig erstellt Redis auch eine neue Datei, um aufzuzeichnen, welche Änderungsbefehle in diesem Zeitraum ausgeführt wurden. Daher kann die Datensicherheit beim Umschreiben besser gewährleistet werden.
AOF enthält eine übersichtlich formatierte, leicht verständliche Protokolldatei zur Aufzeichnung aller Änderungsvorgänge. Tatsächlich können wir die Datenrekonstruktion auch über diese Datei durchführen.
Mangel
Bei gleicher Anzahl an Datensätzen sind AOF-Dateien in der Regel größer als RDB-Dateien. RDB ist beim Wiederherstellen großer Datensätze schneller als AOF.
Abhängig von der Synchronisationsstrategie ist AOF hinsichtlich der Betriebseffizienz häufig langsamer als RDB. Kurz gesagt, die Effizienz der Synchronisationsstrategie pro Sekunde ist relativ hoch und die Effizienz der Strategie zur Deaktivierung der Synchronisation ist genauso effizient wie bei RDB.
Aufbau
In der Redis-Konfigurationsdatei gibt es drei Synchronisierungsmethoden:
appendfsync immer #Die AOF-Datei wird jedes Mal geschrieben, wenn eine Datenänderung auftritt.
appendfsync everysec #Synchronize einmal pro Sekunde Diese Richtlinie ist die Standardrichtlinie von AOF.
appendfsync nein #Nie synchronisieren. Effizient, aber die Daten werden nicht gespeichert.
Persistenz-Mischmodus
redis4.0 beginnt, diesen Modus zu unterstützen
Um das Problem zu lösen
Redis lädt AOF-Dateien normalerweise beim Neustart, die Ladegeschwindigkeit ist jedoch langsam Da die RDB-Daten unvollständig sind, wird AOF geladen Öffnungsmethode: aof-use-rdb-preamble true Wenn AOF aktiviert ist, liest es beim Umschreiben direkt den Inhalt der RDB.
Arbeitsprozess
Dies wird durch bgrwriteaof abgeschlossen. Der Unterschied besteht darin, dass die Hybridpersistenz aktiviert ist. 1 Der untergeordnete Prozess schreibt die Daten im Speicher in Form von RDB in die AOF. 2 Schreiben Sie den inkrementellen Befehl im Rewrite-Puffer in die Datei im AOF-Modus 3 Überschreiben Sie die alte AOF-Datei mit den AOF-Daten, die die Anzahl der RDBs und die Anzahl der AOF-Zellen enthalten. In der neuen AOF-Datei stammt ein Teil der Daten aus der RDB-Datei und ein Teil davon aus den inkrementellen Daten, wenn Redis ausgeführt wird.
Vorteil
Hybride Persistenz kombiniert die Vorteile von RDB-Persistenz und AOF-Persistenz. Da die meisten davon im RDB-Format vorliegen, ist die Ladegeschwindigkeit gleichzeitig hoch. Gleichzeitig werden inkrementelle Daten im AOF-Modus gespeichert.
Mangel
Schlechte Kompatibilität. Sobald die Hybridpersistenz aktiviert ist, wird die AOF-Datei in Versionen vor 4.0 nicht erkannt. Gleichzeitig ist die Lesbarkeit schlecht, da der erste Teil im RDB-Format vorliegt.
Persistenz (doppelt offen)
Wenn innerhalb des durch die Standard-RDB angegebenen Zeitintervalls eine bestimmte Anzahl von Schreibvorgängen ausgeführt wird, werden die Daten auf die Festplatte geschrieben.
Geeignet für die Datenwiederherstellung in großem Maßstab, Datenkonsistenz und -integrität sind schlecht
AOF hängt jede Sekunde Schreibvorgangsprotokolle an die AOF-Datei an
AOF-Dateien sind groß und die Datenintegrität ist höher als bei RDB
Vergleichen Sie mit memcached
Alle Werte in Memcached sind einfache Zeichenfolgen, und Redis unterstützt umfangreichere Datentypen.
Redis ist schneller als Memcached und kann Daten beibehalten
Anwendbare Szene
Sitzungscache
Vollständiger Seitencache (FPC)
Warteschlange
Bestenliste/Zähler
veröffentlichen/abonnieren
Der Unterschied zwischen Redis und Memcache
Memcached ist ein leistungsstarkes verteiltes Speicherobjekt-Caching-System
Ein einzelner Schlüsselwert-In-Memory-Cache
Wird in dynamischen Webanwendungen verwendet, um die Datenbanklast zu reduzieren und Bilder, Videos usw. zwischenzuspeichern.
Redis ist eine In-Memory-Datenbank mit Datenstruktur
Unterstützen Sie Datenpersistenz und Datenwiederherstellung und ermöglichen Sie so Single Points of Failure
Umfangreiche Vorgänge können direkt auf der Serverseite ausgeführt werden, um Netzwerk-IO-Zeiten und Datenvolumen zu reduzieren.
Redis Java-Client
Kopfsalat
Der von Springboot standardmäßig verwendete Client
Eine ereignisgesteuerte Kommunikationsschicht basierend auf dem Netty-Framework, deren Methodenaufrufe asynchron sind
Thread-sichere synchrone, asynchrone und reaktive Nutzung, Unterstützung für Cluster, Sentinel, Pipes und Encoder
Redisson
Basierend auf der Netty-Implementierung, unter Verwendung nicht blockierender E/A und hoher Leistung
Unterstützen Sie asynchrone Anfragen
Unterstützt Verbindungspooling
Transaktionen werden nicht unterstützt
Unterstützt Lese-/Schreibtrennung und Leselastausgleich
Kann in Spring Session integriert werden, um eine Redis-basierte Sitzungsfreigabe zu erreichen
Jedis
Leicht, einfach, einfach zu integrieren und zu modifizieren
Unterstützt Verbindungspooling
Unterstützt Pipelining, Transaktionen, LUA Scripting, Redis Sentinel, Redis Cluster
Die Trennung von Lesen und Schreiben wird nicht unterstützt und muss von Ihnen selbst implementiert werden.
häufiges Problem
Warum ist Redis Single-Threaded?
Da Redis ein speicherbasierter Vorgang ist, ist die CPU nicht der Engpass von Redis.
Unnötiger Kontextwechsel und Race Conditions werden vermieden, und es gibt keinen Multiprozess- oder Multithread-Switching, der CPU verbraucht.
Verwenden Sie ein Mehrkanal-E/A-Multiplexmodell und nicht blockierende E/A
Redis hat direkt seinen eigenen VM-Mechanismus erstellt
So stellen Sie die Konsistenz zwischen Redis und Datenbank sicher
Löschen Sie beim Aktualisieren zuerst den Cache und aktualisieren Sie dann die Datenbank.
Lesen Sie beim Lesen zuerst den Cache. Wenn nicht, lesen Sie die Datenbank, legen Sie die Daten in den Cache und geben Sie die Antwort zurück.
Legen Sie unter besonderen Umständen die Cache-Ablaufzeit fest
So implementieren Sie eine verteilte Sperre in Redis
SET-Schlüsselwert [EX Sekunden] [PX Millisekunden] [NX|XX]
EX Sekunde: Stellen Sie die Ablaufzeit des Schlüssels auf Sekunden ein
NX: Legen Sie den Schlüssel nur fest, wenn der Schlüssel nicht vorhanden ist
Wenn die SET-Operation erfolgreich abgeschlossen wurde, wird OK zurückgegeben, andernfalls wird null zurückgegeben.
PX Millisekunde: Legen Sie die Ablaufzeit des Schlüssels auf Millisekunden Millisekunden fest
XX: Legen Sie den Schlüssel nur fest, wenn der Schlüssel bereits vorhanden ist.
Es ist nur in einem Einzelinstanzszenario sicher
Mehrere Clients können die Sperre gleichzeitig erwerben
Asynchrone Erfassung, Knotenausnahme
Redis-Speicheroptimierung
Optimierung der Speicherkodierung
Die in Redis gespeicherten Daten werden mithilfe der redisObject-Struktur gekapselt.
gemeinsam genutzter Objektpool
Bezieht sich auf den Integer-Objektpool [0-9999], der intern von Redis verwaltet wird, um Speicher zu sparen.
Zusätzlich zu Ganzzahlwertobjekten können auch andere Typen wie interne Listen-, Hash-, Set- und Zset-Elemente den Ganzzahlobjektpool verwenden.
String-Optimierung
Kontrollieren Sie die Anzahl der Schlüssel und verwenden Sie Hash anstelle mehrerer Schlüsselwerte
Reduzieren Sie Schlüsselwertobjekte. Je kürzer der Schlüsselwert, desto besser
Häufige Leistungsprobleme mit Redis
Verhindern Sie, dass der Master Speicher-Snapshots schreibt
Die AOF-Persistenz des Masters beeinträchtigt die Wiederherstellungsgeschwindigkeit beim Neustart des Masters.
Verhindern Sie, dass der Master BGREWRITEAOF aufruft, um die AOF-Datei neu zu schreiben und eine kurze Dienstunterbrechung zu verursachen.
Leistungsprobleme bei der Redis-Master-Slave-Replikation
Für die Geschwindigkeit der Master-Slave-Replikation und die Stabilität der Verbindung ist es am besten, wenn sich Slave und Master im selben LAN befinden.
Welche Eliminierungsstrategien gibt es?
volatile-lru: Aus dem Datensatz mit festgelegter Ablaufzeit
Wählen Sie die aktuellsten und ungenutzten Daten zur Freigabe aus
allkeys-lru: Aus dem Datensatz (einschließlich des Datensatzes mit festgelegter Ablaufzeit und der nicht festgelegten Ablaufzeit)
Wählen Sie die aktuellsten und ungenutzten Daten zur Freigabe aus
volatile-random: aus dem Datensatz mit festgelegter Ablaufzeit
Wählen Sie zufällig ein Datenelement zur Freigabe aus
allkeys-random: aus dem Datensatz (einschließlich festgelegter Ablaufzeit und nicht festgelegter Ablaufzeit)
Wählen Sie zufällig ein Datenelement zur Freigabe aus
volatile-ttl: Aus dem Datensatz mit festgelegter Ablaufzeit
Wählen Sie Daten aus, die demnächst ablaufen, und geben Sie sie frei
noeviction: Keine Daten löschen (Redis wird sie jedoch auch basierend auf dem Referenzzähler freigeben)
Wenn zu diesem Zeitpunkt nicht genügend Speicher vorhanden ist, wird direkt ein Fehler zurückgegeben.
So finden Sie aus einer großen Anzahl von Schlüsseln einen Schlüssel mit einem festen Präfix
Tastenmusterbefehl
Gibt alle passenden Schlüssel zurück
Wenn eine große Anzahl von Schlüsseln abgefragt wird, wirkt sich dies auf den laufenden Dienst aus, da der Dienst verzögert wird, wenn die auf einmal zurückgegebene Datenmenge relativ groß ist.
SCAN-Cursor [MATCH pttern] [Count count] Befehl
SCAN ist eine Liste von Abrufanweisungen im nicht blockierenden Modus, die jedes Mal nur eine kleine Anzahl von Elementen zurückgibt
Cursor bezieht sich auf den Cursor, der MATCH-Musterwert ist eine Anweisung und der Zählparameter gibt die Anzahl der zurückgegebenen Daten an, aber die Zählung kann die Anzahl nicht streng steuern.
scan 0 match k1* count 10 //Dieser Befehl bezieht sich auf die hohe Wahrscheinlichkeit, Zähldaten zurückzugeben, die mit k1 beginnen
Dieser Befehl führt nur neue Iterationen mit 0 als Startpunkt des Cursors durch, bis der vom Befehl zurückgegebene Cursor 0 ist. Das heißt, wenn der zurückgegebene Cursor 0 ist, bedeutet dies, dass der gesamte Iterationsprozess abgeschlossen ist.
Der inkrementelle Iterationsbefehl SCAN garantiert nicht, dass jede Ausführung eine bestimmte Anzahl von Elementen zurückgibt, die 0 sein kann. Wenn der vom Befehl zurückgegebene Cursor nicht Null ist, verwendet die Anwendung weiterhin den vorherigen Cursor für die Iteration, bis der Cursorwert erreicht ist ist 0. Bei größeren Datensätzen können Dutzende von Daten gleichzeitig zurückgegeben werden. Bei kleineren Datensätzen können alle Datensätze direkt zurückgegeben werden.
Alle vom SCAN-Befehl erkannten Befehlspaare können doppelte Werte aufweisen, sodass wir Hashset verwenden können, um eine Datendeduplizierung zu erreichen.
Im Speicher gespeichert
Strukturdiagramm
Verteilter Speicher
MongoDB
FastDFS
Elasticsearch
Voller Cache
Binlog
Es handelt sich um eine Master-Slave-Datensynchronisierungslösung für MySQL und die meisten gängigen Datenbanken.
Andere Caching-Frameworks/Datenbanken
SSDB
RocksDB
Nachrichtenwarteschlange (MQ)
Kafka/Jafka
Vorteil
Zeitkomplexität O(1)
Hoher TPS
Mangel
Unterstützt keine geplanten Nachrichten
Kafka-Streams
ActiveMQ
RabbitMQ
Vorteil
Hohe Parallelität (verursacht durch die Implementierungsmerkmale der Erlang-Sprache)
Hohe Zuverlässigkeit und hohe Verfügbarkeit
Mangel
Schwergewicht
Publish-Subscribe-Modell
Das Publish-Subscribe-Modell von RabbitMQ
Austausch
Von Produzenten gesendete Nachrichten können nur an den Switch gesendet werden. Der Switch entscheidet, an welche Warteschlange gesendet werden soll, und der Produzent kann nicht entscheiden.
temporäre Warteschlange
queueDeclare() zum Erstellen einer nicht persistenten, proprietären, automatisch gelöschten Warteschlange mit einem zufällig generierten Namen
Bindung
RocketMQ
Java-Sprachimplementierung
Komponenten
Name Server
Makler
Hersteller
Verbraucher
Zwei Verbrauchsmodelle
ZIEHEN
DefaultMQPullConsumer
DRÜCKEN
DefaultMQPushConsumer
Vorteil
Hohe Datenzuverlässigkeit
Unterstützt synchrones Disk-Brushing, asynchrones Echtzeit-Disk-Brushing, synchrone Replikation und asynchrone Replikation
Nachrichtenzustellung in Echtzeit
Wiederholungsversuch bei fehlgeschlagener Support-Nachricht
Hoher TPS
Eine einzelne Maschine schreibt etwa 70.000 Nachrichten/Sekunde an eine einzelne TPS-Instanz. Bei der Bereitstellung von 3 Brokern auf einer einzelnen Maschine können maximal 120.000 Nachrichten/Sekunde erreicht werden.
Strenge Nachrichtenreihenfolge
Unterstützen Sie geplante Nachrichten
Unterstützt das Zurückverfolgen von Nachrichten nach Zeit
Milliarden von Nachrichten häuften sich
Mangel
Der Konsumprozess muss idempotent sein (Entfernung von Duplikaten)
ZeroMQ
Vorteil
Hoher TPS
Mangel
Permanente Nachrichten werden nicht unterstützt
Schlechte Zuverlässigkeit und Verfügbarkeit
JMS
API
Verbindungsfabrik
Verbindung
Sitzung
Ziel
Nachrichtenproduzent/-konsument
Nachrichtenzusammensetzung
Nachrichtenkopf
Nachrichtentext
Textnachricht
MapMessage
BytesMessage
StreamMessage
ObjectMessage
Nachrichteneigenschaften
Zuverlässiger JMS-Mechanismus
Die Nachricht gilt erst dann als erfolgreich verarbeitet, wenn sie bestätigt wurde. Der Nachrichtenverbrauch besteht aus drei Phasen: Der Client empfängt die Nachricht, der Client verarbeitet die Nachricht und die Nachricht wird bestätigt
Transaktionssitzung
Nachrichten werden nach session.commit automatisch übermittelt
nicht-transaktionale Sitzung
Antwortmodus
AUTO_ACKNOWLEDGE
automatische Bestätigung
CLIENT_ACKNOWLEDGE
textMessage.acknowledge()Nachricht bestätigen
DUPS_OK_ACKNOWLEDGE
Verzögerte Bestätigung
Peer-to-Peer (P2P-Modus)
Veröffentlichen und abonnieren (Pub/Sub-Modus)
dauerhaftes Abonnement
nicht dauerhaftes Abonnement
Datenbank-Middleware
Unterdatenbank und Untertabelle
ShardingSphere
Architekturdiagramm
SJDBC (Sharding-JDBC)
Meine Katze
andere
Disque
Kassandra
Neo4j
InfoGrid
Verteiltes Framework
Dubbo
Frühlingswolke
Nacos
Apollo
Disconf
Verteilte Architektur
Servicekomponente
Registrierungszentrum
Tierpfleger
Datenmodell
Knotentyp
Persistenzknoten
Persistente geordnete Knoten
Temporärer Knoten
temporärer geordneter Knoten
Befehl
Knoten erstellen
Erstelle [-s] [-e] Pfaddaten-ACL
Knoten abrufen
Pfad abrufen [anschauen]
Knoten auflisten
ls [Pfad]
Knoten ändern
Pfaddaten festlegen [Version]
Knoten löschen
Pfad [Version] löschen
Anwendbare Szene
Abonnement-Veröffentlichungs-/Konfigurationscenter
Implementierung des Watcher-Mechanismus
Realisieren Sie die zentrale Verwaltung von Konfigurationsinformationen und die dynamische Aktualisierung von Daten
Diensterkennung
Verteilte Sperre
Implementierung temporärer geordneter Knoten und eines Überwachungsmechanismus
Exklusives Schloss
Temporäre Knotenimplementierung
gemeinsame Sperre
Temporäre geordnete Knotenimplementierung
Lastverteilung
Anfragen/Daten werden über mehrere Rechnereinheiten verteilt
ID-Generator
verteilte Warteschlange
Einheitlicher Namensdienst
Meisterwahl
Split-Brain-Probleme können vermieden werden
Begrenzend
Euraka
Konsul
Dateisystem
NFS
FTP
Ceph
AWS S3
Netzdienste
Service-Mesh
Linkerd
Istio
Gesandte
Dynamische Serviceerkennung
Lastverteilung
Umfrage
zufällig
Mindestgewichtete Anfragen
TLS-Terminierung
HTTP/2- und gRPC-Proxy
Sicherung
Gesundheitsprüfung, Graustufenfreigabe basierend auf der prozentualen Verkehrsaufteilung
Fehlerinjektion
Umfangreiche Messwerte
Rührgerät
Zugangskontrolle
Verwenden Sie Strategie
Datensammlung
Pilot
Diensterkennung
Robustes Datenverkehrsmanagement (Timeout, Wiederholung, Leistungsschalter usw.).
Intelligentes Routing
Zitadelle
Galeere
Gesandte
nginmesh
Werkzeugbibliothek
Apache Commons
GoogleGuave
Lombok
Bibliothek zur Bytecode-Manipulation
ASM
Cglib
Javassist
Byteman
Byte Kumpel
Bytecode-Viewer
json
FastJson
Gson
Jackson
Json-lib
Andere Frameworks
reaktives Gerüst
Vert.x
asynchrones Framework
Netty
Fliesen
Kernalgorithmus
Konsensalgorithmus
Lastausgleichsalgorithmus
Strombegrenzungsalgorithmus
Verteilte Aufgabenplanung
Verteilte ID-Generierung
Verteilte Koordination und Synchronisation
Filteralgorithmus
Hash-Algorithmus
Anwendung: Dateiüberprüfung, digitale Signatur, Authentifizierungsprotokoll
Typ
MD5 (Message-Digest-Algorithmus 5)
Algorithmus, der eine vollständige und konsistente Informationsübertragung gewährleistet und eine feste Länge von 128 Bit ausgibt
SHA-1
Wird häufig für HTTPS-Übertragung und Softwaresignatur verwendet
SHA-2
SHA-224/SHA-256/SHA-384/SHA-512 und wird zu SHA-2
SHA-3
Früher als Keccak-Algorithmus bekannt, handelt es sich um einen kryptografischen Hash-Algorithmus
Probleme und Methoden
Erstellen Sie leistungsstarke Lesedienste
Die Daten im Cache werden nur dann gefiltert und gespeichert, wenn sie geschäftliche Bedeutung haben und abgefragt werden.
Daten im Cache können komprimiert werden
Komprimierungsalgorithmen wie Gzip und Snappy
Felder werden während der JSON-Serialisierung durch alternative Bezeichner ersetzt
Redis verwendet eine Hash-Struktur zum Speichern von Daten. Sie können stattdessen auch Bezeichner verwenden.
Asynchrones parallelisiertes Lesen
Erstellen Sie einen hochverfügbaren Datenschreibdienst
Datenbank-Sharding/Daten-Sharding
Weltweit eindeutiger Bezeichner
Zufällig mithilfe eines Algorithmus generiert
Erstellen Sie einen ID-Generierungsdienst basierend auf dem Datenbank-Primärschlüssel
Unterbibliotheks-Middleware
Meine Katze
Zustandslose Speicherung, Datenbank jederzeit ausschneiden
Schreiben Sie nach dem Zufallsprinzip entsprechend der Gewichtung der verfügbaren Bibliotheken
Nachdem die Daten erfolgreich in den Zufallsspeicher geschrieben wurden, werden die Daten aktiv in den Cache geschrieben.
Vollständige Synchronisierung, die Erstellungszeit für das Scannen der Datenbank beträgt mehr als 5 Sekunden (konfigurierbar) und die Daten sind nicht synchronisiert
Cache-Downgrade
Führen Sie für eine vollständige Abfrage ein aktives Downgrade auf die Datenbank durch und speichern Sie den abgefragten Wert im Cache
Nachrichtenwarteschlange
Kann aus dem Cache gelesen und asynchron in die Datenbank geschrieben werden
Hochverfügbare Architektur
Zwischenspeichern Sie Hot-Backups für mehrere Maschinen, um Cache-Verluste und andere Probleme zu vermeiden
Nutzung des In-App-Precaching
Lastverteilung
HAProxy
Nginx
Netzwerkmodell
epoll (multiplexed IO)
Downgrade-Schutz
Lese- und Schreibtrennung
Trennung von dynamischem und statischem Verkehr
So stellen Sie die Konsistenz heterogener Daten sicher
Multithreading und Parallelität
Grundprinzipien
synchronisiert
Thread-Sicherheitsprobleme
Es sind freigegebene Daten vorhanden (auch als Offline-Ressourcen bezeichnet).
Es gibt mehrere Threads, die zusammenarbeiten, um diese gemeinsam genutzten Daten zu verwalten
Lösung: Nur ein Thread darf gemeinsam genutzte Ressourcen gleichzeitig bedienen. Andere Threads müssen warten, bis die Verarbeitung durch den Thread abgeschlossen ist, bevor sie gemeinsam genutzte Ressourcen betreiben können.
Eigenschaften der Mutex-Sperre
gegenseitige Ausschließlichkeit
Nur ein Thread darf gleichzeitig eine Objektsperre halten. Durch diese Funktion wird ein Multi-Thread-Koordinierungsmechanismus implementiert, sodass nur ein Thread gleichzeitig auf den Codeblock (zusammengesetzte Operation) zugreifen kann Zeit. Gegenseitige Ausschließlichkeit wird auch als Atomizität von Operationen bezeichnet
Sichtweite
Es muss sichergestellt werden, dass die Änderungen, die vor der Aufhebung der Sperre an der gemeinsam genutzten Variablen vorgenommen wurden, für den Thread sichtbar sind, der die Variable anschließend bearbeitet. Das heißt, der neueste Wert der gemeinsam genutzten Variablen sollte beim Erwerb der Sperre abgerufen werden, andernfalls ein anderer Thread kann lokal auf die gemeinsam genutzte Variable zugreifen. Eine der zwischengespeicherten Kopien funktioniert weiterhin, was zu Inkonsistenzen führt
Was synchronisierte Sperren ist, ist nicht der Code, sondern das Objekt.
Zwei Möglichkeiten, Objektsperren zu erhalten
synchronisierter Codeblock
Synchronisierter Codeblock, synchronisiert (dies), synchronisiert (Instanzobjekt), das Instanzobjekt wird beim Sperren in Klammern gesetzt
Synchronisierte nichtstatische Methoden
Bei der synchronisierten Methode ist das aktuelle Instanzobjekt gesperrt
Nach der Klassifizierung der Erwerbsschlösser
Holen Sie sich eine Objektsperre
synchronisierter Codeblock
synchronisiert (dies), synchronisiert (Klasseninstanzobjekt), die Sperre ist das Instanzobjekt in ()
Synchronisierte nichtstatische Methoden
Die synchronisierte Methode sperrt die Instanz des aktuellen Objekts
Holen Sie sich eine Klassensperre
Der synchronisierte Codeblock synchronisiert (class.class) sperrt das Klassenobjekt in Klammern
Die synchronisierte statische Methode sperrt das aktuelle Klassenobjekt (Klassenobjekt).
synchronisiert Das zugrunde liegende Implementierungsprinzip
Die Anordnung von Objekten im Speicher
Objektheader
Mark Welt
Standardmäßig werden der HashCode und das Generationsalter des gespeicherten Objekts gespeichert. Sperrtyp, Sperrflag und andere Informationen
Sperrstatus
Entsperrter Zustand
leichtes Schloss
Schweres Schloss
GC-Zeichen
Vorspannungssperre
Klassenmetadatenadresse
Der Typzeiger zeigt auf die Klassenmetadaten des Objekts, und die JVM verwendet diesen Zeiger, um zu bestimmen, um welche Klasse es sich bei dem Objekt handelt.
Instanzdaten
Polsterung ausrichten
Was ist Wiedereintritt?
Aufgrund des Designs der Mutex-Sperre wird ein Thread blockiert, wenn er versucht, auf die kritische Ressource der Objektsperre zuzugreifen, die von einem anderen Thread gehalten wird. Wenn ein Thread erneut die kritische Ressource der von ihm gehaltenen Objektsperre anfordert, handelt es sich um eine reentrant-Situation.
Warum verspotten Sie synchronisiert?
In frühen Versionen war synchronisiert ein Schwergewichtsschloss und stützte sich bei der Implementierung auf Mutex Lock.
Das Wechseln zwischen Threads erfordert den Wechsel vom Benutzermodus in den Kernelmodus, was teuer ist.
Nach Java6 synchronisiert Die Leistung wurde erheblich verbessert
Spin-Lock
Spin-Lock
In vielen Fällen dauert der Sperrzustand gemeinsam genutzter Daten so kurz, dass sich ein Threadwechsel nicht lohnt.
Indem der Thread eine Besetztschleife ausführen und auf die Freigabe der Sperre warten lässt, wird die CPU nicht aufgegeben.
Nachteile: Wenn die Sperre längere Zeit von anderen Threads belegt ist, führt dies zu einem erheblichen Leistungsaufwand.
Adaptive Spin-Sperre
Die Schleuderzeit ist nicht mehr festgelegt
Wird durch die vorherige Spin-Zeit für dieselbe Sperre und den Status des Sperreneigentümers bestimmt
Sperrenbeseitigung
Gründlichere Optimierung
Während der JIT-Kompilierung wird ein Kontextscan durchgeführt, um Sperren zu entfernen, bei denen keine Konkurrenz möglich ist.
Schlossaufrauung
Vermeiden Sie wiederholtes Ver- und Entriegeln, indem Sie den Umfang des Schlosses erweitern
Synchronisierte vier Zustände sperren
kein Schloss
Vorspannungssperre
Reduzieren Sie die Kosten für den Erwerb von Sperren für denselben Thread. In den meisten Fällen gibt es keinen Multithread-Wettbewerb um Sperrressourcen, und derselbe Thread ruft die Sperrressource immer mehrmals ab.
Kernidee: Wenn ein Thread die Sperre erhält, wechselt die Sperre in den voreingenommenen Modus und die Struktur des Markierungsworts wird zu einer voreingenommenen Struktur. Wenn der Thread die Sperre erneut anfordert, ist keine Synchronisierungsaktion erforderlich. Das heißt, beim Erlangen der Sperre müssen nur das Markierungsbit der Markierungswortsperre und die aktuelle ID überprüft werden Thread ist gleich der ThreadID des Markierungsworts. Dies kann die Notwendigkeit einer großen Anzahl von Anwendungsvorgängen im Zusammenhang mit Sperren ersparen
leichtes Schloss
Leichte Schlösser werden von voreingenommenen Schlössern aufgewertet. Wenn der zweite Thread dem Sperrenwettbewerb beitritt, wird die voreingenommene Sperre zu einer leichten Sperre aktualisiert.
An das Szenario anpassen: Threads führen abwechselnd synchronisierte Codeblöcke aus Wenn gleichzeitig auf dasselbe Schloss zugegriffen wird, wird es zu einem Schwergewichtsschloss erweitert.
Schweres Schloss
synchronisiert Und ReenTrantLock der Unterschied
Reentrant: Einführung in die Sperre (Wiedereintrittssperre).
Befindet sich im j.U.C-Paket
Implementiert basierend auf AQS wie CountDownLatch, FutureTask und Semaphore
Kann eine feinkörnigere Kontrolle erreichen als synchronisiert, z. B. die Kontrolle der Fairness
Nach dem Aufruf von lock() müssen Sie zum Entsperren unlock() aufrufen
Die Leistung darf nicht höher als synchronisiert sein und ist auch wiedereintrittsfähig.
ReentrantLock-Fairness-Einstellungen
Erstellen Sie ein Beispiel für ein faires Schloss ReentrantLock fairLock = new ReetrantLock(true);
Wenn der Parameter wahr ist, wird die Sperre tendenziell dem Thread erteilt, der am längsten gewartet hat.
faires Schloss
Die Reihenfolge des Erwerbs von Sperren basiert auf der Reihenfolge, in der die Sperrmethode aufgerufen wird (mit Vorsicht verwenden).
unfaire Sperre
Die Reihenfolge der Präemption ist nicht unbedingt festgelegt, sie hängt vom Glück ab.
Faire Sperre und unfaire Sperre
synchronisiert ist eine unfaire Sperre
ReentrantLock objektiviert Sperren
Stellen Sie fest, ob ein Thread oder ein bestimmter Thread in der Warteschlange darauf wartet, die Sperre zu erhalten
Versuchen Sie, eine Sperre mit Zeitüberschreitung zu erhalten
Erkennen Sie, ob die Sperre erfolgreich erworben wurde
Kann wait/notify/notifyAll objektiviert werden?
java.util.concurrent.locks.Condition
ArrayBlockingQueue ist eine threadsichere, begrenzte Blockierungswarteschlange, die vom zugrunde liegenden Array implementiert wird.
Zusammenfassen
synchronisiert ist das Schlüsselwort, ReentrantLock ist die Klasse
ReentrantLock kann die Wartezeit für den Erwerb der Sperre festlegen, um einen Deadlock zu vermeiden.
ReentrantLock kann Informationen zu verschiedenen Sperren abrufen
ReentrantLock kann mehrere Benachrichtigungen flexibel implementieren
Mechanismus: sync arbeitet mit dem Mark Word des Objektheaders und lock ruft die park()-Methode der Unsafe-Klasse auf.
JMM-Speichersichtbarkeit
Was ist java im Speichermodell passieren-vorher
Java von Erinnerung Modell JMM
Das Java Memory Model (kurz JMM) selbst ist ein abstraktes Konzept und existiert nicht wirklich. Durch diesen Satz von Spezifikationen wird jede Variable des Programms (einschließlich Instanzfelder) definiert und Elemente, die ein Array-Objekt bilden).
Hauptspeicher im JMM
Speichern Sie Java-Instanzobjekte
Einschließlich Mitgliedsvariablen, Klasseninformationen, konstantes Licht, statische Variablen usw.
Gehört zu einem Datenfreigabebereich, der Thread-Sicherheitsprobleme verursachen kann, wenn Multithread-Vorgänge gleichzeitig ausgeführt werden.
JMM-Arbeitsspeicher
Speichert alle lokalen Variableninformationen der aktuellen Methode. Lokale Variablen sind für andere Threads nicht sichtbar.
Bytecode-Zeilennummernanzeige, Informationen zur nativen Methode
Es gehört zum privaten Thread-Datenbereich und weist keine Thread-Sicherheitsprobleme auf.
JMM- und Java-Speicherbereichsaufteilung sind unterschiedliche konzeptionelle Ebenen
JMM beschreibt eine Reihe von Regeln, die sich um Atomizität, Ordnung und Sichtbarkeit drehen.
Gemeinsamkeiten: Es gibt Gemeinschaftsbereiche und private Bereiche
Zusammenfassung der Datenspeicherarten und Betriebsweisen von Hauptspeicher und Arbeitsspeicher
Die lokalen Variablen des Basisdatentyps in der Methode werden direkt in der Stapelrahmenstruktur des Arbeitsspeichers gespeichert.
Lokale Variablen vom Referenztyp: Die Referenz wird im Arbeitsspeicher und die Instanz im Hauptspeicher gespeichert
Mitgliedsvariablen, statische Variablen und Klasseninformationen werden alle im Hauptspeicher gespeichert.
Die Hauptspeicherfreigabemethode besteht darin, dass jeder Thread eine Kopie der Daten in den Arbeitsspeicher kopiert und sie nach Abschluss des Vorgangs wieder im Hauptspeicher aktualisiert.
JMM Wie löst man Problem mit der Speichersichtbarkeit
Bedingungen, die für die Neuordnung von Anweisungen erfüllt sein müssen
Die Ergebnisse der Operation können in einer Single-Threaded-Umgebung nicht geändert werden.
Bei Datenabhängigkeiten ist eine Neuordnung nicht zulässig.
Das bedeutet, dass nur Anweisungen neu angeordnet werden können, die nicht durch das „Passiert-vorher“-Prinzip abgeleitet werden können.
Wenn die fehlerhafte Operation von A die Operations-Lernsoftware von B erfordert, dann besteht zwischen A und B eine Passiert-Vorher-Beziehung.
passieren-vorher grundsätzlich
Die wichtigste Grundlage für die Beurteilung, ob in den Daten Konkurrenz besteht und ob der Thread sicher ist
Regeln für die Programmreihenfolge
In einem Thread erfolgen entsprechend der Codereihenfolge die vorne geschriebenen Operationen vor den hinten geschriebenen Operationen.
Sperrregeln
Ein Entsperrvorgang erfolgt vor einem nachfolgenden Sperrvorgang für dieselbe Sperre.
Regeln für flüchtige Variablen
Ein Schreibvorgang für eine Variable erfolgt vor einem nachfolgenden Lesevorgang für die Variable.
Lieferregeln
Thread-Startregeln
Die start()-Methode des Thread-Objekts wird bei jeder Aktion dieses Threads zuerst ausgeführt.
Thread-Beendigungsregeln
Der Aufruf der Interrupt()-Methode des Threads erfolgt erst, nachdem der Code des unterbrochenen Threads das Auftreten des Interrupt-Ereignisses erkennt.
Thread-Beendigungsregeln
Alle Vorgänge im Thread werden zuerst ausgeführt, wenn der Thread beendet wird. Wir können anhand der Thread.join()-Methode und des Rückgabewerts von Thread.isAlive() erkennen, dass der Thread beendet wurde.
Die Initialisierung eines Objekts erfolgt zuerst zu Beginn seiner finalize()-Methode.
Wenn zwei Vorgänge keine der oben genannten „Vorhergehens“-Regeln erfüllen, ist die Reihenfolge dieser beiden Vorgänge nicht garantiert und die JVM kann die beiden Vorgänge neu anordnen.
Wenn Vorgang A vor Vorgang B ausgeführt wird, sind die von Vorgang A im Speicher ausgeführten Vorgänge für Vorgang B sichtbar.
flüchtig
Leichter Synchronisierungsmechanismus, der von JVM bereitgestellt wird
Stellen Sie sicher, dass durch Volatile geänderte gemeinsam genutzte Variablen immer für alle Threads sichtbar sind
Deaktivieren Sie die Optimierung der Neuordnung von Anweisungen
Volatile garantiert keine Sicherheit in Multithread-Situationen
Nicht Thread-sicher
Thread-Sicherheit
Thread-Sicherheit
flüchtige Variablen und warum sie sofort sichtbar sind
Beim Schreiben einer flüchtigen Variablen aktualisiert JMM den Wert der gemeinsam genutzten Variablen im Arbeitsspeicher, der dem Thread im Hauptspeicher entspricht.
Beim Lesen einer flüchtigen Variablen macht JMM den dem Thread entsprechenden Arbeitsspeicher ungültig.
volatil, wie z. B. die Deaktivierung der Neuordnungsoptimierung
Gedächtnisbarriere
Garantieren Sie die Ausführungsreihenfolge bestimmter Vorgänge
Gewährleisten Sie die Speichersichtbarkeit bestimmter Variablen
Deaktivieren Sie Neuordnungsoptimierungen für Anweisungen vor und nach einer Speicherbarriere, indem Sie eine Speicherbarriere einfügen
Erzwingt das Leeren zwischengespeicherter Daten für verschiedene CPUs, sodass Threads auf jeder CPU die neueste Version dieser Daten lesen können
Doppelte Erkennungsimplementierung von Singleton
Verwenden Sie volatile, um die Neuordnungsoptimierung zu deaktivieren
Der Unterschied zwischen volatil und synchronisiert
Der Kern von Volatilität besteht darin, der JVM mitzuteilen, dass der Wert der aktuellen Variablen im Register (Arbeitsspeicher) unsicher ist und aus dem Hauptspeicher gelesen werden muss. Nur der aktuelle Thread kann auf die Variable zugreifen. und andere Threads werden blockiert, bis sie den Wert kennen, bis der Thread die Variablenoperation abschließt
Volatile kann nur auf Variablenebene verwendet werden, und synchronisiert kann auf Variablen-, Methoden- und Klassenebene verwendet werden.
Volatile kann nur die Sichtbarkeit von Variablenänderungen realisieren, kann jedoch keine Atomizität garantieren, während synchronisiert die Sichtbarkeit und Atomizität von Variablenänderungen garantieren kann.
Volatilität führt nicht zu einer Thread-Blockierung; synchronisiert kann zu einer Thread-Blockierung führen.
Als flüchtig gekennzeichnete Variablen werden vom Compiler nicht optimiert; als synchronisiert markierte Variablen können vom Compiler optimiert werden.
CAS-Lock-Free-Technologie (Vergleichen und tauschen)
synchronisiert ist eine pessimistische Sperre, CAS ist ein optimistisches Sperrdesign
Unterstützt atomare Aktualisierungsvorgänge, geeignet für Zähler, Sequenzer und andere Szenarien
Es handelt sich um einen optimistischen Verriegelungsmechanismus, der als Lock-Free bezeichnet wird.
Der Eindruck ist, dass es auf der untersten Ebene immer noch ein Sperrverhalten gibt.
Wenn der CAS-Vorgang fehlschlägt, entscheidet der Entwickler, ob er es weiter versucht oder andere Vorgänge ausführt.
Es wird also nicht blockiert und hängen bleiben
dachte CAS
Enthält drei Operanden
Speicherplatz (V)
Erwarteter Originalwert (A)
neuer Wert (B)
Bei der Durchführung einer CAS-Operation wird der Wert des Speicherorts mit dem erwarteten Originalwert verglichen. Wenn sie gleich sind, setzt der Prozessor den Wert des Speicherorts automatisch auf den neuen Wert, andernfalls führt der Prozessor keine Verarbeitung durch. Der Wert des Speicherplatzes ist der Wert des Hauptspeichers
CAS ist für Entwickler in den meisten Fällen transparent
Das Atompaket von J.U.C bietet häufig verwendete Atomdatentypen sowie verwandte Atomtypen wie Referenzen und Arrays sowie Aktualisierungsoperationstools. Es ist die erste Wahl für viele Thread-sichere Programme.
Obwohl die Unsafe-Klasse CAS-Dienste bereitstellt, birgt sie versteckte Gefahren, da sie Speicheradressen willkürlich zum Lesen und Schreiben manipulieren kann und daher nicht einfach manuell implementiert werden kann.
Sie müssen Unsafe aufrufen. Nach Java 9 wird die Variable Handke API bereitgestellt, um Unsafe zu ersetzen.
Nachteile von CAS
Wenn die Zeit der schwachen Schleife lang ist, ist der Overhead hoch
Nur atomare Operationen auf einer gemeinsam genutzten Variablen sind garantiert
ABA-Problem
Wenn der Wert einer Variablen A ist, aber während des Zeitraums von einem anderen Thread in B und dann wieder in A geändert wurde, geht die CAS-Operation davon aus, dass der Wert zu diesem Zeitpunkt nicht geändert wurde.
Lösung: Stellt eine Version der AtomicStampedeReference-Steuervariablen zur Lösung des ABA-Problems von CAS bereit
Verfahren
Multi-Fortschritt
Merkmale
Speicherisolation: Eine Ausnahme in einem einzelnen Prozess führt nicht zum Absturz der gesamten Anwendung, was das Debuggen erleichtert
Prozessübergreifende Aufrufe, Kommunikation und Vermittlung sind teuer
Wird häufig in Szenarien mit geringer Interaktion zwischen Zielunterfunktionen, schwacher Korrelation und skalierbaren Szenarien für die Verteilung auf mehreren Maschinen (Nginx-Lastausgleich) verwendet
Klassifizierung von Prozessen
Daemon
Daemon-Thread (Daemon-Thread)
Bereitstellung von Diensten für die Ausführung anderer Threads
GC-Thread
Nicht-Daemon-Prozess
Benutzer-Thread (Benutzer-Thread)
So erstellen Sie einen Prozess
Verwenden Sie die Methode exec(String cmdarray[]) von Runtime, um eine Instanz einer virtuellen Maschine zu erstellen
Jeder Prozess wird nur in einer Instanz einer virtuellen Maschine ausgeführt (der zugrunde liegende Quellcode übernimmt den Singleton-Modus).
Erstellen Sie einen Betriebssystemprozess mit der start()-Methode von ProcessBuilder
Der Unterschied zwischen Prozess und Thread
Prozess/Prozess
ist die Entität des Programms
Ein Programm ist eine Beschreibung von Anweisungen, Daten und deren Organisation
Dabei handelt es sich um die laufende Aktivität eines Programms auf einem Computer mit einem bestimmten Datensatz.
Es ist die Grundeinheit für die Ressourcenzuweisung und -planung im System.
Es ist die Grundlage der Betriebssystemstruktur.
Ist ein Container für Threads
Prozesseigenschaften
Unabhängigkeit
Dynamisch
Parallelität
Starten Sie einen Computer, einen Texteditor usw. über einen Prozess
Faden
Es existiert abhängig vom Prozess. Jeder Thread muss einen übergeordneten Prozess haben.
Der Thread verfügt über einen eigenen Stapel, Programmzähler und lokale Variablen, und der Thread teilt die Systemressourcen des Prozesses mit anderen Threads
Prozesse können keinen Speicher gemeinsam nutzen, während Threads den Speicher problemlos miteinander teilen können
Thread-Grundlagen
Die Erstellung eines Threads muss durch einen anderen Thread abgeschlossen werden
Der übergeordnete Thread eines erstellten Threads ist der Thread, der ihn erstellt hat
Erstelle einen Thread
Implementieren Sie die Ausführungsmethode der Runnable-Schnittstelle
Überschreiben Sie die Ausführungsmethode der Thread-Klasse
Daemon-Thread
Thread beitreten
Interrupt-Interrupt-Funktion
1. Rufen Sie interrupt() auf, um dem Thread mitzuteilen, dass er unterbrochen werden soll.
Wenn der Thread blockiert ist, verlässt er den blockierten Zustand sofort und löst eine InterruptedException aus
Aktuelle Nutzung
Der aufgerufene Thread muss mit dem Interrupt kooperieren
Wenn Sie Aufgaben normal ausführen, müssen Sie das Interrupt-Flag-Bit dieses Threads häufig überprüfen. Wenn das Interrupt-Flag gesetzt ist, stoppen Sie den Thread selbst.
Wenn es sich in einem normalen aktiven Zustand befindet, setzen Sie das Interrupt-Flag-Bit des Threads auf true, und der eingestellte Thread wird normal ausgeführt und ist nicht betroffen.
Der Unterschied zwischen Thread und Runable
Runable ist die Schnittstelle
Thread ist eine Klasse, die die Runable-Schnittstelle implementiert
Aufgrund des Einzelvererbungsprinzips von Klassen wird die Verwendung der Runnable-Schnittstelle empfohlen
Der Unterschied zwischen Schlafen und Warten
schlafen()
Thread.sleep()
Die Schlafmethode ist überall einsetzbar
Der Ruhezustand gibt nur die CPU frei und führt nicht dazu, dass sich das Sperrverhalten ändert.
Warten()
Object.wait()
wait kann nur in synchronisierten Methoden oder synchronisierten Codeblöcken verwendet werden
Der Unterschied zwischen notify und notifyAll
Pool sperren und Pool warten
Sperrbecken
Angenommen, Thread A besitzt bereits die Sperre eines Objekts (nicht) und andere Threads B und C möchten die synchronisierte Methode oder den synchronisierten Codeblock dieses Objekts aufrufen, da Threads B und C die synchronisierte Methode (oder den Codeblock) eingeben müssen. des Objekts, Halten Sie den Besitz der Objektsperre. Zu diesem Zeitpunkt wird die Sperre von A gehalten, dann werden die B- und C-Threads blockiert und geben einen Platz ein, um auf die Freigabe der Sperre zu warten Sperrbecken.
warten aufs Essen
benachrichtigen
Ein Thread im Wartepool wird zufällig ausgewählt, um in den Sperrpool einzutreten und um die Möglichkeit zu konkurrieren, die Sperre zu erhalten.
notifyAll
notifyAll führt dazu, dass alle Threads im Wartepool in den Sperrpool gelangen und um die Möglichkeit konkurrieren, die Sperre zu erhalten.
Ertragszuordnungsfunktion
Wenn die Funktion Thread.yield() aufgerufen wird, gibt sie dem Thread-Scheduler einen Hinweis, der anzeigt, dass der aktuelle Thread bereit ist, die CPU aufzugeben, aber der Thread-Scheduler ignoriert diesen Hinweis möglicherweise.
Thread-Status
neu Neu
Thread-Status, der nach der Erstellung noch nicht gestartet wurde
Eingabemethode: nach Neu, vor Start
runnable kann laufen
Läuft/Bereit
Wird ausgeführt: Der Status des Threads, wenn der Thread-Scheduler einen Thread aus dem ausführbaren Pool als aktuellen Thread auswählt.
Der Status eines Threads, wenn der Thread-Scheduler einen Thread aus dem ausführbaren Pool als aktuellen Thread auswählt. Dies ist auch die einzige Möglichkeit für einen Thread, in den laufenden Zustand zu gelangen.
Der Status eines Threads, wenn der Thread-Scheduler einen Thread aus dem ausführbaren Pool als aktuellen Thread auswählt.
1. Der Bereitschaftsstatus bedeutet nur, dass Sie für die Ausführung qualifiziert sind. Wenn der Planer Sie nicht auswählt, befinden Sie sich immer im Bereitschaftsstatus. 2. Rufen Sie die start()-Methode des Threads auf und der Thread wechselt in den Bereitschaftszustand. 3. Die Sleep()-Methode des aktuellen Threads endet und die Join()-Methode anderer Threads endet. Nachdem die Benutzereingabe abgeschlossen ist, erhält ein Thread die Objektsperre und diese Threads wechseln ebenfalls in den Bereitschaftszustand. 4. Wenn die Zeitscheibe des aktuellen Threads aufgebraucht ist, wird die yield()-Methode des aktuellen Threads aufgerufen und der aktuelle Thread wechselt in den Bereitschaftszustand. 5. Wenn die Thread-Zeitscheibe aufgebraucht ist, rufen Sie die yeid()-Methode des aktuellen Threads auf, und der aktuelle Thread wechselt in den Bereitschaftszustand. 6. Nachdem der Thread im Sperrpool die Objektsperre erhalten hat, wechselt er in den Bereitschaftszustand.
blockiert blockiert
Warten auf den Erwerb einer exklusiven Sperre
Warten, unendliches Warten
Wird keine CPU-Ausführungszeit zugewiesen und muss explizit aktiviert werden
Zeitgesteuertes Warten. Zeitgesteuertes Warten
Das System wird nach einer gewissen Zeit automatisch aktiviert.
beendet
Beendeter Status, die Ausführung des Threads ist abgeschlossen
1. Wenn die Ausführung der Ausführungsmethode eines Threads endet oder die Ausführung der Hauptfunktion abgeschlossen ist, gehen wir davon aus, dass der Thread beendet ist. Dieses Thread-Objekt ist möglicherweise aktiv, aber es ist kein separat ausgeführter Thread mehr. Sobald ein Thread beendet ist, kann er nicht wiederbelebt werden. 2. Der Aufruf der Startmethode für einen beendeten Thread löst eine java.lang.IllegalThreadStateExecption-Ausnahme aus.
Multithreading
Die Bedeutung von Multithreading
Holen Sie das Beste aus Ihrem Prozessor heraus
So erstellen Sie einen Thread
Thread-Klasse erben
Implementieren Sie die Runnable-Schnittstelle
Vermeiden Sie die Einschränkungen der Mehrfachvererbung
Kann das Konzept des Teilens besser widerspiegeln
Implementieren Sie die Callable-Schnittstelle
Starten Sie Multithreading über den Thread-Pool
Was ist der Unterschied zwischen runnable und callable?
Die Ausführungsmethode der ausführbaren Schnittstelle hat keinen Rückgabewert
Kann nur Laufzeitausnahmen auslösen und diese nicht abfangen
Die aufrufbare Schnittstellenaufrufmethode hat einen Rückgabewert und unterstützt Generika
Ermöglicht das Auslösen von Ausnahmen und das Abrufen von Ausnahmeinformationen
Wie man mit Informationen interagiert
void notify()
Weckt nach dem Zufallsprinzip einen einzelnen Thread auf, der auf den Wartepool (Monitor) dieses Objekts wartet und in den Sperrpool eintritt
void notifyAll()
Wecken Sie alle Threads auf, die auf den Wartepool (Monitor) dieses Objekts warten, und betreten Sie den Sperrpool
void warte()
Bewirkt, dass der aktuelle Thread wartet, bis andere Threads die Methode notify() oder notifyAll() dieses Objekts aufrufen
Leeres Warten (lange Zeitüberschreitung)
Gleich wie oben oder überschreitet die angegebene Zeitspanne
void wait(long timeout, int nanos)
Dasselbe wie oben oder ein anderer Thread unterbricht den aktuellen Thread
JMM
Atomizität
Das Merkmal, dass ein oder mehrere Vorgänge nicht unterbrochen werden, während die CPU ausgeführt wird
Atomare Klassen, beginnend mit Atomic
CAS-Prinzip
AtomicLong >> LongAdder
AtomicLong basiert auf dem CAS-Spin-Update
LongAdder teilt den Wert in mehrere Zellen auf
Sichtweite
Änderungen an gemeinsam genutzten Variablen durch einen Thread können von einem anderen Thread sofort gesehen werden.
flüchtig
Ordentlichkeit
Programmausführung in Ordnung Codiert Nacheinander ausführen
Geschieht vor der Regel
Regeln für die Programmreihenfolge
Innerhalb eines Threads erfolgen gemäß der Programmkontrollflusssequenz die vorne geschriebenen Operationen vor den hinten geschriebenen Operationen.
Sperrregeln überwachen
Ein Entsperrvorgang erfolgt vor einem nachfolgenden Sperrvorgang für dieselbe Sperre.
Regeln für flüchtige Variablen
Ein Schreibvorgang auf eine flüchtige Variable erfolgt vor einem nachfolgenden Lesevorgang auf diese Variable.
Thread-Startregeln
Die start()-Methode des Thread-Objekts wird bei jeder Aktion dieses Threads zuerst ausgeführt.
Thread-Beendigungsregeln
Alle Vorgänge in einem Thread werden zuerst ausgeführt, wenn die Beendigung dieses Threads erkannt wird
Regeln für Thread-Unterbrechungen
Der Aufruf der Interrupt()-Methode des Threads erfolgt erst, nachdem der Code des unterbrochenen Threads das Auftreten des Interrupt-Ereignisses erkennt.
Regeln für die Objektfinalisierung
Der Abschluss der Initialisierung eines Objekts (das Ende der Konstruktorausführung) erfolgt zuerst zu Beginn seiner finalize()-Methode.
ThreadLocal-Thread-Lokalspeicher
Jeder Thread kann auf den Wert in seinem eigenen internen ThreadLocalMap-Objekt zugreifen
Beispiel: Jedem Thread wird eine JDBC-Verbindung Connection zugewiesen
Thread-Pool
Verwenden Sie Executors, um verschiedene Thread-Pools zu erstellen, um den Anforderungen verschiedener Szenarien gerecht zu werden
newFixedThreadPool(int nThreads)
Thread-Pool mit der angegebenen Anzahl von Arbeitsthreads
newCachedThreadPool(
Thread-Pool zur Bewältigung großer Mengen kurzlebiger Arbeitsaufgaben
Versucht, Threads zwischenzuspeichern und wiederzuverwenden. Wenn keine zwischengespeicherten Threads verfügbar sind, werden neue Arbeitsthreads erstellt
Wenn ein Thread länger als den Schwellenwert inaktiv ist, wird er beendet und aus dem Cache verschoben.
Wenn das System längere Zeit im Leerlauf ist, werden keine Ressourcen verbraucht.
newSingleThreadPool()
Erstellen Sie einen eindeutigen Arbeitsthread, um die Aufgabe auszuführen. Wenn der Thread abnormal endet, wird er durch einen anderen Thread ersetzt.
newSingleThreadScheduledExecutor() und newScheduledThreadPool(int corePoolSize)
Timing oder periodische Arbeitsplanung, der Unterschied liegt in einem einzelnen Arbeitsthread oder mehreren Threads
newWorkStealingPool()
ForkJoinPool wird intern erstellt und verwendet den Work-Stealing-Algorithmus, um Aufgaben parallel zu verarbeiten. Die Verarbeitung kann nicht garantiert werden.
Fork/Jion-Framework
Paralleles Task-Framework, bereitgestellt von Java7
Ein Framework, das eine große Aufgabe in mehrere kleine Aufgaben unterteilt, diese parallel ausführt und schließlich die Ergebnisse jeder kleinen Aufgabe zusammenfasst, um die Ergebnisse der großen Aufgabe zu erhalten
arbeitsraubender Algorithmus
Ein Thread stiehlt Aufgaben aus anderen Warteschlangen zur Ausführung
Fork teilt Aufgaben in verschiedene Warteschlangen auf und erstellt für jede auszuführende Warteschlange separate Threads.
Wenn ein Thread die Ausführung seiner eigenen Aufgabenwarteschlange abschließt, stiehlt er die Aufgaben in der Warteschlange anderer Threads zur Ausführung.
Die Warteschlange übernimmt eine doppelendige Warteschlange. Der gestohlene Thread übernimmt die Aufgabe immer vom Kopf der doppelendigen Warteschlange und der gestohlene Thread übernimmt immer die Aufgabe vom Ende der doppelendigen Warteschlange.
Executor-Framework
Es handelt sich um ein Framework, das die Aufgabeübermittlung und die Aufgabenausführung trennt.
Die drei Executor-Schnittstellen von J.U.C
Testamentsvollstrecker
Eine einfache Schnittstelle zum Ausführen neuer Aufgaben mit Details zur Aufgabenübermittlung und Aufgabenausführung
ExecutorService
Es verfügt über Methoden zum Verwalten von Executoren und Task-Deklarationszyklen, und der Task-Übermittlungsmechanismus ist vollständiger.
ScheduledExecutorService
Unterstützen Sie zukünftige und regelmäßig ausgeführte Aufgaben
Konstruktor von ThreadPoolExecutor
corePoolSize
Anzahl der Kernthreads
maximalePoolSize
Die maximale Anzahl von Threads, die erstellt werden können, wenn nicht genügend Threads vorhanden sind
Arbeitswarteschlange
Warteschlange für Aufgaben
keepAliveTime
Zusätzlich zur Anzahl der Kernthreads auch die Überlebenszeit anderer Threads im Leerlauf
Die Reihenfolge der Präemption ist nicht unbedingt festgelegt, sie hängt vom Glück ab.
ThreadFactory
Neuen Thread erstellen
Der Standardwert ist Executors.defaultThreadFactory
Handler
Sättigungsstrategie
AbortPolicy
Lösen Sie direkt eine Ausnahme aus. Dies ist die Standardstrategie
CallerRunsPolicy
Verwenden Sie den Thread des Aufrufers, um die Aufgabe auszuführen
DiscardOldestPolicy
Verwerfen Sie die oberste Aufgabe in der Warteschlange
DiscardPolicy
Verwerfen Sie die Aufgabe direkt
Implementieren Sie einen benutzerdefinierten Handler der RejectedExecutionHandler-Schnittstelle, um Ihre eigenen Geschäftsanforderungen zu erfüllen
Beurteilung, nachdem eine neue Aufgabe zur Ausführung vorgelegt wurde
Wenn weniger Threads ausgeführt werden als corePoolSize, werden neue Threads zur Bearbeitung von Aufgaben erstellt, auch wenn andere Threads im Thread-Pool inaktiv sind.
Wenn die Anzahl der im Thread-Pool erhaltenen Threads größer oder gleich corePoolSize und kleiner als MaximumPoolSize ist, wird nur dann ein neuer Thread zur Verarbeitung erstellt, wenn die workQueue voll ist. Andernfalls wird die workQueue gefüllt.
Wenn corePoolSize und MaximumPoolSize gleich sind, ist die Größe des erstellten Thread-Pools festgelegt. Wenn zu diesem Zeitpunkt eine neue Aufgabe übermittelt wird und die WorkQueue nicht voll ist, wird die Aufgabe in die WorkQueue gestellt und wartet darauf, dass ein inaktiver Thread die Aufgabenverarbeitung aus der WorkQueue extrahiert.
Wenn die Anzahl der laufenden Threads größer oder gleich maximunPoolSize ist und die WorkQueue voll ist Die Bearbeitung der Aufgabe erfolgt durch die vom Bearbeiter formulierte Strategie
Thread-Pool-Status
LÄUFT
Kann neue Aufgaben annehmen und Aufgaben in workQueue bearbeiten
SCHUHE
Es werden keine neuen Aufgaben mehr angenommen, bestehende Aufgaben können jedoch bearbeitet werden
STOPPEN
Es werden keine neuen Aufgaben mehr angenommen und keine bestehenden Aufgaben ausgegeben.
AUFRÄUMEN
Alle Aufgaben wurden beendet
BEENDET
beendet (), geben Sie diesen Status ein, nachdem die Methode ausgeführt wurde
Lebenszyklus des Worker-Threads
Warum Thread-Pool verwenden?
Reduzieren Sie den Ressourcenverbrauch
Verbessern Sie die Thread-Verwaltbarkeit
So wählen Sie die Größe des Thread-Pools aus
CPU-intensiv
Anzahl der Threads = Stellen Sie entsprechend der Anzahl der Kerne oder der Anzahl der Kerne 1 ein
I/O-intensiv
Anzahl der Threads = Anzahl der CPU-Kerne * (1 durchschnittliche Wartezeit / durchschnittliche Arbeitszeit)
Thread-Executor-Executor
Zustand
Executor-Framework
Testamentsvollstrecker
newFixedThreadPool
Ein Thread-Pool fester Länge erstellt jedes Mal einen Thread, wenn eine Aufgabe übermittelt wird, bis die maximale Anzahl von Thread-Pools erreicht ist.
newScheduledThreadPool
Thread-Pool mit fester Länge, der regelmäßige Aufgaben ausführen kann
Möglichkeit, die Ausführung von Befehlen nach einer bestimmten Verzögerung oder in regelmäßigen Abständen nach Bedarf zu planen
newCachedThreadPool
Cachebarer Thread-Pool: Wenn die Kapazität des Thread-Pools die Anzahl der Aufgaben überschreitet, werden inaktive Threads automatisch recycelt
Neue Threads können automatisch hinzugefügt werden, wenn die Aufgaben zunehmen, und die Kapazität des Thread-Pools ist nicht begrenzt.
newSingleThreadExecutor
Wenn in einem Single-Threaded-Thread-Pool der Thread abnormal endet, wird ein neuer Thread erstellt, um sicherzustellen, dass Aufgaben in der Reihenfolge ausgeführt werden, in der sie übermittelt werden.
newSingleThreadScheduledExecutor
Ein Single-Threaded-Thread-Pool, der regelmäßige Aufgaben ausführen kann
newWorkStealingPool
Aufgaben stehlen den Thread-Pool und garantieren nicht die Ausführungsreihenfolge, was für Aufgaben mit großen Unterschieden im Zeitverbrauch geeignet ist.
Die standardmäßig erstellte Parallelebene ist die Anzahl der CPU-Kerne. Wenn der Hauptthread endet, wird er sofort angehalten, selbst wenn sich Aufgaben im Thread-Pool befinden.
ForkJoinTask
Lösen Sie das Problem des Ungleichgewichts der CPU-Last
Holen Sie mithilfe des Divide-and-Conquer-Prinzips das Beste aus Multi-Core-CPUs heraus
Aufgabensegmentierung
Ergebnisse zusammengeführt
ThreadPoolExecutor Thread-Pool-Basisklasse
corePoolSize
Anzahl der Kernthreads
maximalePoolSize
Maximale Anzahl von Threads
keepAliveTime
Überlebenszeit des Threads im Leerlauf
Einheit
Überlebenszeiteinheit
Arbeitswarteschlange
Aufgabenblockierungswarteschlange
ThreadFactory
Factory erforderlich, wenn ein neuer Thread erstellt wird
Handler
Richtlinie verweigern
AbortPolicy
Wenn die Warteschlange voll ist, werden Aufgaben standardmäßig verworfen und eine Ausnahme ausgelöst.
DiscardPolicy
Wenn die Warteschlange voll ist, wird die Aufgabe verworfen, ohne dass eine Ausnahme ausgelöst wird.
DiscardOldestPolicy
Löschen Sie die früheste Aufgabe, die in die Warteschlange gelangt, und versuchen Sie dann erneut, der Warteschlange beizutreten
CallerRunPolicy
Wenn das Hinzufügen zum Thread-Pool fehlschlägt, führt der Hauptthread die Aufgabe selbst aus.
Vier Ablehnungsstrategien
SecheduleThreadPoolExecutor
Wird hauptsächlich verwendet, um Aufgaben nach einer bestimmten Verzögerung auszuführen oder Aufgaben, die regelmäßig ausgeführt werden
ExecutorCompletionService
Verwaltet intern eine Blockierungswarteschlange abgeschlossener Aufgaben
einreichen()
Senden Sie die Aufgabe und sie wird schließlich an den internen Ausführenden delegiert, um die Aufgabe auszuführen.
Parameter (Ausführbar) oder (Ausführbar und Ergebnis T) oder (Aufrufbar)
Rückgabewert Zukunft Beim Aufruf der get-Methode können Sie Ausnahmen abfangen und behandeln
nehmen()
Wenn sich in der Blockierungswarteschlange bereits eine abgeschlossene Aufgabe befindet, geben Sie das Aufgabenergebnis zurück. Andernfalls blockieren Sie und warten Sie, bis die Aufgabe abgeschlossen ist.
Umfrage()
Gibt zurück, wenn in der Warteschlange eine Aufgabe vorhanden ist, die abgeschlossen wurde, andernfalls wird null zurückgegeben
pull(long,TimeUnit)
Wenn sich eine abgeschlossene Aufgabe in der Warteschlange befindet, wird das Ergebnis der Aufgabe zurückgegeben, andernfalls wird die angegebene Zeit abgewartet. Wenn immer noch keine Aufgabe abgeschlossen ist, geben Sie null zurück
Fork/Join-Framework
ForkJoinPool
Es ist eine Ergänzung zu ExecutorService, kein Ersatz. Es eignet sich besonders für Divide-and-Conquer- und rekursive Berechnungsalgorithmen.
RekursiveTask
Aufgaben, die Ergebnisse liefern
Rekursive Aktion
Berechnungen, die keine Ergebnisse liefern
Thread-Framework
JUC
【java.util.concurrent Entwicklungspaket】
Kernklasse
TimeUnit-Toolklasse
ThreadFactory-Thread-Factory-Klasse
CAS
Ist die Basis des Pakets java.util.concurrent.autimic
atomic (atomare Variablenklasse)
Die Atomklasse basiert auf CAS und Volatile CAS ist eine häufig verwendete Implementierung nicht blockierender Algorithmen, die eine bessere Leistung aufweist.
Gewöhnliche Atomklasse
AtomicBoolean
AtomicLong
AtomicInteger
AtomicIntegerArray
AtomicLongArray
Referenzatomklasse
AtomicReference
AtomicReferenceArray
Lösen Sie ABA
AtomicMarkableReference
AtomicStampedReference
Erweiterte Atomklasse
LongAkkumulator
Der Konstruktor eines benutzerdefinierten Long-Akkumulators akzeptiert eine binokulare Bedienerschnittstelle und gibt einen berechneten Wert zurück, der auf den beiden Eingabeparametern basiert. Der andere Parameter ist der Anfangswert des Akkumulators.
Doppelakkumulator
Benutzerdefinierter Doppeltyp-Akkumulator, genau wie LongAccumulator
LongAdder
Atomare Operationen vom Typ „Long“ sind hinsichtlich der Parallelität besser als LongAtomic und sollten zuerst verwendet werden. LongAdder ist ein Sonderfall von LongAccumulator
DoubleAdder
Atomare Operationen vom Typ Double, genau wie LongAdder
Kernkomponenten
Verriegelungsmechanismus
Sperren
ReadWriteLock
AQS (Queue Synchronizer)
Es ist das Paket java.util.concurrent.locks und die Basis einiger gängiger Klassen wie Semophore und ReentratLock.
AbstractOwnableSynchronizer (exklusive Sperre)
Um blockierende Sperren und Korrelationen zu implementieren, die auf First-In-First-Out-FIFO-Warteschlangen basieren Synchronisierer <Semaphoren, Ereignisse usw.> bieten einen Rahmen
AbstractQueuedLongSynchronizer (64-Bit-Synchronizer)
ReentrantLock-Mutex-Sperre
ReadWriteLock Lese-/Schreibsperre
Zustandskontrollwarteschlange
LockSupport-Blockierungsgrundelement
Semaphor-Semaphor
CountDownLatch-Latch
CyclicBarrier-Zaun
Tauscherschalter
CompletableFuture-Thread-Rückruf
Gleichzeitige Sammlungen
gleichzeitige Warteschlange
ArrayBlockingQueue
Begrenzte Blockierungswarteschlange mit Array-Struktur
LinkedBlockingDueue
Eine blockierende Warteschlange mit einer verknüpften Listenstruktur. Wenn die Größe nicht angegeben ist, ist sie unbegrenzt.
LinkedBlockingQueue
Eine bidirektionale Blockierungswarteschlange mit einer verknüpften Listenstruktur. Wenn die Größe nicht angegeben ist, ist sie unbegrenzt.
PriorityBlockingQueue
Prioritätsbegrenzte Blockierungswarteschlange der Array-Struktur, Heap-Sortierung
Verzögerungswarteschlange
verzögerte Blockierungswarteschlange
PriorityQueue wird intern verwendet, um Verzögerungen zu implementieren
SynchronousQueue
Die synchrone Blockierungswarteschlange hat keine Kapazität und der Put-Vorgang wird immer blockiert. Die Ausführung kann erst fortgesetzt werden, wenn eine Take-Operation erfolgt.
LinkedTransferQueue
Kombination von SychronousQueue und LinkedBlockingQueue Unbegrenzte Blockierungswarteschlange
Die Blockierungswarteschlange BlockQueue bietet blockierende Einreihungs- und Entnahmeoperationen. Wird hauptsächlich im Produzenten- und Verbrauchermodus verwendet Im Fall von Multithreading Der Produzent fügt Elemente am Ende der Warteschlange hinzu Der Verbraucher verbraucht Elemente an der Spitze der Warteschlange Um den Zweck zu erreichen, die Generierung und den Verbrauch von Aufgaben zu isolieren
ConcurrentLinkedDeque
Threadsichere Warteschlange mit verknüpfter Listenstruktur
ConcurrentLinkedQueue
Threadsichere bidirektionale Warteschlange mit verknüpfter Listenstruktur
nicht blockierende Warteschlange
gleichzeitige Sammlung
ConcurrentHashMap
Threadsichere Karte, Array, verknüpfte Liste/rot-schwarze Baumstruktur
ConcurrentHashMap.newKeySet()
Threadsichere Vorgänge
ConcurrentSkipListMap
Thread-Sicherheit, Karte nach Schlüssel sortiert, Listenstruktur überspringen
ConcurrentSkipListSet
Thread-Sicherheit, geordneter Satz, Listenstruktur überspringen
CopyOnWriteArrayList
Schreiben Sie, um die Liste zu kopieren, das Szenario, mehr zu lesen und weniger zu schreiben
CopyOnWriteArraySet
Set beim Schreiben kopiert, Szenario, bei dem man mehr liest und weniger schreibt
Tools für Parallelitätstools
CountDownLatch
Durch das Sperren kann ein Thread warten, bis andere Threads ihre Arbeit abgeschlossen haben, bevor er mit der Ausführung fortfährt.
CyclicBarrier
Mithilfe von Zäunen können mehrere Threads darauf warten, dass eine Bedingung erfüllt wird, bevor sie mit der Ausführung fortfahren.
Semaphor
Semaphore, ein Zählsemaphor, der von dem Thread, der ihn erhalten hat, freigegeben werden muss, wird häufig verwendet, um die Anzahl der Threads zu begrenzen, die auf bestimmte Ressourcen zugreifen können.
Austauscher
Exchanger, eine gekapselte Toolklasse, die zum Datenaustausch zwischen zwei Arbeitsthreads verwendet wird
andere
Zeiteinheit
ThreadLocalRandom
Verbesserte Leistung bei der Generierung von Zufallszahlen unter Multithreading, um Konkurrenz um denselben Startwert zu vermeiden
Thread-Sicherheit und Datensynchronisation
CountDownLatch
Lassen Sie einen oder mehrere Threads warten
Semaphor
Hilfsklasse für die Thread-Synchronisierung, die die Anzahl der aktuell auf sich selbst zugreifenden Threads verwalten und für die Synchronisierung sorgen kann
CyclicBarrier
Implementieren Sie eine Gruppe von Threads, die aufeinander warten, und führen Sie dann nachfolgende Vorgänge aus, wenn alle Threads einen bestimmten Barrierepunkt erreichen
flüchtig
Wirkung
Kann nur auf Variablen reagieren
Zeigt an, dass die Variable im CPU-Register undefiniert ist und aus dem Hauptspeicher gelesen werden muss.
Merkmale
Sorgen Sie für Sichtbarkeit
Keine Garantie für Atomizität
Deaktivieren Sie die Neuanordnung von Befehlen
Thread-Blockierung
Sperren
Level-Klassifizierung
kein Schloss
Vorspannungssperre
leichtes Schloss
Schweres Schloss
Ursache
Kreuzschloss
Nicht genug Speicherplatz
Datenbanksperre
Frage-und-Antwort-Datenaustausch
Endlosschleife
Sackgasse
Vier notwendige Bedingungen
Gegenseitig ausschließende Bedingungen
Eine bestimmte Ressource wird für einen bestimmten Zeitraum nur von einem Thread belegt, und andere Threads, die die Ressource anfordern, können nur warten.
keine Entzugsbedingungen
Die von einem Thread erhaltenen Ressourcen können nicht gewaltsam von anderen Threads weggenommen werden, bevor sie vollständig verwendet werden.
Sie kann nur aktiv von dem Thread freigegeben werden, der die Ressource erhalten hat.
Bedingungen anfordern und zurückhalten
Der Thread enthält bereits mindestens eine Ressource, stellt jedoch eine neue Ressourcenanforderung
Die Ressource ist bereits von anderen Threads belegt und der anfordernde Thread ist zu diesem Zeitpunkt blockiert.
Behalten Sie die erworbenen Ressourcen
Schleifenwartebedingung
Es gibt eine kreisförmige Wartekette für Thread-Ressourcen
Die von jedem Thread erhaltenen Ressourcen werden gleichzeitig vom nächsten Thread in der Kette angefordert.
Möglichkeiten, Deadlocks zu vermeiden
Sperrreihenfolge
Threads werden in einer bestimmten Reihenfolge gesperrt
Sperrfrist
Fügen Sie ein bestimmtes Zeitlimit hinzu, wenn der Thread versucht, die Sperre zu erhalten
Bei Überschreitung des Zeitlimits wird der Antrag auf Sperre aufgegeben und die Sperre aufgehoben.
Deadlock-Erkennung
Diagnose
jstack
jvisualvm
Spin-Lock
Der Thread prüft wiederholt, ob die Sperrvariable verfügbar ist
Die TicketLock-Sperre löst hauptsächlich das Problem der Fairness
Die CLH-Sperre ist eine skalierbare, leistungsstarke und faire Spin-Sperre, die auf einer verknüpften Liste basiert
MCSLock durchläuft die Knoten lokaler Variablen
CAS-Implementierung
CAS hat 3 Operanden, den Speicherwert V, den alten erwarteten Wert A und den neuen zu ändernden Wert B
Nur wenn der erwartete Wert A und der Speicherwert V gleich sind, ändern Sie den Speicherwert V in B, andernfalls unternehmen Sie nichts
Ausführliche Grundsätze
CAS-Ticket
Sperroptimierung
JVM-Optimierung
Die Optimierungsrichtung besteht darin, die Thread-Blockierung zu reduzieren
In Java SE 1.6 haben Sperren insgesamt 4 Zustände
Kein Sperrzustand, teilweiser Sperrzustand, Leichter Sperrstatus, schwerer Sperrstatus
Mit der Wettbewerbssituation wird sich der Status sukzessive verschärfen.
Die Sperre kann nach dem Upgrade nicht herabgestuft werden.
Sperrenbeseitigung
Der JIT-Compiler eliminiert Sperren, die durch Code synchronisiert werden, der nicht synchronisiert werden muss.
Fluchtanalyse
Es geht darum, zu beobachten, ob eine bestimmte Variable vorhanden ist Wird aus einem bestimmten Bereich entkommen
Schlossaufrauung
Wenn eine Reihe aufeinanderfolgender Vorgänge dasselbe Objekt wiederholt sperren und entsperren
Die JVM erweitert (vergröbert) den Umfang der Sperrensynchronisierung über die gesamte Operationssequenz hinaus.
Programmoptimierung
Reduzieren Sie die Haltezeit der Sperre
Reduzieren Sie die Granularität der Sperre
Verwenden Sie Lese-/Schreibsperren, um exklusive Sperren zu ersetzen
Sperrentrennung
kein Schloss
CAS
synchronisierte Synchronisationssperre
Wirkung
Ändern Sie einen Codeblock
Synchronisierter Anweisungsblock
Sein Umfang ist der in geschweifte Klammern eingeschlossene Code {}
Das Aktionsobjekt ist das Objekt, das diesen Codeblock aufruft.
Ändern Sie eine Methode
Ändern Sie eine statische Methode
Ändern Sie eine Klasse
Einstufung
Methodensperre
Objektsperre synchronisiert (dies)
Klassensperre synchronisiert (Demo.Class)
Merkmale
Sorgen Sie für Ordnung, Atomizität und Sichtbarkeit zwischen den Threads
Thread-Blockierung
Prinzip
Bytecode plus Identifikation
Der Synchronisationscodeblock erhält das Ausführungsrecht des Threads über die Anweisungen „monitorenter“ und „monitorexit“.
Die Synchronisationsmethode steuert die Ausführungsrechte des Threads durch Hinzufügen des Flags ACC_SYNCHRONIZED.
Sperren
Code
lock () erhält die Sperre auf blockierende Weise und der Blockierungsstatus ignoriert die Interrupt-Methode
lockInterruptably() ignoriert im Gegensatz zu lock() keine Interrupt-Methoden
tryLock() erhält die Sperre auf nicht blockierende Weise und kann Zeitparameter hinzufügen
Sperren und synchronisieren
Ähnlichkeit: Die Sperre kann alle durch die Synchronisierung implementierten Funktionen ausführen
Unterschied: Lock hat eine präzisere Thread-Semantik und eine bessere Leistung als synchronisiert
Das Sperren von Schlössern wird durch Code implementiert
Der Programmierer gibt es manuell frei und muss es in der final-Klausel freigeben
synchronisiert wird auf JVM-Ebene implementiert
automatische Entriegelungssperre
Der Umfang der Sperre ist begrenzt und der Umfang des Blocks begrenzt
synchronisiert kann Blöcke, Objekte und Klassen sperren
ReetrantLock
Wiedereintretende Sperre, Mutex-Sperre
ReeTrantReadWriteLock
Wiedereintretende Lese-/Schreibsperre, gemeinsame Lese-/Lesesperre, Lese-/Schreibmutex, Schreib-/Schreibmutex
StampedLock
Lese-/Schreibsperre mit Zeitstempel, nicht wiedereintrittsfähig
ReadWriteLock Lese-/Schreibsperre
Eine Implementierung von ReentrantReadWriteLock
Der Unterschied zwischen synchronisiert und ReentrantLock
abwarten und benachrichtigen
Warten
1) Heben Sie die aktuelle Objektsperre auf
2) Lassen Sie den aktuellen Thread in die Blockierungswarteschlange eintreten
benachrichtigen
einen Thread aufwecken
Praxis für Szenarien mit hoher Parallelität
Mehrstufige Cache-Architektur von Redis und JVM
Reduzierung von Spitzenlasten im Nachrichten-Middleware-Verkehr und asynchrone Verarbeitung
Umsetzung der Strombegrenzungsstrategie
Nginx-Strombegrenzung
Schalter
gleitendes Zeitfenster
Token-Bucket, Leaky-Bucket-Algorithmus
Sentinel/Hystrix-Strombegrenzung
Implementierung eines Service-Peak-Downgrades
Systemsicherheits-Anti-Brush-Strategie
Leistungsoptimierung
JVM GC-Tuning
GC
Vermeiden Sie die Verwendung der Objektfinalisierungsmethode finalize()
Tomcat-Tuning
Nginx-Tuning
Java-Algorithmus
binäre Suche
public static int biSearch(int []array,int a){ int lo=0; int hi=array.length-1; int Mitte; while(lo<=hi){ mid=(lo hi)/2;//mittlere Position if(array[mid]==a){ Rückkehr Mitte 1; }else if(array[mid]<a){ //Suche nach rechts lo=Mitte 1; }else{ //Suche links hallo=Mitte-1; } } return -1; }
Blasensortierungsalgorithmus
public static void bubbleSort1(int [] a, int n){ int i, j; for(i=0; i<n; i ){//Gibt n Sortiervorgänge an. for(j=1; j<n-i; j ){ if(a[j-1] > a[j]){//Wenn die vorherige Zahl größer als die folgende Zahl ist, tauschen Sie sie aus //A[j-1] und a[j] austauschen int temp; temp = a[j-1]; a[j-1] = a[j]; a[j]=temp; } } } }
Sortieralgorithmus für Einfügungen
public void sort(int arr[]) { for(int i =1; i<arr.length;i ) { //Nummer eingefügt int insertVal = arr[i]; //Die eingefügte Position (zum Vergleich mit der vorherigen Zahl vorbereiten) int index = i-1; //Wenn die eingefügte Zahl kleiner ist als die eingefügte Zahl while(index>=0&&insertVal<arr[index]) { //Bewegt arr[index] nach hinten arr[index 1]=arr[index]; //Index vorwärts bewegen lassen Index--; } //Setzen Sie die eingefügte Zahl an die entsprechende Position arr[index 1]=insertVal; } }
Scannen Sie in der sortierten Reihenfolge von hinten nach vorne, um die entsprechende Position zu finden und einzufügen.
Die Einfügungssortierung ist der von Spielkarten sehr ähnlich.
Quicksort-Algorithmus
Das Prinzip der Schnellsortierung: Wählen Sie einen Schlüsselwert als Basiswert aus. Werte, die kleiner als die Grundlinie sind, befinden sich alle in der linken Reihenfolge (im Allgemeinen ungeordnet).
Diejenigen, die größer als der Basiswert sind, befinden sich auf der rechten Seite (im Allgemeinen ungeordnet). Im Allgemeinen wird das erste Element der Sequenz ausgewählt.
Eine Schleife: Vergleichen Sie von hinten nach vorne, vergleichen Sie den Basiswert mit dem letzten Wert, tauschen Sie die Positionen, wenn er kleiner als der Basiswert ist, wenn nicht, fahren Sie mit dem Vergleich mit dem nächsten fort, tauschen Sie nicht, bis der erste Wert kleiner ist als Der Basiswert ist gefunden. Nachdem dieser Wert gefunden wurde, beginnt der Vergleich von vorne nach hinten. Wenn ein Wert größer als der Basiswert ist, wird die Position getauscht. Wenn der Wert nicht mit dem nächsten verglichen wird, wird die Position erst dann getauscht, wenn der erste Wert größer ist als der Basiswert gefunden wird.
Bis der Vergleichsindex von vorne nach hinten > der Index von hinten nach vorne ist, endet die erste Schleife. Zu diesem Zeitpunkt sind für den Basiswert die linke und rechte Seite in Ordnung.
public void sort(int[] a,int low,int high){ int start = niedrig; int end = hoch; int key = a[low]; while(end>start){ //Von hinten nach vorne vergleichen while(end>start&&a[end]>=key) //Wenn es keinen kleineren Wert als den Schlüsselwert gibt, vergleichen Sie den nächsten, bis es eine Swap-Position gibt, die kleiner als der Schlüsselwert ist, und vergleichen Sie dann von vorne nach hinten. Ende--; if(a[end]<=key){ int temp = a[end]; a[Ende] = a[Start]; a[start] = temp; } //Von vorne nach hinten vergleichen while(end>start&&a[start]<=key) //Wenn es keine gibt, die größer als der Schlüsselwert ist, vergleichen Sie die nächste, bis es eine Swap-Position gibt, die größer als der Schlüsselwert ist Start ; if(a[start]>=key){ int temp = a[start]; a[Anfang] = a[Ende]; a[end] = temp; } //An diesem Punkt endet der erste Schleifenvergleich und die Position des Schlüsselwerts wurde bestimmt. Die Werte auf der linken Seite sind alle kleiner als der Schlüsselwert und die Werte auf der rechten Seite Die Werte sind alle größer als der Schlüsselwert, aber die Reihenfolge auf beiden Seiten kann unterschiedlich sein. Führen Sie den folgenden rekursiven Aufruf durch. } //Rekursion if(start>low) sort(a,low,start-1);//Linke Sequenz. Erste Indexposition zum Schlüsselwertindex -1 if(end<high) sort(a,end 1,high);//rechte Sequenz. Vom Schlüsselwertindex 1 bis zuletzt } }
Hill-Sortieralgorithmus
Idee: Teilen Sie zunächst die gesamte Sequenz der zu sortierenden Datensätze in mehrere Teilsequenzen für die Direkteinfügungssortierung auf. Wenn die Datensätze in der gesamten Sequenz „grundsätzlich in Ordnung“ sind, führen Sie dann eine Direkteinfügungssortierung für alle Datensätze durch.
1. Betriebsmethode: Wählen Sie eine inkrementelle Sequenz t1, t2, ..., tk aus, wobei ti>t, tk=1;
2. Sortieren Sie die Sequenz k-mal entsprechend der Anzahl der inkrementellen Sequenzen k;
Bei jedem Sortierdurchlauf wird die zu sortierende Spalte entsprechend dem entsprechenden Inkrement ti in mehrere Teilsequenzen der Länge m unterteilt, und für jede Untertabelle wird eine direkte Einfügungssortierung durchgeführt. Nur wenn der Inkrementfaktor 1 ist, wird die gesamte Sequenz als Tabelle verarbeitet und die Länge der Tabelle entspricht der Länge der gesamten Sequenz.
private void shellSort(int[] a) { int dk = a.length/2; while( dk >= 1 ){ ShellInsertSort(a, dk); dk = dk/2; } } private void ShellInsertSort(int[] a, int dk) { // Ähnlich wie bei der Einfügungssortierung, außer dass das Inkrement der Einfügungssortierung 1 ist. Hier ist das Inkrement dk. Ersetzen Sie einfach 1 durch dk. for(int i=dk;i<a.length;i){ if(a[i]<a[i-dk]){ int j; int x=a[i];//x ist das einzufügende Element a[i]=a[i-dk]; for(j=i-dk; j>=0 && x<a[j];j=j-dk){ // Durch die Schleife ein Bit nach dem anderen zurückgehen, um die einzufügende Position zu finden. a[j dk]=a[j]; } a[j dk]=x;//Einfügen } } }
Sortieralgorithmus zusammenführen
öffentliche Klasse MergeSortTest { public static void main(String[] args) { int[] data = new int[] { 5, 3, 6, 2, 1, 9, 4, 8, 7 }; drucken(Daten); mergeSort(data); System.out.println("Sortiertes Array:"); drucken(Daten); } public static void mergeSort(int[] data) { sort(data, 0, data.length - 1); } public static void sort(int[] data, int left, int right) { if (links >= rechts) zurückkehren; // Den Zwischenindex finden int center = (links rechts) / 2; //Rekursion auf das linke Array sort(data, left, center); //Rekursion auf das rechte Array sort(data, center 1, right); // verschmelzen merge(data, left, center, right); drucken(Daten); }
/** * Führen Sie die beiden Arrays zusammen. Die beiden Arrays sind vor dem Zusammenführen bereits in Ordnung, und sie sind nach dem Zusammenführen immer noch in Ordnung. * @param-Daten * Array-Objekt * @param ist gegangen * Index des ersten Elements des linken Arrays * @param center * Der Index des letzten Elements des linken Arrays, Mitte 1 ist der Index des ersten Elements des rechten Arrays * @param richtig * Index des letzten Elements des rechten Arrays */ public static void merge(int[] data, int left, int center, int right) { //temporäres Array int[] tmpArr = new int[data.length]; // Index des ersten Elements des rechten Arrays int mid = center 1; // Dritter zeichnet den Index des temporären Arrays auf int dritter = links; //Cache den Index des ersten Elements des linken Arrays int tmp = left; while (left <= center && mid <= right) { // Nimm das kleinste aus den beiden Arrays und füge es in das temporäre Array ein if (data[left] <= data[mid]) { tmpArr[third] = data[left]; } anders { tmpArr[third] = data[mid]; } } //Die restlichen Teile werden der Reihe nach in das temporäre Array gelegt (eigentlich wird nur einer der beiden Whiles ausgeführt) while (mitte <= rechts) { tmpArr[third] = data[mid]; 13.04.2018 Seite 240 von 283 } while (links <= Mitte) { tmpArr[third] = data[left]; } //Kopiere den Inhalt des temporären Arrays zurück in das ursprüngliche Array // (Der Inhalt des ursprünglichen Links-Rechts-Bereichs wird zurück in das ursprüngliche Array kopiert) while (tmp <= right) { data[tmp] = tmpArr[tmp]; } } public static void print(int[] data) { for (int i = 0; i < data.length; i ) { System.out.print(data[i] "\t"); } System.out.println(); } }
Bucket-Sortieralgorithmus
Die Grundidee der Bucket-Sortierung besteht darin, das Array arr in n Unterbereiche (Buckets) gleicher Größe zu unterteilen, jeden Unterbereich separat zu sortieren und schließlich zusammenzuführen. Die Zählsortierung ist ein Sonderfall der Bucket-Sortierung. Sie können sich die Zählsortierung als einen Fall vorstellen, bei dem sich in jedem Bucket nur ein Element befindet.
1. Suchen Sie den Maximalwert max und den Minimalwert min im zu sortierenden Array
2. Wir verwenden das dynamische Array ArrayList als Bucket, und die im Bucket platzierten Elemente werden auch in ArrayList gespeichert. Die Anzahl der Buckets beträgt (max.-min.)/Arr.länge 1
3. Durchlaufen Sie das Array arr und berechnen Sie den Bucket, in dem jedes Element arr] platziert wird.
4. Sortieren Sie jeden Eimer einzeln
public static void BucketSort(int[] arr){ int max = Integer.MIN_VALUE; int min = Integer.MAX_VALUE; for(int i = 0; i < arr.length; i ){ max = Math.max(max, arr[i]); min = Math.min(min, arr[i]); } //Bucket erstellen int BucketNum = (max - min) / arr.length 1; ArrayList<ArrayList<Integer>> BucketArr = new ArrayList<>(bucketNum); for(int i = 0; i < BucketNum; i ){ BucketArr.add(new ArrayList<Integer>()); } //Jedes Element in den Bucket legen for(int i = 0; i < arr.length; i ){ int num = (arr[i] - min) / (arr.length); BucketArr.get(num).add(arr[i]); } // Jeden Bucket sortieren for(int i = 0; i < BucketArr.size(); i ){ Collections.sort(bucketArr.get(i)); }}
Radix-Sortieralgorithmus
öffentliche Klasse radixSort { inta[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,101,56,17,18,23,34 ,15,35,2 5,53,51}; public radixSort(){ sort(a); for(inti=0;i<a.length;i ){ System.out.println(a[i]); } } public void sort(int[] array){ //Bestimmen Sie zunächst die Anzahl der Sortierdurchgänge; int max=array[0]; for(inti=1;i<array.length;i ){ if(array[i]>max){ max=array[i]; } } int time=0; //Beurteilen Sie die Anzahl der Ziffern; while(max>0){ max/=10; Zeit ; } //Erstelle 10 Warteschlangen; List<ArrayList> queue=newArrayList<ArrayList>(); for(int i=0;i<10;i ){ ArrayList<Integer>queue1=new ArrayList<Integer>(); queue.add(queue1); } //Zeitzuteilung und -erfassung durchführen; for(int i=0;i<time;i){ //Array-Elemente zuordnen; for(intj=0;j<array.length;j ){ //Die erste Ziffer der Zahl abrufen; int x=array[j]%(int)Math.pow(10,i 1)/(int)Math.pow(10, i); ArrayList<Integer>queue2=queue.get(x); queue2.add(array[j]); queue.set(x, queue2); } int count=0; //Elementzähler; //Warteschlangenelemente sammeln; for(int k=0;k<10;k ){ while(queue.get(k).size()>0){ ArrayList<Integer>queue3=queue.get(k); array[count]=queue3.get(0); queue3.remove(0); zählen ; } } } } }
Beschneidungsalgorithmus
Bei der Optimierung von Suchalgorithmen besteht das Beschneiden darin, unnötige Durchlaufprozesse durch bestimmte Urteile zu vermeiden. Im übertragenen Sinne bedeutet es, einige „Zweige“ im Suchbaum abzuschneiden, daher wird es als Beschneiden bezeichnet. Das Kernproblem bei der Anwendung der Beschneidungsoptimierung besteht darin, eine Beschneidungsbeurteilungsmethode zu entwerfen, d. h. eine Methode, um zu bestimmen, welche Zweige verworfen und welche beibehalten werden sollen.
Backtracking-Algorithmus
Der Backtracking-Algorithmus ist eigentlich ein Suchversuchsprozess, der der Aufzählung ähnelt. Er sucht hauptsächlich nach der Lösung des Problems, wenn während des Suchversuchs festgestellt wird, dass die Lösungsbedingungen nicht mehr erfüllt sind .
Algorithmus für den kürzesten Weg
Unter den Pfaden, die an einem bestimmten Scheitelpunkt beginnen und entlang der Kanten des Diagramms zu einem anderen Scheitelpunkt führen, wird der Pfad mit der kleinsten Summe der Gewichte an jeder Kante als kürzester Pfad bezeichnet. Es gibt die folgenden Algorithmen zur Lösung des Kürzeste-Wege-Problems: Dijkstra-Algorithmus, Bellman-Ford-Algorithmus, Floyd-Algorithmus und SPFA-Algorithmus usw.
Maximaler Subarray-Algorithmus
längster gemeinsamer Teilsequenzalgorithmus
Minimaler Spanning Tree-Algorithmus
Es gibt viele Algorithmen zum Konstruieren minimaler Spannbäume, aber alle nutzen die gleiche Eigenschaft minimaler Spannbäume: die MST-Eigenschaft (vorausgesetzt, N=(V,{E}) ist ein zusammenhängendes Netzwerk und U ist nicht leer Teilmenge der Scheitelpunktmenge V: Wenn (u, v) eine Kante mit minimalem Gewicht ist, wobei u zu U und v zu V-U gehört, muss es einen minimalen Spannbaum geben, der die Kante (u, v) enthält). Es gibt zwei Möglichkeiten, MST-Eigenschaftsalgorithmen zum Generieren minimaler aufspannender Bäume zu verwenden: den Algorithmus von Prim und den Algorithmus von Kruskal.
Wir können verschiedene Spannbäume für ein verbundenes Netzwerk mit n Eckpunkten erstellen. Jeder Spannbaum kann als Kommunikationsnetzwerk verwendet werden. Wenn die Kosten für den Aufbau dieses verbundenen Netzwerks minimal sind, wird der Aufbau des Spannbaums dieses verbundenen Netzwerks als minimal bezeichnet Spannbaum.
Java-Grundlagen
objektorientierte
Verkapselung
Objekteigenschaften ausblenden, um den internen Objektstatus zu schützen
Verbesserte Benutzerfreundlichkeit und Wartbarkeit des Codes
Verhindern Sie schlechte Interaktionen zwischen Objekten und verbessern Sie die Modularität
erben
Bietet Objekten die Möglichkeit, Felder und Methoden aus Basisklassen abzurufen
Polymorphismus
Die Möglichkeit, dieselbe Schnittstelle für verschiedene zugrunde liegende Datentypen anzuzeigen
abstrakt
Trennen Sie das Klassenverhalten von der konkreten Implementierung
Objektorientierte Grundlagen
Definieren Sie Klassen und erstellen Sie Instanzen
Methode
Konstruktionsmethode
Zweck: Initialisieren Sie alle internen Felder beim Erstellen einer Objektinstanz mit den entsprechenden Werten
Standardkonstruktor
Felder initialisieren
Mehrere Baumethoden
diese Variable
Parameter
Formale Parameter und tatsächliche Parameter
Formale Parameter: sind Parameter, die beim Definieren des Funktionsnamens und des Funktionskörpers verwendet werden. Der Zweck besteht darin, die beim Aufruf der Funktion übergebenen Parameter zu empfangen, die als „formale Parameter“ bezeichnet werden.
Tatsächliche Parameter: Beim Aufrufen einer Funktion in der aufrufenden Funktion werden die Parameter in Klammern nach dem Funktionsnamen als „tatsächliche Parameter“ oder kurz „tatsächliche Parameter“ bezeichnet.
Parameterübergabe: Die Methode zur Parameterübergabe in Java erfolgt nach Wert.
Wenn das Argument von einem primitiven Typ ist, wird eine Kopie des Literalwerts des primitiven Typs übergeben.
Wenn der Parameter ein Referenztyp ist, wird eine Kopie des Adresswerts im Heap des Objekts übergeben, auf das der Parameter verweist.
Der grundlegende Unterschied zwischen der Wertübergabe und der Referenzübergabe besteht darin, ob eine Kopie des übergebenen Objekts erstellt wird.
Parameterbindung
Methodenüberladung: Die Methodennamen sind gleich, aber ihre Parameter sind unterschiedlich, was als Methodenüberladung bezeichnet wird.
Zugriffskontrollmodifikator
Öffentlich: Hat die größten Zugriffsrechte und kann auf alle Klassen, Schnittstellen, Ausnahmen usw. unter dem Klassenpfad zugreifen. Es wird häufig in externen Situationen verwendet, also in Form einer Schnittstelle für ein Objekt oder eine Klasse zur Außenwelt.
geschützt: Die Hauptfunktion besteht darin, Unterklassen zu schützen. Dies bedeutet, dass Unterklassen die von ihr geänderten Mitglieder verwenden können, andere jedoch nicht. Dies entspricht einer geerbten Sache, die an Unterklassen übergeben wird.
Standard: Manchmal auch freundlich genannt, ist es für den Zugriff auf dieses Paket konzipiert. Alle Klassen, Schnittstellen, Ausnahmen usw. unter diesem Paket können aufeinander zugreifen, auch Mitglieder der übergeordneten Klasse, die nicht mit protected geändert wurden.
privat: Die Zugriffsrechte sind auf das Innere der Klasse beschränkt, was ein Ausdruck der Kapselung ist. Beispielsweise sind die meisten Mitgliedsvariablen in „privat“ geändert und möchten von keiner anderen externen Klasse aufgerufen werden.
Vererbung: erweitert
Definition: Die Java-Vererbung ist das wichtigste Merkmal der Objektorientierung. Vererbung ist die Ableitung einer neuen Klasse von einer vorhandenen Klasse. Die neue Klasse kann die Datenattribute und Verhaltensweisen der vorhandenen Klasse übernehmen und neue Fähigkeiten erweitern.
Funktion: Durch die Vererbungstechnologie ist es sehr einfach, vorherigen Code wiederzuverwenden, was den Entwicklungszyklus erheblich verkürzen und die Entwicklungskosten senken kann.
Schlüsselwort super: gibt die übergeordnete Klasse an
Upcasting: Eine Zuweisung, die einen Unterklassentyp sicher in einen übergeordneten Klassentyp ändert, wird Upcasting genannt.
Downcasting: Wenn ein übergeordneter Klassentyp zu einem Unterklassentyp gezwungen wird, handelt es sich um eine Downcasting-Methode.
Operator-Instanz von
Der Unterschied zwischen Vererbung und Kombination: Vererbung ist eine Ist-Beziehung und Kombination ist eine Hat-Beziehung.
Polymorphismus
Definition: Derselbe Vorgang wirkt sich auf verschiedene Objekte aus und kann unterschiedliche Interpretationen haben und unterschiedliche Ausführungsergebnisse erzeugen. Zur Laufzeit können Sie Methoden in einer abgeleiteten Klasse über einen Zeiger auf die Basisklasse aufrufen.
Funktion: Ermöglicht das Hinzufügen weiterer Arten von Unterklassen, um eine Funktionserweiterung zu implementieren, ohne den Code basierend auf der übergeordneten Klasse zu ändern. Durch die Behandlung verschiedener Unterklassenobjekte als übergeordnete Klassen können die Unterschiede zwischen verschiedenen Unterklassenobjekten abgeschirmt, gemeinsamer Code geschrieben und eine gemeinsame Programmierung zur Anpassung an sich ändernde Anforderungen vorgenommen werden.
Methoden zur Erzielung von Polymorphismus: virtuelle Funktionen, abstrakte Klassen, Überschreibungen, Vorlagen
überschreiben
Definition: Wenn in einer Vererbungsbeziehung eine Unterklasse eine Methode mit genau derselben Signatur wie die Methode der übergeordneten Klasse definiert, spricht man von Überschreibung.
Objektmethoden überschreiben
toString(): Instanz als String ausgeben
equal(): Bestimmen Sie, ob zwei Instanzen logisch gleich sind
hashCode(): Berechnen Sie den Hash-Wert einer Instanz
Steuerbeispiel
Schlüsselwort final: Durch Ändern der Methode mit final kann verhindert werden, dass sie von Unterklassen überschrieben wird
abstrakte Klasse
Definition: Eine mit abstract modifizierte Klasse ist eine abstrakte Klasse.
Funktion: Da die abstrakte Klasse selbst nur für die Vererbung konzipiert ist, kann die abstrakte Klasse die Unterklasse zwingen, die von ihr definierte abstrakte Methode zu implementieren, andernfalls meldet die Kompilierung einen Fehler. Daher sind abstrakte Methoden tatsächlich gleichbedeutend mit der Definition von „Spezifikationen“.
abstrakte Programmierung
Schlüsselwortabstrakt
Schnittstelle
Definition: Interface ist eine rein abstrakte Schnittstelle, die abstrakter ist als eine abstrakte Klasse, da sie nicht einmal Felder haben kann.
Der Unterschied zwischen abstrakter Klasse und Schnittstelle
Schlüsselwortschnittstelle
Standardmethode
Statische Felder und Methoden
Statisches Feld: statisches Feld
statische Felder der Schnittstelle
Statische Methode: statische Methode
Initialisierungssequenz statischer Variablen und statischer Methoden
Tasche
Java definiert einen Namensraum namens package: package. Eine Klasse gehört immer zu einem bestimmten Paket (z. B. Person) ist nur eine Abkürzung. Der tatsächliche vollständige Klassenname ist Paketname.Klassenname. Verwenden Sie Pakete, um Namenskonflikte zu lösen
Paketumfang: Klassen, die sich im selben Paket befinden, können auf die Felder und Methoden des Paketumfangs zugreifen. Felder und Methoden, die nicht durch public, protected oder private geändert werden, sind Paketbereiche.
Schlüsselwort import: Der Zweck des Imports besteht darin, Ihnen das Schreiben von Xyz zu ermöglichen, ohne abc.def.Xyz schreiben zu müssen, und Zugriffsberechtigungen sind zwei verschiedene Dinge.
Umfang
Mit den Modifikatoren public, protected und private kann der Zugriffsbereich eingeschränkt werden.
Lokale Variablen: Innerhalb einer Methode definierte Variablen werden als lokale Variablen bezeichnet. Der Gültigkeitsbereich lokaler Variablen beginnt mit der Deklaration der Variablen und endet mit dem entsprechenden Block. Methodenparameter sind ebenfalls lokale Variablen.
finaler Modifikator: Java bietet auch einen finalen Modifikator. final steht nicht in Konflikt mit Zugriffsberechtigungen und hat viele Verwendungsmöglichkeiten.
Das Dekorieren einer Klasse mit final kann verhindern, dass sie vererbt wird.
Das Dekorieren einer Methode mit final verhindert, dass sie von Unterklassen überschrieben wird
Das Ändern eines Felds mit final verhindert, dass es neu zugewiesen wird
Das Dekorieren lokaler Variablen mit final verhindert, dass sie neu zugewiesen werden
Klassenpfad und Glas
Modul
Verglichen
Abstrakte Klassen und Schnittstellen
Essenz: Abstraktion ist die Abstraktion von Klassen und ein Template-Interface ist die Abstraktion von Verhalten und eine Spezifikation von Verhalten.
abstrakte Änderung der abstrakten Klasse
Geben Sie einen gemeinsamen Typ für Unterklassen an
Kapseln Sie wiederholte Eigenschaften und Methoden in Unterklassen
Abstrakte Klassen enthalten nicht unbedingt abstrakte Methoden, aber Klassen mit abstrakten Methoden müssen abstrakte Klassen sein und können nicht instanziiert werden.
Konstruktoren und Klassenmethoden (durch Statik geänderte Methoden) können nicht als abstrakte Methoden deklariert werden
Definieren Sie abstrakte Methoden
abstrakte modifizierte Methode
Eine Unterklasse einer abstrakten Klasse muss, sofern sie nicht auch eine abstrakte Klasse ist, die von der abstrakten Klasse deklarierten Methoden implementieren
Zwischen der übergeordneten Klasse und der abgeleiteten Klasse muss eine „Ist-ein“-Beziehung bestehen, d. h. die übergeordnete Klasse und die abgeleitete Klasse sollten konzeptionell gleich sein.
Schnittstellenschnittstellenmodifikation
Die Methoden einer Schnittstelle sind standardmäßig öffentlich. Alle Methoden können nicht in der Schnittstelle implementiert werden.
In jdk9 wurden die private Methode und die private statische Methode eingeführt
Die Implementierung der Schnittstelle muss über eine Unterklasse erfolgen. Die Unterklasse verwendet das Schlüsselwort „implementiert“, und die Schnittstelle kann auf verschiedene Arten implementiert werden.
Wenn eine Klasse eine Schnittstelle implementiert, muss sie alle Methoden der Schnittstelle implementieren, abstrakte Klassen jedoch nicht unbedingt
Eine Schnittstelle kann nicht mit new instanziiert werden, aber sie kann deklariert werden, sie muss jedoch auf ein Objekt verweisen, das die Schnittstelle implementiert.
Mitgliedsvariablen in der Schnittstelle können nur vom Typ public static final sein
Der Implementierer implementiert nur den durch die Schnittstelle definierten Verhaltensvertrag, eine „Like-a“-Beziehung
Der Unterschied zwischen Überladen und Umschreiben
Überladung: Tritt in derselben Klasse auf, der Methodenname muss gleich sein, der Parametertyp und die Parameternummer sind unterschiedlich
Umschreiben: Tritt in übergeordneten und untergeordneten Klassen auf. Der Methodenname und die Parameterliste müssen gleich sein und der Rückgabewert ist kleiner oder gleich dem der übergeordneten Klasse.
Wenn der Methodenzugriffsmodifikator der übergeordneten Klasse privat ist, wird er in der Unterklasse nicht überschrieben.
Vergleichen Sie mit prozessorientiert
Objektprozeduren weisen eine höhere Leistung auf, haben jedoch den Nachteil, dass sie nicht so einfach zu warten und zu erweitern sind wie objektorientierte.
Einfache Wartung, einfache Wiederverwendung, einfache Erweiterung, geringere Leistung als prozessorientiert
Datentypen und Operationen
Grundlegende Datentypen
Integer Wert
Byte, kurz, int, lang
Zeichentyp
verkohlen
Boolescher Wert
Boolescher Wert
Gleitkomma
doppelt, schweben
Art der Verpackung
Byte, Kurz, Ganzzahl, Lang
Boolescher Wert
Charakter
Float, Double
Der Unterschied zwischen Grundtypen und Verpackungstypen
Wrapper-Typen können null sein, Basistypen nicht
Wrapper-Typen können mit Generika verwendet werden, Basistypen nicht
Primitive Typen sind effizienter als verpackte Typen
Basistypen speichern bestimmte Werte direkt auf dem Stapel, während Wrapper-Typen Referenzen im Heap speichern.
Die Werte zweier Wrapper-Typen können gleich, aber nicht gleich sein
Ganzzahl chenmo = new Integer(10); Integer wanger = new Integer(10); System.out.println(chenmo == wanger); // false System.out.println(chenmo.equals(wanger)); // true
Ein- und Auspacken
Der Prozess der Konvertierung von Basistypen in verpackte Typen wird als Boxen bezeichnet
Der Vorgang des Konvertierens eines umschlossenen Typs in einen Basistyp wird als Unboxing bezeichnet
Referenztyp
Art
Schnittstelle
Array
Array-Typ: int[] ns = new int[5]
Befehlszeilenparameter String[ ] args
Zeichenfolge
String-Objekte sind unveränderlich
Die Zeichenfolge wird von final geändert und kann daher nicht vererbt werden.
StringBuffer und StringBuilder
StringBuilder bietet eine höhere Leistung als StringBuffer, ist jedoch threadunsicher
String-Verkettung:
Leerer Wert null und leere Zeichenfolge
aufzählen
markieren
Schlüsselwörter
var
Betrieb
Ganzzahlige Operationen
Arithmetik
Selbstinkrementierung/Selbstdekrementierung: ,--
Verschiebung
Bitoperationen
Verwandte konzepte
Betriebspriorität
Überlauf
Typkonvertierung
Gleitkomma-Arithmetik
Arithmetik
Verwandte konzepte
Überlauf
erzwungene Transformation
Typförderung
Boolesche Operationen
Vergleichsoperatoren: >, >=, <, <=, ==, !=
UND-Verknüpfung: &&
ODER-Verknüpfung: ||
Kein Betrieb: !
Ternärer Operator: b ? x : y
Verwandte konzepte
Kurzschlussoperation: Wenn das Ergebnis eines booleschen Operationsausdrucks im Voraus bestimmt werden kann, werden nachfolgende Berechnungen nicht ausgeführt und das Ergebnis wird direkt zurückgegeben.
Vorrang relationaler Operationen
Referenztyp
starke Referenz
Standardtyp
GC-Roots-Erreichbarkeitsanalyse: erreichbar, immer noch referenziert und nicht erreichbar, Szenario des Recyclings aller Programme, Basisobjekte, benutzerdefinierter Objekte usw.
String str = "xxx";
weiche Referenz
Etwas schwächer als starke Referenzen
Wenn der Speicher ausreicht, wird er nicht recycelt. Wenn der Speicher nicht ausreicht, wird er recycelt.
Wird im Allgemeinen für Ressourcen verwendet, die sehr speicherempfindlich sind und in vielen Cache-Szenarien verwendet werden: Webseiten-Caching, Bild-Caching usw.
SoftReference<String> softReference = new SoftReference<String>(new String("xxx"));
schwache Referenz
Der Lebenszyklus ist kürzer als der von Soft-Referenzen und kann nur bis zur nächsten Garbage Collection überleben.
Objekte mit einem kurzen Lebenszyklus, wie z. B. Key in ThreadLocal
WeakReference<String> schwachReference = new WeakReference<String>(new String("Misout's blog")); if(weakReference.get() == null) { System.out.println("weakReference has been Von GC recycelt"); } // Infolgedessen wurde schwache Referenz von GC recycelt
virtuelle Referenz
Muss in Verbindung mit einer Referenzwarteschlange verwendet werden
Derzeit gibt es in der Branche keine Nutzungsszenarien. Es kann intern vom JVM-Team verwendet werden, um JVM-Garbage-Collection-Aktivitäten zu verfolgen.
Es kann jederzeit recycelt werden. Sobald es erstellt wurde, kann es bald recycelt werden.
Funktion: Um den Speicher von Objekten besser zu verwalten und eine bessere Speicherbereinigung durchzuführen
PhantomReference<String> phantomReference = new PhantomReference<String>(new String("Misout's blog"), new ReferenceQueue<String>()); //Das Ergebnis ist immer Null
Prozesssteuerung
Eingabe und Ausgabe
Ausgabe: System.out.println (Ausgabeinhalt)
Eingabe: Scanner scanner = new Scanner(System.in); String name = scanner.nextLine();
wenn Urteil
wenn ... sonst wenn ..
Bestimmen Sie die Gleichheit des Referenztyps: Methode equal()
Mehrfachauswahl umschalten
Die switch-Anweisung kann auch mit Zeichenfolgen übereinstimmen. Beim Abgleichen von Zeichenfolgen wird „Inhalt ist gleich“ verglichen.
durchdringend
Zyklus
while-Schleife
mache eine While-Schleife
for-Schleife
Schleifenkontrollanweisung
break: Aus der aktuellen Schleife springen
continue: Diese Schleife vorzeitig beenden und direkt mit der Ausführung der nächsten Schleife fortfahren.
Java-Kernklassen
Zeichenfolge
Erstellen: String s1 = „Hallo“
Vergleiche: s1.equals(s2)
Suche: s1.contain(s2) s1.indexOf(s2) / s1.lastIndexOf(s2) / s1.statsWith(s2) / s1.endWith(s2)
Extraktion: s1.substring(index1, index2)
Führende und nachfolgende Leerzeichen entfernen: s1.trim() / s1.strip()
Zeichenfolge ersetzen
replaceFirst(String-Regex,String-Ersetzung)
Teilzeichenfolge ersetzen: s1.replace(s2, s3) / s1.replaceAll(regex)
Aufteilen: s1.split(regex)
Spleißen: String.join("Spleißsymbol", String[])
Ermitteln Sie die Stringlänge
str.length()
Holen Sie sich das Zeichen an einer bestimmten Position in der Zeichenfolge
str.charAt(4)
Holen Sie sich einen Teilstring eines Strings
str.substring(2,5)
String-Vergleich
Finden Sie die Position eines Teilstrings in einem String
str.indexOf('a')
str.indexOf('a',2)
str.lastIndexOf('a')
str.lastIndexOf('a',2)
Groß-/Kleinschreibung von Zeichen in einer Zeichenfolge
toLowerCase()
toUpperCase()
Entfernen Sie Leerzeichen an beiden Enden der Zeichenfolge
trimmen()
String in String-Array aufteilen
split(String str)
Grundlegende Typkonvertierung in einen String
String.valueOf(12.99)
Konvertierung des Basistyps in String: String.valueOf(Basistyp)
String wird in Basistypen konvertiert: Integer.parseInt(s1) / Double.parseDouble(s1) / Boolean.parseBoolean(s1)
String -> char[]: char[ ] cs = s1.toCharArray()
char[] -> String:String s = neuer String(cs)
Typkonvertierung
Kodierung: byte[] b1 = s1.getBytes("Eine Kodierungsmethode")
Dekodierung: String s1 = neuer String(b1, „Einige Kodierungsmethode“)
verschlüsseln entschlüsseln
StringBuilder
Erstellen: StringBuilder sb = new StringBuilder(buffer size);
Zeichenfolge schreiben: sb.append(s1).sappend(s2)...
Zeichenfolge löschen: sb.delete(start_index, end_index)
Konvertierung: String s1 = sb.toString()
StringJoiner
Erstellen: var sj = new StringJoiner(Trennzeichen, Startsymbol, Endsymbol)
Zeichenfolge schreiben: sj.add(s1)
Konvertierung: String s1 = sb.toString()
Art der Verpackung
Autoboxing: Integer n = 100; // Der Compiler verwendet automatisch Integer.valueOf(int)
Automatisches Unboxing: int x = n; // Der Compiler verwendet automatisch Integer.intValue()
Basiskonvertierung: int x2 = Integer.parseInt("100", 16); // 256, da es hexadezimal analysiert wird
statische Variable
Nummer
JavaBeans
Enum-Klasse
Warum Enum-Klassen verwenden?
Erstellen: enum ClassName{A, B, C...}
Vergleiche: ==
Konstantennamen zurückgeben: String s = ClassName.A.name()
Gibt die Ordnungszahl der definierten Konstante zurück: int n = ClassName.A.ordinal()
Lesbarkeit verbessern: toString()
Aufzählung: Schalter
Rekordklasse
Schlüsselwort aufzeichnen
BigInteger
Erstellen: BigInteger a = new BigInteger("1234567890")
Operationen: a.add(b) / a.subtract(b) / a.multiply(b) / a.mod(b) usw.
BigDecimal
Erstellen: BigDecimal bd = new BigDecimal("123.4567")
Anzahl der Dezimalstellen: bd.scale() // 4, vier Dezimalstellen
Nachgestellte Nullen entfernen: bd.stripTrailingZeros()
Operation: bd.function(bd2)
Kürzen
Vergleiche: bd.equals(bd2)
Häufig verwendete Werkzeuge
Mathematische Berechnungen: Mathe
Generieren Sie gefälschte Zufallszahlen: Zufällig
Sichere Zufallszahlen generieren: SecureRandom
Betrachtung
Klasse Klasse
Es gibt drei Möglichkeiten, eine Klasseninstanz einer Klasse abzurufen
Erhalten Sie es direkt über die statische Variablenklasse einer Klasse: Klasse cls = String.class
Wenn eine Instanzvariable vorhanden ist, kann diese über die von der Instanzvariablen bereitgestellte Methode getClass() abgerufen werden: String s = "Hello";Class cls = s.getClass();
Wenn Sie den vollständigen Klassennamen einer Klasse kennen, können Sie ihn über die statische Methode Class.forName() abrufen: Klasse cls = Class.forName("java.lang.String");
Klasseninstanzvergleich und Instanzvergleich
Erhalten Sie die Klasseninformationen des Objekts durch Reflexion
Erstellen Sie Instanzen entsprechender Typen über Klasseninstanzen
Funktionen des dynamischen Ladens von Klassen durch VM: Um verschiedene Implementierungsklassen je nach Bedingungen während der Laufzeit zu laden.
Eine dynamische Montage kann erreicht werden
Reduzieren Sie die Codekopplung
dynamischer Proxy
Die Klasse java.lang.Class im JDK ist eine der Kernklassen zur Implementierung der Reflektion.
dynamischer Proxy
Zur Laufzeit wird eine Zielklasse erstellt und Methoden der Zielklasse können aufgerufen und erweitert werden.
Dynamischer JDK-Proxy
Implementieren Sie die InvocationHandler-Schnittstelle
Schreiben Sie die Aufrufmethode neu und fügen Sie Geschäftslogik hinzu
Enthält das Zielklassenobjekt
Stellen Sie eine statische Methode bereit, um einen Proxy zu erhalten
Dynamischer CGLib-Proxy
Verwendet ASM (Bytecode Manipulation Framework), um Bytecode zu manipulieren und neue Klassen zu generieren
Java-Serialisierung
Serialisierung: Der Prozess der Konvertierung von Java-Objekten in Bytestreams
Deserialisierung: Der Prozess der Konvertierung eines Bytestreams in ein Java-Objekt
JavaException
Wurfklasse
Fehlerklasse
Bezieht sich im Allgemeinen auf Probleme im Zusammenhang mit virtuellen Maschinen
Durch diese Art von Fehler verursachte Unterbrechungen können vom Programm selbst nicht behoben werden. Wenn ein solcher Fehler auftritt, wird empfohlen, das Programm zu beenden.
NoClassDefFoundError
Tritt auf, wenn die JVM dynamisch ausgeführt wird und die entsprechende zu ladende Klasse gemäß dem von Ihnen angegebenen Klassennamen nicht im Klassenpfad finden kann.
Ausnahmeklasse
Stellt eine Ausnahme dar, die das Programm verarbeiten, abfangen und möglicherweise wiederherstellen kann
Wenn Sie auf eine solche Ausnahme stoßen, sollten Sie die Ausnahme so gut wie möglich behandeln und das Programm fortsetzen, anstatt die Ausnahme willkürlich zu beenden.
Ungeprüfte Ausnahme
Bezieht sich auf einen Fehler oder Logikfehler in einem Programm, der zur Laufzeit nicht behoben werden kann
RuntimeException
NullPointerException/Nullzeigerausnahme
Eine NullPointerException tritt auf, wenn eine Methode für ein Nullobjekt aufgerufen wird
IndexOutOfBoundsException-Array-Index-Ausnahme außerhalb der Grenzen
NegativeArraySizeException Ausnahme bei negativer Array-Länge
ArithmeticException Mathematische Berechnungsausnahme
Umwandlungsausnahme vom Typ ClassCastException
Ausnahme „SecurityException“, Verletzung der Sicherheitsprinzipien
Geprüfte Ausnahme
Stellt ungültige externe Bedingungen dar, die das Programm nicht direkt steuern kann
ClassNotFoundException
Ein Fehler tritt auf, wenn die entsprechende Klasse während der Kompilierung nicht im Klassenpfad gefunden werden kann.
Ausnahme „NoSuchMethodException-Methode nicht gefunden“.
IOException-Eingabe- und Ausgabeausnahme
NumberFormatException String zur Nummernausnahme
EOFException Datei beendete Ausnahme
FileNotFoundException Ausnahme Datei nicht gefunden
SQLException-Vorgangsdatenbankausnahme
Würfe
Wirkt auf die Deklaration einer Methode und gibt an, dass der Aufrufer der Methode die Ausnahme behandelt, wenn eine Ausnahme ausgelöst wird.
Die Methode löst eine Ausnahme eines bestimmten Typs aus, sodass ihre Benutzer wissen, welche Art von Ausnahme abzufangen ist.
Eine Anomalie ist möglich, muss aber nicht zwangsläufig auftreten
Werfen
löst tatsächlich eine Ausnahme aus
Versuchen Sie es endlich zu fangen
Sowohl „catch“ als auch „final“ können weggelassen werden, jedoch nicht beide gleichzeitig
„finally“ wird auf jeden Fall ausgeführt, und die Rückgabe in „catch“ wird erst ausgeführt, wenn der Code in „final“ ausgeführt wird.
JavaEE-Grundlagen
hierarchisches Modell
Klassische drei Schichten
Web-Ebene
Servlet/JSP
Geschäftslogikschicht (BLL)
EJB
Persistenzschicht
JDBC, MyBatis, Hibernate
Vierschichtmodell
Präsentationsschicht (PL)
Serviceschicht (Service)
Geschäftslogikschicht (BLL)
Datenzugriffsschicht (DAL)
Fünfschichtiges Modell
Domänenobjektebene
DAO (Datenzugriffsschicht)
Geschäftslogikschicht
MVC-Kontrollschicht
Präsentationsfolie
Mehrschichtige Anwendung
JPA (Java Persistence API)
JPA-Implementierung
JMS (Java Message Service)
JCA (JavaEE-Connector-Architektur)
Verwaltete Bohnen, EJB
CDI (Safe Dependency Injection)
Webebene
Servlets, JSPs
Internetdienste
JavaIO/NIO
IO
Streaming
Byte-Stream
Eingabestrom
PipedInputStream
ByteArrayInputStream
FileInputStream
FileterInputStream
BufferedInputStream
DataInputStream
PushBackInputStream
StringBufferInputStream
SequenceInputStream
ObjectInputStream
Ausgabestrom
ObjectOutputStream
PipedOutputStream
FileterOutputStream
BufferedOutputStream
DataOutputStream
PrintStream
FileOutputStream
ByteArrayOutputStream
Zeichenstrom
Schriftsteller
FilterWriter
StringWriter
PipedWriter
OutputStreamWriter
FileWriter
CharArrayWriter
BufferedWriter
PrintWriter
Leser
BufferedReader
LineNumberReader
CharArrayReader
InputStreamReader
FileReader
PipedReader
StringReader
FilterReader
Nicht-Streaming
Datei
andere
SerializablePermission
Dateisystem
Zeichenkodierung
ASCII, amerikanischer Standardcode für den Informationsaustausch
Lateinischer Code, ISO8859-1
Chinesischer Code, GB2312/GBK/GBK18030
Internationaler Standardcode, Unicode
UTF-8, UTF-16, Codierung mit variabler Länge gemäß Unicode
IO-Modell
BIO (Blocking I/O): Synchroner Blocking I/O-Modus
NIO (New I/O): Synchrones, nicht blockierendes I/O-Modell
Kanal bidirektionaler Kanal
Puffer
Wähler
Multiplexen
wählen
Schematische Darstellung
Mangel: 1) Es gibt eine Höchstgrenze für die Anzahl der Dateideskriptoren, die überwacht werden können (1024). 2) Die Effizienz des linearen Scannens ist gering
Umfrage
epoll
Wenn der FD bereit ist, verwenden Sie die Rückruffunktion des Systems, um den FD direkt einzufügen, was effizienter ist. Keine Begrenzung der maximalen Anzahl von Verbindungen
AIO (Asynchronous I/O): Asynchrones, nicht blockierendes IO-Modell
Signalgesteuertes IO-Modell
Asynchrones IO-Modell
Pseudoasynchrones IO-Modell
Formalparameter und Aktualparameter
Parameter, die in einer Funktionsdefinition erscheinen, werden als formale Parameter bezeichnet. Parameter, die in einem Funktionsaufruf erscheinen, werden als tatsächliche Parameter bezeichnet.
Formale Parametervariablen allokieren nur beim Aufruf Speichereinheiten. Am Ende des Aufrufs werden die allokierten Speichereinheiten sofort freigegeben.
Aktualparameter können Konstanten, Variablen, Ausdrücke, Funktionen usw. sein. Egal um welche Art von Größen es sich bei den Aktualparametern handelt, diese müssen bei Funktionsaufrufen bestimmte Werte haben, damit diese Werte auf die Formalparameter übertragen werden können.
Im allgemeinen Call-by-Value-Mechanismus können nur die tatsächlichen Parameter auf die formalen Parameter übertragen werden, der Wert der formalen Parameter kann jedoch nicht in umgekehrter Richtung auf die tatsächlichen Parameter übertragen werden. Daher ändert sich während des Funktionsaufrufs der Wert des formalen Parameters, der Wert im tatsächlichen Parameter jedoch nicht. Beim Call-by-Reference-Mechanismus wird die Adresse der tatsächlichen Parameterreferenz an den formalen Parameter übergeben, sodass alle am formalen Parameter vorgenommenen Änderungen tatsächlich an der tatsächlichen Parametervariablen vorgenommen werden.
Java-Web-Grundlagen
Servet JDBC-Anwendung (3.1)
db.properties-Datei (Eigenschaftendatei)
Inhalt der .properties-Datei: #Fahreradresse driversClassName=oracle.jdbc.OracleDriver #Verbindungsadresse url=jdbc:oracle:thin:@localhost:1521/XE #Accountnummer Benutzername=system/litao #Passwort Passwort=123456 #Optional #Initialisierte Verbindungspoolanzahl der Verbindungen initialaSize=5 #Maximale Anzahl von Verbindungen maxActive=100 #Maximale Anzahl reservierter Verbindungen im Leerlauf maxIdle=10 #Mindestanzahl reservierter Verbindungen im Leerlauf minIdle=5 #Überstunden maxWait=10000
Importieren Sie 3 Pakete
Schreiben Sie die Verbindungspool-Toolklasse
DbcpUtil
com.xdl.util-Paket
Schließen Sie die Funktion zum Anmelden bei einem Bankkonto ab
Erstellen Sie eine Bankkontotabelle in der Datenbank
Erstellen Sie eine init.sql
/** Erstellen Sie eine Bankkontotabelle und löschen Sie sie vor der Erstellung */ Drop-Tabelle xdl_bank_account Kaskadenbeschränkung; Erstellen Sie die Tabelle xdl_bank_account( ID-Nummernbeschränkung xdl_bank_account_id_pk Primärschlüssel, acc_no varchar(30) Einschränkung xdl_bank_account_acc_no_uk eindeutig, acc_password varchar(30), acc_money-Nummer ); /** Erstellen Sie eine Sequenz für diese Tabelle und löschen Sie sie, bevor Sie sie erstellen */ Drop-Sequenz xdl_bank_account_id_seq; Sequenz erstellen xdl_bank_account_id_seq; /** Testdaten einfügen */ in xdl_bank_account-Werte einfügen (xdl_bank_account_id_seq.nextval, 'malaoshi','17',10000000); begehen;
Erstellen Sie ein Projekt und erstellen Sie Entitätsklassen basierend auf Tabellen (um es ganz klar auszudrücken: Kapselung).
Benennungsformat: Entfernen Sie den Unterstrich im Tabellennamen und schreiben Sie den ersten Buchstaben groß Der Variablenname stimmt mit der Tabelle überein construction,get set,tostring,serialization implementiert Serializable
com.xdl.bean-Paket
Definieren Sie das Design von DAO-Schnittstellenmethoden
Benennungsformat: Fügen Sie DAO nach der Entitätsklasse hinzu Führen Sie nur eines der Dinge aus: Hinzufügen, Löschen, Ändern und Überprüfen
com.xdl.Dao
Kombinieren Sie gemäß der DAO-Schnittstelle die DbcpUtil- und JDBC-Programmierung in fünf Schritten, um die DAO-Implementierungsklasse abzuschließen
Benennungsformat: Entitätsklasse Dao-Datenbankname imp Datenbankverbindungscode 1. Laden Sie den Treiber. 2. Stellen Sie die Verbindung her 3. Definieren Sie SQL und erhalten Sie die vorkompilierte Umgebung von SQL Parameter setXX einstellen 4. Führen Sie SQL aus, um den Rückgabewert von SQL Select/Durchlauf der Ergebnismenge zu verarbeiten 5. Geben Sie Ressourcen frei
com.xdl.dao.imp
Schreiben Sie einen Geschäftslogikklassendienst, um Geschäftsmethoden zu kapseln
Benennungsformat: Fügen Sie die Funktion Service nach der Entitätsklasse hinzu 1. Halten Sie ein DAO 2. Weisen Sie Dao einen Wert zu 3. Kapseln Sie eine Geschäftsmethode (return interface.method).
com.xdl.service
Testklasse
com.xdl.test
Schreiben Sie eine HTML-Seite, um eine Anmeldeanfrage zu stellen
Schreiben Sie ein Servlet, um Benutzeranforderungsparameter zu empfangen, und rufen Sie die Methode im Dienst basierend auf den Parametern auf, um zu sehen, ob die Anmeldung erfolgreich ist. Andernfalls ist die Anmeldung fehlgeschlagen.
Benennungsformat: Servlet nach der Entitätsklasse hinzufügen 0.Kodierung 1. Anforderungsparameter abrufen 2. Nutzen Sie den Service, um Urteile zu fällen 3. Kapseln Sie Parameter in Objekte 4. Schreiben Sie in den Browser und rufen Sie ein Ausgabeobjekt für den Browser ab
com.xdl.servlet
Statusverwaltung
Warum sollten wir eine staatliche Verwaltung haben?
Da das HTTP-Protokoll zustandslos ist, wird die Anfrage beim Antworten vom Server getrennt Die letzte Anfrage Es hat nichts mit zukünftigen Datenvariablen zu tun. Manchmal müssen Sie jedoch den Datenstatus der letzten Anfrage abrufen, z. B. beim Einkaufen, um Waren zu kaufen. Benötigt werden die Produktdaten des letzten und vorangegangenen Kaufs.
So implementieren Sie staatliche Managementtechnologie
Clientbasierte Zustandsverwaltungstechnologie
Kekse
Prinzip
Wenn der Browser einen Server auf dem Server anfordert, erstellt der Server ein Cookie-Objekt und verwendet dann setCookie Wird in Form von Nachrichtenheadern an den Browser übergeben. Wenn der Browser erneut Dienste vom Server anfordert, trägt er dieses Cookie-Objekt. an den Server. Der Server kann den letzten Datenstatus erfahren.
Wie erreichen?
Erstellen Sie ein Cookie-Objekt Cookie cookie=new Cookie("key","value");
So schreiben Sie an den Kunden Antwort.addCookie(cookie);
Zusammenfassung
So erhalten Sie das entsprechende Cookie in der Anfrage Cookie [] Cookies =request.getCookies();
Rufen Sie den Namen und den Wert des Cookies ab getName() Wert erhalten() Einstellungen setValue("String-Wert")
Zusammenfassung
Probleme mit dem Cookie-Lebenszyklus
Der Standardwert ist derselbe wie die Browserlebensdauer. Er verschwindet, wenn der Browser geschlossen wird.
setMaxAge(int Sekunden); (Sekunden)
Nach Ablauf des Cookies wird es vom Browser nicht mehr übertragen (Wie lege ich eine dreimonatige Lebensdauer fest? setMaxAge(60*60*24*93);) Wenn Sie die Lebensdauer auf 0 setzen, wird das Cookie sofort gelöscht
Problem mit dem Cookie-Pfad
Der Standardpfad, in dem sich das Cookie befindet, ist der Pfad, in dem sich das Servlet befindet.
Die Regel für die Übertragung von Cookies lautet, dass die Cookies unter diesem Pfad und die Cookies unter dem übergeordneten Pfad, der diesem Pfad entspricht, übertragen werden.
Sie können den Standardpfad von Cookies über setPath("/path") ändern.
Zum Beispiel: setPath("/servlet-day04") Das bedeutet, dass das Cookie unter dem Projekt platziert wird Alle Anfragen für dieses Projekt enthalten dieses Cookie.
Was bedeutet es, wenn der Pfad als /? geschrieben wird? Vertreter für alle Anliegen
Serverbasierte Zustandsverwaltungstechnologie
Sitzung
Grundwissen
Parameter anfordern
Chinesisches verstümmeltes Problem der Anforderungsparameter
tomcat8: Es gibt kein Problem mit verstümmeltem Code in der get-Methode
tomcat8: Problem mit verstümmeltem Code im Post-Modus
Wenn der Beitrag übermittelt wird, werden die Daten in utf-8 übermittelt. Wenn Tomcat jedoch dekodiert, erfolgt die Dekodierung standardmäßig gemäß ISO-8859-1.
HttpServletRequest Dieser Objekttyp stellt die entsprechende API für Tomcat bereit, um die Decodierungskodierung festzulegen.
request.setCharacterEncoding("utf-8")
Sagen Sie Tomcat, dass es in UTF-8 dekodieren soll
Muss erscheinen, bevor Parameter abgerufen werden
Dies gilt nur für die Post-Methode
acc_no=new String (acc_no.getbytes("iso-8859-1"),"utf-8");
Zuerst nach ISO-8859-1 dekodieren, dann nach utf-8 kodieren
Dies ist eine gängige Lösung
Holen Sie sich Post für Tomcat7- und Tomcat8-Post
Anforderungsparameter abrufen
Anforderungsparameter in String abrufen String data= request.getParameter("name") Rufen Sie die entsprechenden Anforderungsparameter basierend auf dem Namen ab, der einem einzelnen Wert entspricht
String [] datas=request.getParameterValues("name"); Rufen Sie den entsprechenden Anforderungsparameter und das Array der entsprechenden Werte entsprechend dem Namen ab
HttpServletRequest API zum Abrufen von Anforderungsheaderinformationen
getMethod()
Anforderungsmethode abrufen
getServletPath();
Rufen Sie den Anforderungspfad des Servlets ab, der url-pattiern entspricht
getContextPath()
/Artikelname
getServerPort()
Die Portnummer
getServerName()
CPU-Name
getRemoteAddr()
Rufen Sie die Remote-Client-Adresse ab
getLocalAddr()
Serveradresse abrufen
getRequestURL()
Einheitliche Ressourcenpositionierung
http://localhost:8888/Web02/Zhuce
Protokoll-Host-Port-Projektanforderung
getRequestURI()
Einheitlicher Ressourcenbezeichner
/Web02/Zhuce
Projektanfrage
Weiterleitung und Umleitung
der Unterschied
Die sendRedirect()-Methode in der HttpServletResponse-Schnittstelle wird zum Implementieren der Umleitung verwendet
Big Data, Cloud Computing und andere Erweiterungen
Betrieb und Integration
Kontinuierliche Integration (CI/CD)
Versionsverwaltungstool (SCM)
Git
SVN
Lagerverwaltung
GitLab
Maven-Repository-Manager
Apache Archiva
JFrog Artifactory
Sonatype Nexus
Werkzeuge erstellen
Maven
Ameise
Gradle
Codeerkennung
SonarQube
Automatisierte Freigabe
Jenkins
prüfen
Verteiltes Testen
Vollständiger Link-Stresstest
Integrationstests
Verschlüsselungsalgorithmus
AES
Advanced Encryption Standard (AES, Advanced Encryption Standard) ist der gebräuchlichste symmetrische Verschlüsselungsalgorithmus
Der symmetrische Verschlüsselungsalgorithmus verwendet denselben Schlüssel für die Verschlüsselung und Entschlüsselung
RSA
Der RSA-Verschlüsselungsalgorithmus ist ein typischer asymmetrischer Verschlüsselungsalgorithmus, der auf dem mathematischen Problem der Faktorisierung großer Zahlen basiert. Er ist auch der am weitesten verbreitete asymmetrische Verschlüsselungsalgorithmus.
Die asymmetrische Verschlüsselung verwendet zwei Schlüssel (öffentlicher Schlüssel-privater Schlüssel) zum Ver- und Entschlüsseln von Daten.
Der öffentliche Schlüssel wird zur Verschlüsselung und der private Schlüssel zur Entschlüsselung verwendet.
CRC
Cyclic Redundancy Check (CRC) ist eine Hash-Funktion, die einen kurzen Prüfcode mit fester Ziffer auf der Grundlage von Netzwerkdatenpaketen oder Computerdateien generiert. Sie wird hauptsächlich zur Erkennung oder Überprüfung von Fehlern bei der Datenübertragung oder -speicherung verwendet.
Es verwendet die Prinzipien der Division und des Rests zur Fehlererkennung.
MD5
MD5 erscheint oft als Signatur einer Datei, wir sehen oft einen Text oder eine Zeichenzeile mit der Erweiterung .MD5 an der Dateiseite Originaldaten erstellt und über MD5 berechnet. Nachdem wir die Datei heruntergeladen haben, können wir eine Software verwenden, die die MD5-Informationen der Datei überprüft, um eine Berechnung für die heruntergeladene Datei durchzuführen.
Durch zweimaliges Vergleichen der Ergebnisse kann die Genauigkeit der heruntergeladenen Datei sichergestellt werden.
Eine weitere häufige Verwendung ist die Verschlüsselung vertraulicher Website-Informationen wie Benutzernamen und Passwörter, Zahlungssignaturen usw.
Mit der Popularisierung der https-Technologie verwenden aktuelle Websites in großem Umfang die Front-End-Klartextübertragung an das Back-End und MD5-Verschlüsselung (mit Offset), um sensible Daten zu schützen und die Website- und Datensicherheit zu gewährleisten.
neue Technologie
Blockchain-Technologie (Java Edition)
Blockchain-Anwendung
Bitcoin
Äther
Hyperledger
Big-Data-Technologie
Große Daten
Hadoop
Karte verkleinern
Hadoop MapReduzieren Sie den Joblebenszyklus
Klient
JobTracker
TaskTracker
Aufgabe
Umsetzungsprozess
1. Lesen Sie die MapTask-Zwischenergebnisse vom Remote-Knoten (sogenannte „Shuffle-Phase“);
2. Schlüssel/Wert-Paare nach Schlüssel sortieren (als „Sortierungsphase“ bezeichnet);
3. Lesen Sie <Schlüssel, Werteliste> nacheinander, rufen Sie die benutzerdefinierte Funktion „reduce0“ zur Verarbeitung auf und speichern Sie das Endergebnis in HDFS
HDFS
Klient
NameNode
Sekundärer NameNode
Datenknoten
Garn wird nach Hadoop2.0 eingeführt
HBase
Funke
Kernarchitektur
Funkenkern
Spark SQL
Spark-Streaming
MIlib
GraphX
Kernkomponenten
Cluster-Manager – Steuern Sie den gesamten Cluster und überwachen Sie die Worker
Worker-Knoten – verantwortlich für die Steuerung von Rechenknoten
Treiber: Führen Sie die main()-Funktion der Anwendung aus
Testamentsvollstrecker
Aktuator,
Ist ein Prozess, der auf einem Arbeitsknoten für eine Anwendung ausgeführt wird
SPARK-Programmiermodell
1. Benutzer verwenden die von SparkContext bereitgestellte API (häufig verwendete APIs sind textFile, sequenceFile, runJob, stop usw.), um das Treiberanwendungsprogramm zu schreiben. Darüber hinaus kapseln SQLContext, HiveContext und Streaming Context SparkContext und stellen APIs für SQL, Hive und Streaming Computing bereit.
2. Mit SparkContext übermittelte Benutzeranwendungen verwenden zunächst BlockManager und BroadcastManager, um die Hadoop-Konfiguration der Aufgabe zu übertragen. Die Aufgaben werden dann von DAGScheduler in RDDs umgewandelt und in DAGs organisiert. Die DAGs werden ebenfalls in verschiedene Phasen unterteilt. Schließlich verwendet TaskScheduler ActorSystem, um die Aufgabe an den Cluster-Manager (Cluster Manager) zu übermitteln.
3. Der Cluster-Manager (ClusterManager) weist Aufgaben Ressourcen zu, dh weist Arbeitern bestimmte Aufgaben zu, und Arbeiter erstellen Executoren, um die Ausführung von Aufgaben zu übernehmen. Standalone, YARN, Mesos, EC2 usw. können alle als Spark-Cluster-Manager verwendet werden.
SPARK-Berechnungsmodell
SPARK-Betriebsprozess
1. Erstellen Sie das laufende Umgebungssystem der Spark-Anwendung und starten Sie SparkContext
2.SparkContext gilt für die Ausführung von Executor-Ressourcen vom Ressourcenmanager (kann Standalone, Mesos, Yarn sein) und startet StandaloneExecutorbackend.
3.Der Executor fordert eine Aufgabe von SparkContext an
4. SparkContext verteilt die Anwendung an Executor
5.SparkContext wird in ein DAG-Diagramm umgewandelt, das DAG-Diagramm wird in Phasen zerlegt, der Tasksatz wird an den Taskplaner gesendet und schließlich sendet der Taskplaner die Aufgabe zur Ausführung an den Executor
6. Die Aufgabe wird auf dem Executor ausgeführt und alle Ressourcen werden nach der Ausführung freigegeben.
SPARK RDD-Prozess
1. Erstellen Sie ein RDD-Objekt
2. Das DAGScheduler-Modul greift in den Vorgang ein, um die Abhängigkeiten zwischen RDDs zu berechnen. Die Abhängigkeiten zwischen RDDs bilden eine DAG.
3. Jeder Job ist in mehrere Phasen unterteilt. Eine Hauptgrundlage für die Aufteilung der Stufen ist, ob die Eingabe des aktuellen Berechnungsfaktors sicher ist. Wenn ja, teilen Sie ihn in dieselbe Stufe auf, um zu vermeiden, dass die Nachricht zwischen mehreren Stufen weitergegeben wird.
Bienenstock
Big-Data-Suche
Lucene
ElasticSearch
Merkmale
Basierend auf der Lucene-Grundarchitektur
Der Begründer der Java-Suchbranche
Hohe Suchleistung in Echtzeit
Reguläre, Teilstring-Speicherdatenbank
Mitglied
Text der Dokumentzeile (Zeile).
Indexindex (Datenschlüsselwert)
Analysator-Wortsegmentierer (Beschriftung)
Solr
Merkmale
Für die Echtzeitsuche nicht verfügbar
Nutt
Garn
Ressourcenmanager
1. ResourceManager ist für die Ressourcenverwaltung und -zuweisung des gesamten Clusters verantwortlich und ist ein globales Ressourcenverwaltungssystem.
2. NodeManager meldet die Ressourcennutzung im Heartbeat-Verfahren an ResourceManager (derzeit hauptsächlich CPU- und Speichernutzung). RM akzeptiert nur Ressourcenrückgabeinformationen von NM und überlässt die spezifische Ressourcenverarbeitung NM selbst.
3. YARN Scheduler weist Anwendungen Ressourcen basierend auf deren Anforderungen zu und ist nicht für die Überwachung, Nachverfolgung, Ausführung von Statusrückmeldungen, Start usw. von Anwendungsjobs verantwortlich.
NodeManager
1. NodeManager ist der Ressourcen- und Task-Manager auf jedem Knoten. Er ist der Agent, der diesen Computer verwaltet und für die Ausführung des Knotenprogramms sowie die Verwaltung und Überwachung der Knotenressourcen verantwortlich ist. Jeder Knoten im YARN-Cluster führt einen NodeManager aus.
2. NodeManager meldet regelmäßig die Ressourcennutzung (CPU, Speicher) dieses Knotens und den Betriebsstatus des Containers an ResourceManager. Wenn ResourceManager ausfällt, stellt NodeManager automatisch eine Verbindung zum RM-Sicherungsknoten her.
3. NodeManager empfängt und verarbeitet verschiedene Anforderungen von ApplicationMaster, z. B. das Starten und Stoppen von Containern.
ApplicationMaster
1. Verantwortlich für die Verhandlungen mit dem RM-Scheduler zum Erhalt von Ressourcen (dargestellt durch Container).
2. Ordnen Sie die erhaltenen Aufgaben weiter internen Aufgaben zu (sekundäre Zuweisung von Ressourcen).
3. Kommunizieren Sie mit NM, um Aufgaben zu starten/stoppen.
4. Überwachen Sie den Ausführungsstatus aller Aufgaben und wenden Sie erneut Ressourcen für die Aufgabe an, um die Aufgabe neu zu starten, wenn die Aufgabe fehlschlägt.
5. Derzeit verfügt YARN über zwei ApplicationMaster-Implementierungen. Eine davon ist das Instanzprogramm DistributedShell, das zur Demonstration von AM-Schreibmethoden verwendet werden kann. Die andere dient der parallelen Ausführung eines Shell-Befehls oder Shell-Skripts Anwendungen. AM – MRAppMaster.
Künstliche Intelligenz-Technologie
Neuronale Netze
maschinelles Lernen
tiefes Lernen
Häufig verwendete Frameworks
DL4J
Algorithmus für maschinelles Lernen
Entscheidungsbaum
Random-Forest-Algorithmus
logistische Regression
SVM
Naiver Bayes
K-Algorithmus für den nächsten Nachbarn
K-Means-Algorithmus
Adaboost-Algorithmus
Markow
Mathematische Grundlage
Anwendungsszenarien
Cloud Computing
virtuelle Maschine
JRockitVM
HotSpotVM
Cloud-nativ
Kubernetes
Docker
Docker verwendet ein Client-Server-Architekturmodell (C/S) und nutzt Remote-APIs zum Verwalten und Erstellen von Docker-Containern.
Docker-Container werden aus Docker-Images erstellt.
Die vier Netzwerkmodi von Docker
Gastgeber
Container
Keiner
Brückenmodus
Von Docker unterstützte Speichertreiber
AUFS
Gerätemapper
Overlay2
zfs
vfs
Klassifizierung der Cloud-Architektur
öffentliche Cloud
Kauf/Lösung – Obere Ebene
Riesige Rechenressourcen
Unternehmen A baut eine Cloud-Computing-Umgebung auf ---->Unternehmen B/C/D
Im Ausland: aws/google/azure
Inland: Aliyun/Tencent Cloud/Huaweicloud/Jinshan Cloud
Private Wolke
Bereitstellung und Konstruktion – unterste Schicht
Private Daten/wichtige Daten
Unternehmen A baut – Unternehmen A nutzt
Im Ausland: VMware Vicoud
Inland: Huawei DevCloud/H3C Cloud
Hybrid Cloud: Private Cloud der öffentlichen Cloud
Cloud-Computing-Geschäftsmodell
SaaS
Berechnen Sie die Gebühr pro Nutzung, indem Sie Dienste bereitstellen, die den Anforderungen des Endbenutzers entsprechen
Internetanwendung
Beispiel
Zwangsversteigerung
Huawei Cloud: WeLink
PaaS
Bereitstellung einer Anwendungslauf- und Entwicklungsumgebung
Bereitstellung von Komponenten für die Anwendungsentwicklung (z. B. Datenbank)
Beispiel
Microsoft: Visio Studio Tools für Azure
Huawei Cloud: Devcloud-Softwareentwicklungs-Cloud
laaS
Mieten Sie Computer, Speicher, Netzwerk und andere IT-Ressourcen
Bezahlen pro Benutzung
Beispiel
Amazon EC2 Cloud-Host
Huawei Cloud: ECS
Offener Stapel
Viel
Java-Sammlungen
Sammlungsrahmen
Rahmenstrukturdiagramm
Sammlung
Aufführen
Anordnungsliste
Geordnet und wiederholbar
Grundlage der Verwendung von Arrays
Die Methoden getter() und setter() sind schnell, das Hinzufügen und Löschen jedoch langsam.
Nicht Thread-sicher
Wenn die Kapazität nicht ausreicht, ist die ArrayList die aktuelle Kapazität * 1,5 1
CopyOnWriteArrayList
Schreibt eine Kopie des Arrays, unterstützt effiziente Parallelität und ist Thread-sicher
Sperrfreie ArrayList lesen
Geeignet für den Einsatz in Szenarien, in denen Lesevorgänge viel umfangreicher sind als Schreibvorgänge, z. B. beim Caching
Es gibt kein Erweiterungskonzept. Für jeden Schreibvorgang ist eine Kopie erforderlich, sodass die Leistung des Schreibvorgangs schlecht ist.
Implementierte Schnittstellen wie List, RandomAccess, Cloneable, java.io.Serializable usw.
Schreibmethoden wie Hinzufügen/Entfernen müssen gesperrt werden. Der Zweck besteht darin, das Kopieren von N Kopien und das gleichzeitige Schreiben zu vermeiden.
LinkedList
Geordnet und wiederholbar
Die unterste Ebene verwendet eine bidirektionale zirkuläre verknüpfte Listendatenstruktur
Die Abfragegeschwindigkeit ist hoch, das Hinzufügen und Löschen ist schnell, add() und remove() sind schnell
Nicht Thread-sicher
Vektor
Geordnet und wiederholbar
Grundlage der Verwendung von Arrays
Schnelles, langsames Hinzufügen und Löschen
Wenn die Kapazität nicht ausreicht, erweitert Vector standardmäßig seine Kapazität auf das Doppelte.
Stapel
Die unterste Ebene ist ebenfalls ein Array, das von Vector geerbt wurde
First in, last out, die Standardkapazität beträgt 10
Anwendung: Auswertung von Postfix-Ausdrücken
Satz
HashSet
In keiner Reihenfolge angeordnet und nicht wiederholbar
Die unterste Ebene wird mithilfe einer Hash-Tabelle implementiert, und die interne Ebene ist eine HashMap.
Schnelle Zugriffsgeschwindigkeit
TreeSet
In keiner Reihenfolge angeordnet und nicht wiederholbar
Die unterste Ebene wird mithilfe eines Binärbaums implementiert
Sortierspeicher, intern TreeMap und SortedSet
LinkedHashSet
Verwenden Sie die Hash-Tabellenspeicherung und doppelt verknüpfte Listendatensätze zum Einfügen von Daten
Von HashSet geerbt, intern LinkedHashMap
Warteschlange
An beiden Enden eingefügte Listen können auch mithilfe von Arrays oder verknüpften Listen implementiert werden.
Verzögerungswarteschlange
Es handelt sich um eine verzögerte Blockierungswarteschlange unter dem Java-Concurrent-Paket, die häufig zum Implementieren geplanter Aufgaben verwendet wird.
DelayQueue implementiert BlockingQueue
Hauptsächlich mithilfe von Prioritätswarteschlangen implementiert, ergänzt durch wiedereintretende Sperren und Bedingungen zur Steuerung der Parallelitätssicherheit
Prioritätswarteschlange
Ist ein kleiner oberer Heap, nicht threadsicher
Es ist nicht geordnet, nur das kleinste Element wird oben im Heap gespeichert
PriorityBlockingQueue
Es handelt sich um eine Prioritätsblockierungswarteschlange unter dem gleichzeitigen Java-Paket, die threadsicher ist.
ArrayDeque (doppelendige Warteschlange)
Es handelt sich um eine spezielle Warteschlange, die an beiden Enden Elemente betreten und verlassen kann, daher der Name doppelendige Warteschlange.
Es handelt sich um eine als Array implementierte doppelendige Warteschlange, die nicht threadsicher ist.
ArrayDeque implementiert die Deque-Schnittstelle, die von der Queue-Schnittstelle erbt.
Es kann direkt als Stapel verwendet werden, indem das Array über Kopf- und Endzeiger recycelt wird.
Wenn die Kapazität nicht ausreicht, wird sie erweitert. Bei jeder Erweiterung wird die Kapazität verdoppelt.
Karte
HashMap
Tasten können nicht wiederholt werden, Werte können wiederholt werden
Zugrunde liegende Hash-Tabelle, internes Array, einfach verknüpfte Liste
In jdk8 werden rot-schwarze Bäume eingeführt, um verknüpfte Listen mit einer Länge > 8 zu konvertieren
Der Schlüsselwert darf null sein, und der Wert kann auch null sein.
Verwenden Sie den Hash-Algorithmus, um die Speicheradresse gemäß hashCode() zu konfigurieren
Nicht Thread-sicher
Schreibvorgang verloren
Überschreibung ändern
HashTable (Hash-Tabelle/Hash-Tabelle)
Tasten können nicht wiederholt werden, Werte können wiederholt werden
zugrunde liegende Hash-Tabelle
Thread-Sicherheit
Schlüssel und Wert dürfen nicht null sein
LinkedHashMap
Implementiert basierend auf HashMap und doppelt verknüpfter Liste/Rot-Schwarz-Baum
ordentlich
Einfügungsauftrag
Die Reihenfolge, in der sie eingefügt werden, entspricht der Reihenfolge, in der sie ausgelesen werden.
Zugriffssequenz
Nach dem Zugriff auf einen Schlüssel kommt dieser Schlüssel zum Ende.
WeakHashMap
ConcurrentHashMap
Effizient und Thread-sicher
Schlüssel und Wert dürfen nicht null sein
TreeMap
Tasten können nicht wiederholt werden, Werte können wiederholt werden
Der Schlüsselwert ist erforderlich, um java.lang.Comparable zu implementieren
Bei der Iteration sortiert TreeMap standardmäßig in aufsteigender Reihenfolge nach Schlüsselwert.
NavigableMap-Implementierung basierend auf einem Rot-Schwarz-Baum
Rot-Schwarz-Bäume sind ausgeglichene Binärbäume
Die durchschnittliche Höhe beträgt log(n), und die Höhe im schlimmsten Fall wird 2log(n) nicht überschreiten.
Rot-Schwarz-Bäume können Such-, Einfüge- und Löschvorgänge mit einer zeitlichen Komplexität von O(log2(N)) ausführen.
Jedes Ungleichgewicht wird innerhalb von 3 Drehungen behoben
SortedMap-Schnittstelle
Karte der Gesamtreihenfolge der Schlüssel
Eigenschaften
HashTable-Unterklasse, kann nur mit dem String-Typ arbeiten
Strom
Grundlegende Vorgänge streamen
Karte verkleinern
Verteiltes Rechenmodell, das hauptsächlich im Suchfeld verwendet wird
Allgemeine Löschung
Generika und Objekt Der Unterschied
Allgemeine Erklärung
public <T> T doSomeThing(T t){return t;
Allgemeine Referenz
Keine erzwungene Konvertierung mehr, die Typsicherheit wird automatisch zur Kompilierungszeit überprüft und implizite Typkonvertierungsausnahmen werden vermieden.
Objektdeklaration
öffentliches Objekt doSomeThing(Object obj){ return obj }
Objektreferenz
Möglicherweise tritt eine Typkonvertierungsausnahme (ClassCastException) auf
Unterschiede und Analogien
HashMap, HashSet, Der Unterschied zwischen HashTable
HashSet
HashMap
Hash-Kollision
Kettenadressmethode
verlinkte Liste
JDK1.7
Verkettete Bit-Bucket-Liste
JDK1.8
Bit-Bucket-verknüpfte Liste rot-schwarzer Baum
Hash-tabelle
ConcurrentHashMap
HashMap, LinkedHashMap, Der Unterschied zwischen TreeMap
HashMap
Array-verknüpfte Liste/Rot-Schwarz-Baum
Werte in keiner Reihenfolge
Der Schlüssel von höchstens einem Datensatz ist null
In den meisten Fällen ist keine Sortierung erforderlich
LinkedHashMap
Array-verknüpfte Liste/Rot-Schwarz-Baum
Werte werden in der Reihenfolge der Einfügung/Änderung übernommen, gesteuert durch accessOrder
Der Schlüssel von höchstens einem Datensatz ist null
Die Reihenfolge des Einfügens und die Reihenfolge des Entfernens müssen gleich sein.
TreeMap
roter schwarzer Baum
Drücken Sie beim Einfügen die natürliche Reihenfolge der Tasten oder eine benutzerdefinierte Reihenfolge.
Der Schlüssel darf nicht null sein, wenn er in der natürlichen Reihenfolge der Schlüssel gespeichert wird
Wenn Sie die natürliche Reihenfolge der Tasten oder sogar eine benutzerdefinierte Reihenfolge einhalten müssen
Anordnungsliste, Der Unterschied zwischen LinkedList
Arraylist basiert auf der Array-Struktur (dynamisches Array).
Die maximale Array-Kapazität beträgt Integer.MAX_VALUE-8
Für die frei gewordenen 8 Bits
①Speicherkopfwörter
② Vermeiden Sie einen Überlauf des Maschinenspeichers und verringern Sie die Fehlerwahrscheinlichkeit. Weisen Sie daher weniger zu
③Der maximal noch unterstützte Wert ist Integer.MAX_VALUE.
Dynamisches Linkedlist-Array basierend auf der verknüpften Liste
Das Hinzufügen und Löschen von Daten ist effizient und erfordert nur das Ändern des Zeigers.
Allerdings ist die durchschnittliche Effizienz beim Zugriff auf Daten gering und die verknüpfte Liste muss durchlaufen werden.
Der Unterschied zwischen ArrayList und Vector
Synchronizität
Vector ist Thread-sicher
Thread-Synchronisation zwischen Methoden
ArrayList ist programmgesteuert unsicher
Die Threads werden zwischen den Methoden nicht synchronisiert
Datenwachstum
Der Vektor wächst standardmäßig um das Doppelte seiner ursprünglichen Größe
ArrayList wächst um das 1,5-fache seiner ursprünglichen Größe
Was ist der Unterschied zwischen Collection und Collections?
java.util.Collection ist eine Sammlungsschnittstelle
Stellt allgemeine Schnittstellenmethoden für grundlegende Vorgänge an Sammlungsobjekten bereit
java.util.Collections ist eine Wrapper-Klasse
Verschiedene statische Methoden im Zusammenhang mit Sammelvorgängen
Kann nicht wie eine Toolklasse instanziiert werden und dient dem Collection-Framework von Java
Was ist der Unterschied zwischen Array und ArrayList?
ArrayList stellt man sich als „Array vor, das seine Kapazität automatisch erweitert“
Die Größe von Array ist fest und die Größe von ArrayList ändert sich dynamisch.
Array kann Basistypen und Objekttypen enthalten, ArrayList kann nur Objekttypen enthalten.
Die Warteschlange ist ein typischer First-In-First-Out-Container (FIFO).
Der Unterschied zwischen offer() und add() zum Hinzufügen eines Elements zur Warteschlange
Wenn Sie einer vollständigen Warteschlange ein neues Element hinzufügen möchten
Die offer()-Methode gibt false zurück
Die Methode add() löst eine ungeprüfte Ausnahme aus
Der Unterschied zwischen peek() und element() bei der Rückgabe des Kopfes der Warteschlange, ohne ihn zu entfernen
Die Methode peek() gibt null zurück, wenn die Warteschlange leer ist
Die Methode element() löst eine NoSuchElementException aus
Entfernen Sie den Kopf der Warteschlange und geben Sie ihn zurück. Der Unterschied zwischen poll() und remove().
poll() gibt null zurück, wenn die Warteschlange leer ist
„remove()“ löst die Ausnahme „NoSuchElementException“ aus
IteratorIterator
Iteratormuster
Trennen Sie das Durchlaufverhalten von Datenstrukturen vom Sequenztyp von den durchquerten Objekten
Wiederholbar
Sammlungsobjekte, die diese Schnittstelle implementieren, unterstützen die Iteration und können iteriert werden.
Kann mit foreach verwendet werden
Iterator: Iterator
Ein Objekt, das einen Iterationsmechanismus bereitstellt. Die spezifische Iterationsmethode wird durch diese Iterator-Schnittstelle angegeben.
Die Beziehung zwischen foreach und Iterator
Der Aufruf von „Collection Remove“ in „foreach“ führt dazu, dass sich die ursprüngliche Sammlung ändert und ein Fehler auftritt.
Sie sollten die Methode „remove“ des Iterators verwenden
Vergleich zwischen for-Schleife und Iterator
Die get()-Methode in der for-Schleife verwendet die Direktzugriffsmethode
ArrayList ist für den Direktzugriff schneller
Die next()-Methode im Iterator verwendet die sequentielle Zugriffsmethode
LinkedList ist für sequentiellen Zugriff schneller.
Der Unterschied zwischen Iterator und ListIterator
ListIterator-Iterator
Unterschiedlicher Einsatzbereich
Iterator kann auf alle Sammlungen, Set, List und Map sowie Untertypen dieser Sammlungen angewendet werden
ListIterator kann nur mit List und seinen Untertypen verwendet werden
ListIterator ist leistungsfähiger und kann hinzufügen, löschen, ändern und abfragen
Implementierungsmethoden und -prinzipien
Implementierungsprinzip von HashMap
Eintragsarray
Lagerraum
Quellcode
static int indexFor(int h, int length) { return h & (length-1);}
static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
Aufgrund der Summenoperation (Länge-1) beträgt die Länge in den meisten Fällen weniger als 2 hoch 16. Daher sind immer die unteren 16 Bits des Hashcodes an der Operation beteiligt. Wenn auch die oberen 16 Bits an der Operation beteiligt sind, wird der resultierende Index stärker gehasht.
Also erhält (h >>> 16) seine hohen 16 Bits und führt die ^-Operation mit hashCode() aus
Da & und | beide das Ergebnis auf 0 oder 1 verzerren, was kein einheitliches Konzept ist, verwenden Sie daher XOR
Implementierungsprinzip von HashSet
Keine doppelten Elemente zulässig
Der Wert von HashSet wird im Schlüssel von HashMap gespeichert
Die unterste Ebene von HashSet wird durch HashMap implementiert, das ungeordnet ist.
Die Elemente in HashSet werden im Schlüssel von HashMap gespeichert
Der Wert wird zu einer bedeutungslosen statischen Konstante vereint privates statisches endgültiges Objekt PRESENT = new Object();
So stellen Sie sicher, dass eine Sammlung nicht geändert werden kann
Verwenden Sie die Methode Collections.unmodifiableCollection(Collection c) unter dem Collections-Paket
Jeder Vorgang, der die Sammlung ändert, löst die Ausnahme Java.lang.UnsupportedOperationException aus
Verschiedene Methoden zum Konvertieren zwischen Arrays und Listensammlungen
Array zur Liste
Verwenden des Collectors im Stream
List<String> list5=Stream.of(str).collect(Collectors.toList());
Liste zum Array
Verwenden Sie die Methode toArray()
String[] str2=list.toArray(new String[list.size()]);
Deduplizierungsmethode auflisten
Verwenden Sie den Stream von Java8, um Duplikate zu entfernen
Liste uniqueList = list.stream().distinct().collect(Collectors.toList());
Set erlaubt keine doppelten Elemente
Duplikate durchlaufen und entfernen
Mikrodienste
Theoretisches Wissen
ESB (Service Bus)
Enthält Inhalte
Service-Metadatenverwaltung
Serviceregistrierung, Lebenszyklus
Protokollanpassung
Vermittlungsdienste
Verschiedene Integrationsszenarien unterstützen verschiedene Nachrichtenverarbeitungs- und Konvertierungsmodi
Governance und Überwachung
Protokolle und statistische Analyse von Serviceaufrufen und Nachrichtenverarbeitung, Servicequalität, Serviceverschlechterung, Flusskontrolle usw.
Sicherheit
Übertragungskommunikationssicherheit, Datensicherheit, Serviceanrufsicherheit, Identitätsprüfung usw.
andere
Transaktionsmanagement, hohe Leistung, hohe Verfügbarkeit, hohe Zuverlässigkeit, hohe Stabilität usw.
Sicherung
Erkennung der Dienstregistrierung
Werkzeug
Zookeeper
Konsul
etcd,
Heureka
Kundenregistrierung (Zookeeper)
Registrierung durch Dritte (unabhängiger Service-Registrar)
Wenn der Dienst gestartet wird, wird der Registrar auf irgendeine Weise benachrichtigt, und dann ist der Registrar für die Einleitung der Registrierungsarbeiten beim Registrierungszentrum verantwortlich.
Gleichzeitig muss das Registrierungszentrum den Heartbeat zwischen dem Dienst und dem Dienst aufrechterhalten. Wenn der Dienst nicht verfügbar ist, muss das Registrierungszentrum den Dienst abmelden.
Client-Erkennung
Servererkennung
API-Gateway
API Gateway ist ein Server, der auch als einziger Knoten bezeichnet werden kann, der in das System eindringt.
Weiterleitung beantragen
Die Dienstweiterleitung installiert hauptsächlich die Last von Mikrodiensten auf Clientanfragen und leitet sie an verschiedene Dienste weiter.
Antwortzusammenführung
Kombinieren Sie die Arbeit, die den Aufruf mehrerer Serviceschnittstellen erfordert, in einem Aufruf, um der Außenwelt einheitliche Dienste bereitzustellen.
Protokollkonvertierung
Der Schwerpunkt liegt auf der Unterstützung der Protokollkonvertierung zwischen SOAP, JMS und Rest.
Datenkonvertierung
Der Schwerpunkt liegt auf der Unterstützung von Nachrichtenformatkonvertierungsfunktionen zwischen XML und Json (optional).
Sicherheitszertifikat
1. Tokenbasierte Client-Zugriffskontrolle und Sicherheitsrichtlinie
2. Um Übertragungsdaten und Nachrichten zu verschlüsseln und auf dem Server zu entschlüsseln, ist auf dem Client ein unabhängiges SDK-Agentenpaket erforderlich.
3. HTTPS-basierte Übertragungsverschlüsselung, Unterstützung digitaler Client- und Serverzertifikate
4. Dienstsicherheitsauthentifizierung basierend auf OAuth2.0 (Autorisierungscode, Client, Passwortmodus usw.)
Konfigurationszentrum
Erfordern
Effiziente Akquise
Echtzeitwahrnehmung
verteilter Zugriff
Zookeeper-Konfigurationscenter
Datenklassifizierung im Konfigurationscenter
Veranstaltungsplanung (Kafka)
Serviceverfolgung (Starter-Sleuth)
Da die Anzahl der Microservices weiter wächst, ist es notwendig, den Ausbreitungsprozess einer Anfrage von einem Microservice zum nächsten zu verfolgen. SpringCloud Sleuth löst dieses Problem. Es führt eindeutige IDs in das Protokoll ein, um die Konsistenz zwischen Microservice-Aufrufen sicherzustellen Sie können verfolgen, wie eine Anfrage von einem Microservice zum nächsten weitergeleitet wird.
Service-Leistungsschalter (Hystrix)
Das Prinzip einer Sicherung ist sehr einfach, genau wie bei einem elektrischen Überlastschutz. Wenn es im Laufe der Zeit viele ähnliche Fehler erkennt, führt es dazu, dass mehrere nachfolgende Aufrufe schnell fehlschlagen und nicht mehr auf den Remote-Server zugreifen, wodurch verhindert wird, dass die Anwendung ständig versucht, möglicherweise fehlgeschlagene Vorgänge auszuführen Die Anwendung kann mit der Ausführung fortfahren, ohne auf die Behebung von Fehlern warten zu müssen oder CPU-Zeit mit dem Warten auf eine lange Zeitüberschreitung zu verschwenden. Mithilfe von Leistungsschaltern kann eine Anwendung auch diagnostizieren, ob der Fehler behoben wurde. Ist dies der Fall, versucht die Anwendung erneut, den Vorgang aufzurufen.
Hystrix-Leistungsschaltermechanismus
Wenn die Anzahl der fehlgeschlagenen Hystrix Command-Anfragen an Backend-Dienste einen bestimmten Anteil (Standard 50 %) überschreitet, wechselt der Leistungsschalter in den Zustand „Offener Stromkreis“ (Offen).
Mittlere Microservice-Plattform
SpringCloud Alibaba
SpringCloud Netflix
Enthält Artikel
Eureke
Verteilte Middleware auf Basis von REST-Services für das Service-Management
Hystrix
Ein fehlertolerantes Framework, das dabei hilft, Komponenteninteraktionen zwischen verteilten Systemen zu steuern
Führen Sie ein Service-Rollback durch, wenn der Anruf fehlschlägt
Unterstützt Echtzeitüberwachung, Alarm und andere Vorgänge
Stoppen Sie in verteilten Systemen kaskadierende Ausfälle (Dienstunterbrechungen)
Vortäuschen
REST-Client, der die Entwicklung von Webdienst-Clients vereinfachen soll
Schleife
Das Lastausgleichsframework unterstützt die Kommunikation zwischen verschiedenen Clients im Microservice-Cluster und realisiert den Lastausgleich in der mittleren Schicht.
Zuul
Stellen Sie Proxy-, Filter-, Routing- und andere Funktionen für Microservice-Cluster bereit
Netty- und RPC-Framework
Netty
Netty-Prinzip
Es handelt sich um ein leistungsstarkes, asynchrones, ereignisgesteuertes NIO-Framework, das auf der Grundlage der von JAVA NIO bereitgestellten API implementiert wird
Es bietet Unterstützung für TCP, UDP und Dateiübertragung
Alle IO-Operationen von Netty sind asynchron und nicht blockierend
Über den Future-Listener-Mechanismus können Benutzer auf einfache Weise E/A-Vorgangsergebnisse aktiv oder über den Benachrichtigungsmechanismus abrufen.
Nett hohe Leistung
Die IO-Multiplexing-Technologie multiplext die Blockierung mehrerer IOs mit der Blockierung derselben Auswahl, sodass das System mehrere Client-Anfragen gleichzeitig in einem einzigen Thread verarbeiten kann.
Im Vergleich zum herkömmlichen Multi-Thread-/Multi-Prozess-Modell besteht der größte Vorteil des E/A-Multiplexings darin, dass der System-Overhead gering ist und das System keine neuen zusätzlichen Prozesse oder Threads erstellen muss.
Das System muss den Betrieb dieser Prozesse und Threads nicht überwachen, was den Wartungsaufwand des Systems verringert und Systemressourcen spart.
Multiplex-Kommunikationsmethode
Der IO-Thread NioEventLoop von Netty kann aufgrund der Aggregation des Multiplexer-Selektors gleichzeitig Hunderte oder Tausende von Client-Kanälen verarbeiten. Da die Lese- und Schreibvorgänge nicht blockieren, kann dies die Betriebseffizienz des IO-Threads vollständig verbessern und vermeiden aufgrund der Thread-Unterbrechung, die durch häufige E/A-Blockierung verursacht wird.
Asynchrone Kommunikation NIO
Da Netty einen asynchronen Kommunikationsmodus verwendet, kann ein IO-Thread N Client-Verbindungen sowie Lese- und Schreibvorgänge gleichzeitig verarbeiten, wodurch das herkömmliche synchrone blockierende IO-Modell mit einer Verbindung und einem Thread grundsätzlich gelöst wird.
Keine Kopie (DIRECT BUFFERS verwendet Off-Heap-Direktspeicher)
1. Netty verwendet DIRECT BUFFERS zum Empfangen und Senden von ByteBuffer und verwendet Off-Heap-Direktspeicher zum Lesen und Schreiben von Sockets, ohne dass eine sekundäre Kopie des Bytepuffers erforderlich ist. Wenn herkömmlicher Heap-Speicher (HEAP BUFFERS) zum Lesen und Schreiben von Sockets verwendet wird, kopiert die JVM den Heap-Speicherpuffer in den Direktspeicher und schreibt ihn dann in den Socket. Im Vergleich zum direkten Speicher außerhalb des Heaps verfügt die Nachricht während des Sendevorgangs über eine zusätzliche Speicherkopie des Puffers.
2.Netty bietet ein kombiniertes Pufferobjekt, das mehrere Byte-Pufferobjekte zusammenfassen kann. Benutzer können den kombinierten Puffer genauso bequem bedienen wie einen Puffer und vermeiden so die herkömmliche Methode, mehrere kleine Puffer durch Speicherkopieren zu einem großen zusammenzuführen.
3. Die Dateiübertragung von Netty verwendet die transferTo-Methode, mit der die Daten im Dateipuffer direkt an den Zielkanal gesendet werden können, wodurch das durch die herkömmliche zyklische Schreibmethode verursachte Speicherkopierproblem vermieden wird.
Speicherpool (Pufferwiederverwendungsmechanismus basierend auf dem Speicherpool)
Puffer wiederverwenden,
Netty bietet einen auf einem Speicherpool basierenden Pufferwiederverwendungsmechanismus
Reaktor-Thread-Modell
Reaktor-Single-Threaded-Modell
Dies bedeutet, dass alle I0-Vorgänge im selben NIO-Thread abgeschlossen werden
1) Als NIO-Server die TCP-Verbindung des Clients empfangen;
2) Initiieren Sie als NIO-Client eine TCP-Verbindung zum Server.
3) Lesen Sie die Anforderungs- oder Antwortnachricht vom Kommunikationspartner.
4) Senden Sie eine Nachrichtenanforderung oder eine Antwortnachricht an den Kommunikationspartner.
Da der Reaktormodus asynchrone, nicht blockierende E/A verwendet, verursachen alle E/A-Vorgänge keine Blockierung. Theoretisch kann ein Thread alle E/A-bezogenen Vorgänge unabhängig verarbeiten.
Reaktor-Multithreading-Modell
Der größte Unterschied zwischen dem Rector-Multithread-Modell und dem Single-Thread-Modell besteht darin, dass es eine Reihe von NIO-Threads zur Abwicklung von E/A-Vorgängen gibt.
Der NIO-Thread-Akzeptor-Thread wird verwendet, um den Server zu überwachen und die TCP-Verbindungsanforderung des Clients zu empfangen.
Netzwerk-I0-Operationen – Lesen, Schreiben usw. – sind für einen NIO-Thread-Pool verantwortlich
Der Thread-Pool kann mithilfe des Standard-JDK-Thread-Pools implementiert werden, der eine Aufgabenwarteschlange und N verfügbare Threads enthält. Diese NIO-Threads sind für das Lesen, Dekodieren, Codieren und Senden von Nachrichten verantwortlich.
Modellnummer des Master-Slave-Reaktors mit mehreren Threads
Der Server ist nicht mehr ein separater NIO-Thread zum Empfangen von Client-Verbindungen, sondern ein unabhängiger NIO-Thread-Pool.
Nachdem der Akzeptor die TCP-Verbindungsanforderung des Clients empfangen und die Verarbeitung abgeschlossen hat (einschließlich Zugriffsauthentifizierung usw.), registriert er den neu erstellten SocketChannel bei einem E/A-Thread im E/A-Thread-Pool (Sub-Reaktor-Thread-Pool), für den er verantwortlich ist Lesen und Schreiben der SocketChannel- und Codec-Arbeit.
Der Acceptor-Thread-Pool wird nur für die Client-Anmeldung, den Handshake und die Sicherheitsauthentifizierung verwendet. Sobald die Verbindung erfolgreich hergestellt wurde, wird die Verbindung beim E/A-Thread des Back-End-SubReactor-Thread-Pools registriert und der E/A-Thread ist für nachfolgende E/A-Vorgänge verantwortlich .
Sperrfreies Design, Fadenbindung
Netty verwendet ein serielles, sperrfreies Design und führt serielle Vorgänge innerhalb von 10 Threads aus, um Leistungseinbußen durch Multithread-Konkurrenz zu vermeiden.
Mehrere serialisierte Threads können parallel gestartet werden. Dieses lokal sperrenfreie serielle Thread-Design bietet eine bessere Leistung als ein Warteschlangen-Multiple-Worker-Thread-Modell.
Hochleistungs-Serialisierungs-Framework
1.SO RCVBUF und SO SNDBUF
Allgemein empfohlene Werte sind 128K oder 256K.
2.SO TCPNODELAY:
Kleine Pakete kapseln große Pakete, um eine Überlastung des Netzwerks zu verhindern
3. Soft-Interrupt: Nach dem Einschalten von RPS kann ein Soft-Interrupt implementiert werden, um den Netzwerkdurchsatz zu verbessern.
Soft-Interrupt-Hashwert-CPU-Bindung
Netty RPC-Implementierung
RPC-Konzept
Rufen Sie einen Dienst auf einem Remotecomputer genauso auf wie einen lokalen Dienst.
RPC kann Systeme sehr gut entkoppeln. WebService ist beispielsweise ein RPC, der auf dem HTTP-Protokoll basiert.
Schlüsseltechnologie
1. Dienstveröffentlichung und -abonnement: Der Server verwendet Zookeeper, um die Dienstadresse zu registrieren, und der Client erhält die verfügbare Dienstadresse von Zookeeper.
2. Kommunikation: Verwenden Sie Netty als Kommunikationsrahmen.
3.Spring: Verwenden Sie Spring, um Dienste zu konfigurieren, Beans zu laden und Anmerkungen zu scannen.
4. Dynamischer Proxy: Der Client verwendet den Proxy-Modus, um Dienste transparent aufzurufen.
5. Kodierung und Dekodierung von Nachrichten: Verwenden Sie Protostuff, um Nachrichten zu serialisieren und zu deserialisieren.
Kernprozess
1. Der Dienstkonsument (Client) ruft den Dienst über Ortsanrufe auf.
2. Nach Erhalt des Anrufs ist der Client-Stub dafür verantwortlich, Methoden, Parameter usw. zu einem Nachrichtentext zusammenzustellen, der über das Netzwerk übertragen werden kann.
3. Der Client-Stub findet die Dienstadresse und sendet die Nachricht an den Server.
4. Der Server-Stub dekodiert die Nachricht nach dem Empfang.
5. Der Server-Stub ruft basierend auf den Decodierungsergebnissen lokale Dienste auf.
6. Der lokale Dienst wird ausgeführt und die Ergebnisse werden an den Server-Stub zurückgegeben.
7. Der Server-Stub verpackt die zurückgegebenen Ergebnisse in Nachrichten und sendet sie an den Verbraucher;
8. Der Client-Stub empfängt die Nachricht und dekodiert sie;
9. Der Servicekonsument erhält das Endergebnis.
Nachrichtencodec
Nachrichtendatenstruktur (Schnittstellenname, Methodenname, Parametertyp und Parameterwert, Timeout-Anforderungs-ID).
1. Schnittstellenname: In unserem Beispiel lautet der Schnittstellenname „HelloWorldService“. Wenn er nicht übergeben wird, weiß der Server nicht, welche Schnittstelle er aufrufen soll.
2. Methodenname: Eine Schnittstelle kann viele Methoden enthalten. Wenn der Methodenname nicht übergeben wird, weiß der Server nicht, welche Methode er aufrufen soll.
3. Parametertypen und Parameterwerte: Es gibt viele Parametertypen, z. B. bool int, long, double, string, map, list und sogar struct (Klasse);
4. Zeitüberschreitung:
5.requestID, identifiziert die eindeutige Anforderungs-ID. Die Verwendung von requestID wird im folgenden Abschnitt ausführlich beschrieben.
6. Die vom Server zurückgegebene Nachricht enthält im Allgemeinen den folgenden Inhalt. Rückgabewert-Statuscode-RequestID
Serialisierung
planen
Protobuf
Vorteil
Leistung
kleines Volumen
Nach der Serialisierung kann die Datengröße um etwa das Dreifache reduziert werden
Die Serialisierung ist schnell
20-100-mal schneller als XML und JSON
Schnelle Übertragungsgeschwindigkeit
Aufgrund seiner geringen Größe werden Bandbreite und Übertragungsgeschwindigkeit optimiert.
Verwendung
Einfach zu benutzen
Der Proto-Compiler serialisiert und deserialisiert automatisch
Geringe Wartungskosten
Mehrere Plattformen müssen nur einen Satz von Objektprotokolldateien (.proto) verwalten.
Gute Abwärtskompatibilität
Das heißt, gute Skalierbarkeit: Die Datenstruktur kann direkt aktualisiert werden, ohne das alte Datenformat zu zerstören.
Gute Verschlüsselung
Bei der Erfassung von HTTP-Übertragungsinhalten können nur Bytes angezeigt werden
Anwendungsbereich
Plattformübergreifend
sprachenübergreifend
Gute Skalierbarkeit
Mangel
Funktionale Aspekte
Nicht geeignet für die Erstellung mit textbasierten Markup-Dokumenten (z. B. HTML), da Text nicht zur Beschreibung von Datenstrukturen geeignet ist.
andere Aspekte
Weniger vielseitig
Json und XML sind in vielen Branchen zu Standard-Schreibwerkzeugen geworden, während Protobuf nur ein intern von Google verwendetes Werkzeug ist.
Schlechte Selbsterklärung
Im binären Datenstrommodus (nicht lesbar) gespeichert, müssen Sie die .proto-Datei durchgehen, um die Datenstruktur zu verstehen
Zusammenfassen
Protocol Buffer ist kleiner, schneller und einfacher zu verwenden und zu warten als XML und Json!
Sparsamkeit
Avro
Kommunikationsprozess
requestID generation-AtomicLong
Speichern Sie den Callback-Objektrückruf in der globalen ConcurrentHashMap
synchronisiert erhält die Sperre des Callback-Objekts Callback und dreht Wait
Der auf die Nachricht wartende Thread empfängt die Nachricht, findet die Sperre für den Rückruf und wacht auf
RMI-Implementierung
1. Schreiben Sie eine Remote-Service-Schnittstelle, die die java.rmi.Remote-Schnittstelle erben muss, und die Methode muss eine java.rmi.RemoteException-Ausnahme auslösen.
2. Schreiben Sie eine Remote-Schnittstellen-Implementierungsklasse, die die Klasse java.rmi.server.UnicastRemoteObject erben muss.
3. Führen Sie den RMI-Compiler (rmic) aus und erstellen Sie die Client-Stub-Klasse und die Server-Skelettklasse.
4. Starten Sie eine RMI-Registrierung, um diese Dienste zu hosten.
5. Registrieren Sie den Dienst in der RMI-Registrierung.
6. Der Client sucht nach Remote-Objekten und ruft Remote-Methoden auf.
Sprachenübergreifendes RPC-Framework
Hessisch
Apache Thrift
gRPC
Hprosa
Service Governance RPC-Framework
Dubbo
Komposition
Anbieter
Verbraucher
Registrierung
Monitor
Unterstützte Container
Frühling
Anlegestelle
Log4j
Wieder anmelden
Unterstützte Protokolle
Dubbo (Standard)
RMI
hessisch
Internetservice
http
Sparsamkeit
Unterstützte Register
Tierpfleger
redis
Multicast
einfach
Service-Governance
Lastverteilung
Konfigurierbares Gewicht
Konsistentes Hashing
minimale Aktivität
....
Aufbau
Die Registry unterstützt lokales Caching (im Dateisystem zwischengespeichert)
DubboX
JSF
Motan
Datenbank
Speicher-Engine
Hash-Speicher-Engine
Unterstützt Hinzufügungs-, Lösch-, Änderungs- und Zufallslesevorgänge, unterstützt jedoch kein sequentielles Scannen. Das entsprechende Speichersystem ist ein Schlüsselwertspeichersystem.
Repräsentative Datenbanken: Redis, Memcache, Speichersystem Bitcask
B-Tree-Speicher-Engine
Unterstützt nicht nur das zufällige Lesen, sondern auch das Bereichsscannen
LSM-Baum-Speicher-Engine (Log-Structured Merge Tree).
Verteilte Datenbank
HBase
Überblick
Ausgehend von BigTable
BigTable ist ein verteiltes Speichersystem, das das von Google vorgeschlagene verteilte parallele Rechenmodell MapReduce zur Verarbeitung großer Datenmengen verwendet, das verteilte Dateisystem GFS von Google als zugrunde liegende Datenspeichermethode verwendet und Chubby zur Bereitstellung von Systemverwaltungsdiensten verwendet, die erweitert werden können PB-Ebene und Tausende von Maschinen zeichnen sich durch breite Anwendbarkeit, Skalierbarkeit, hohe Leistung und hohe Verfügbarkeit aus.
BigTable verfügt über die folgenden Funktionen:
Unterstützen Sie umfangreiche Datenmengen
Die verteilte gleichzeitige Datenverarbeitung ist äußerst effizient
Einfache Erweiterung und Unterstützung dynamischer Skalierung
Gut für günstige Geräte
Geeignet für Lesevorgänge, jedoch nicht für Schreibvorgänge
Einführung in HBase
HBase verwendet Hadoop Mapreduce, um große Datenmengen in HBase zu verarbeiten und Hochleistungsrechnen zu erreichen.
Verwenden Sie Zookeeper als kollaborativen Dienst, um einen stabilen Dienst und eine Wiederherstellung nach Fehlern zu erreichen.
Verwenden Sie HDFS als äußerst zuverlässigen zugrunde liegenden Speicher und nutzen Sie kostengünstige Cluster, um umfangreiche Datenspeicherfunktionen bereitzustellen.
Um die Datenverarbeitung auf HBase zu erleichtern, stellt Sqoop HBase eine effiziente und praktische Datenimportfunktion für relationale Datenbankverwaltungssysteme zur Verfügung.
HBase ist eine Open-Source-Implementierung von BigTable
Die zugrunde liegende technische Entsprechung zwischen HBase und BigTable:
Beziehungsanalyse zwischen HBase und traditionellen relationalen Datenbanken
HBase ist ein sehr ausgereiftes und stabiles Datenbankverwaltungssystem. Es verfügt normalerweise über Funktionen wie festplattenorientierte Speicher- und Indexstruktur, Multithread-Zugriff, sperrenbasierten synchronisierten Zugriffsmechanismus, protokollbasierten Wiederherstellungsmechanismus und Transaktionsmechanismus usw.
Der Unterschied zwischen HBase und herkömmlichen relationalen Datenbanken spiegelt sich hauptsächlich in den folgenden Aspekten wider:
Art der Daten
Datenoperationen
Speichermodus
Datenindex
Datenwartung
Skalierbarkeit
Hbase-Zugriffsschnittstelle
Typ: Native Java-API
Merkmale: Konventionelle und effiziente Zugriffsmethoden
Verwendungsmöglichkeiten: Geeignet für die parallele Stapelverarbeitung von HBase-Tabellendaten durch Hadoop MapReduce-Jobs
Typ: HBase-Shell
Features: HBase-Befehlszeilentool, einfache Schnittstelle
Verwendungszwecke: Geeignet für die HBase-Verwaltung
Typ: Thrift Gateway
Funktionen: Nutzt die Thrift-Serialisierungstechnologie zur Unterstützung von C, PHP, Python und anderen Sprachen
Verwendungsmöglichkeiten: Geeignet für andere heterogene Systeme, um online auf HBase-Tabellendaten zuzugreifen
Typ: REST-Gateway
Funktionen: Sprachbeschränkungen entfernen
Verwendungsmöglichkeiten: Unterstützt die HTTP-API im REST-Stil für den Zugriff auf Hbase
Typ: Schwein
Funktionen: Verwenden Sie die Streaming-Programmiersprache Pig Latin, um Daten in HBase zu verarbeiten
Verwendungsmöglichkeiten: geeignet für Datenstatistiken
Typ: Bienenstock
Eigenschaften: Einfach
Verwendungszwecke: Wenn Sie auf SQL-ähnliche Weise auf HBase zugreifen müssen
HBase-Datenmodell
Übersicht über das Datenmodell
HBase ist eine spärliche, mehrdimensionale, geordnete Zuordnungstabelle. Der Index dieser Tabelle umfasst Zeilenschlüssel, Spaltenfamilien, Spaltenqualifizierer und Zeitstempel.
Datenmodellbezogene Konzepte
Oberfläche
HBase verwendet Tabellen zum Organisieren von Daten. Tabellen bestehen aus Zeilen und Spalten, und Spalten sind in mehrere Spaltenfamilien unterteilt.
Zeilenschlüssel
Jede HBase-Tabelle besteht aus mehreren Zeilen und jede Spalte wird durch einen Spaltenschlüssel (Zeilenschlüssel) identifiziert.
Clans
Eine HBase-Tabelle ist in eine Sammlung von „Spaltenfamilien“ gruppiert, die die Grundeinheit der Zugriffskontrolle bilden.
Spaltenqualifizierer
Daten innerhalb einer Spaltenfamilie werden durch Spaltenqualifizierer (oder Spalten) lokalisiert.
Zelle
In einer HBase-Tabelle wird eine Zelle (Zelle) durch Zeilenschlüssel, Spaltenfamilie und Spaltenqualifizierer bestimmt.
Zeitstempel
Jede Zelle enthält mehrere Versionen derselben Daten, indexiert durch Zeitstempel.
Datenkoordinaten
HBase verwendet Koordinaten, um Daten in Tabellen zu lokalisieren, und auf jeden Wert wird über Koordinaten zugegriffen.
konzeptionelle Sicht
Aus der konzeptionellen Sicht von HBase kann eine Tabelle als eine spärliche, mehrdimensionale Zuordnungsbeziehung betrachtet werden.
physische Sicht
Aus konzeptioneller Sicht besteht jede Tabelle in HBase aus vielen Zeilen, aber auf der internen Speicherebene wird spaltenbasierter Speicher anstelle von zeilenbasiertem Speicher wie bei herkömmlichen relationalen Datenbanken verwendet. Dies ist auch ein wichtiger Unterschied zwischen HBase und herkömmlichen relationalen Datenbanken Datenbanken.
spaltenorientierte Speicherung
Durch die vorherige Diskussion wissen wir bereits, dass HBase ein spaltenorientierter Speicher und HBase eine „Spaltendatenbank“ ist.
HBase-Implementierungsprinzip
Funktionskomponenten von HBase
Bibliotheksfunktionen, verknüpft mit jedem Client.
Ein Master-Server (auch Master genannt).
Viele Regionsserver.
Tabellen und Regionen
In einer HBase werden viele Tabellen gespeichert. Jede Tabelle enthält nur eine Region, und da kontinuierlich Daten eingefügt werden, wächst die Region weiter.
Positionierung der Region
Eine HBase-Tabelle kann sehr groß und in viele Regionen aufgeteilt sein, die auf verschiedene Regionsserver verteilt werden können.
HBase-Betriebsmechanismus
HBase-Systemarchitektur
Klient
Zookeeper-Server
Master-Hauptserver
Regionsserver
So funktioniert der Regionsserver
Der Prozess, bei dem Benutzer Daten lesen und schreiben
Cache-Aktualisierung
StoreFile
So funktioniert Store
Der Regionsserver ist das Kernmodul von HBase, und Store ist der Kern des Regionsservers. Jeder Store entspricht der Speicherung einer Spaltenfamilie in der Tabelle. Jeder Store enthält einen MEMStore-Cache und mehrere StoreFile-Dateien.
So funktioniert HLog
In einer verteilten Umgebung müssen Systemfehler berücksichtigt werden. Wenn beispielsweise der Regionsserver ausfällt, gehen alle Daten im MEMStore-Cache (die nicht in die Datei geschrieben wurden) verloren. Daher verwendet HBase HLog, um sicherzustellen, dass das System bei einem Fehler in den Normalzustand zurückversetzt werden kann.
HBASE-Programmierpraxis
HBase verwendet häufig Shell-Befehle
HBase verwendet häufig verwendete Java-APIs und Anwendungsbeispiele
relationale Daten
MySQL
Indexoptimierung
Optimieren Sie den Index-Binär-Suchbaum
Merkmale
Alle Nicht-Blattknoten haben höchstens zwei untergeordnete Knoten
Jeder Knoten speichert einen Schlüssel
Der linke Zeiger eines Nicht-Blattknotens zeigt auf einen Teilbaum, der kleiner als sein Schlüssel ist, und der rechte Zeiger zeigt auf einen Teilbaum, der größer als sein Schlüssel ist.
MACHEN
Index optimieren B-Baum
Merkmale
Mehrweg-Suchbaum, nicht unbedingt binär
Definieren Sie jeden Blattknoten so, dass er höchstens M Söhne hat und M>2 ist;
Der untergeordnete Baum des Wurzelknotens ist [2,M]
Der untergeordnete Baum der Knoten außer dem Wurzelknoten ist [M/2,M]
Jeder Knoten speichert mindestens M/2-1 (aufgerundet) und höchstens M-1 Schlüsselwörter (mindestens 2 Schlüsselwörter);
Die Anzahl der Schlüsselwörter von Nicht-Blattknoten = die Anzahl der Zeiger auf untergeordnete Knoten - 1;
Schlüsselwörter für Nicht-Blattknoten: K[1], K[2], …, K[M-1] und K[i] < K[i 1];
Zeiger auf Nicht-Blattknoten:
P[1], P[2], …, P[M]; wobei P[1] auf einen Teilbaum mit einem Schlüssel kleiner als K[1] zeigt,
P[M] zeigt auf den Teilbaum, dessen Schlüssel größer als K[M-1] ist, und andere P[i] zeigen auf den Teilbaum, dessen Schlüssel zu (K[i-1], K[i]) gehört;
Alle Blattknoten befinden sich auf derselben Ebene.
Die B-Tree-Suche beginnt am Wurzelknoten und führt eine binäre Suche nach der Schlüsselwortsequenz (geordnet) innerhalb des Knotens If durch Wenn es getroffen wird, wird es beendet, andernfalls wird es in den untergeordneten Knoten des Bereichs eingegeben, zu dem das Abfrageschlüsselwort gehört. Wiederholen Sie dies, bis der entsprechende untergeordnete Zeiger leer ist oder bereits ein Blattknoten ist.
1. Der Schlüsselwortsatz wird im gesamten Baum verteilt. 2. Jedes Schlüsselwort kommt nur in einem Knoten vor; 3. Die Suche kann an einem Nicht-Blattknoten enden; 4. Die Suchleistung entspricht einer binären Suche im gesamten Schlüsselwortsatz. 5. Automatische Schichtsteuerung; Da andere Nicht-Blattknoten als der Wurzelknoten darauf beschränkt sind, mindestens M/2 Söhne zu enthalten, ist die minimale Auslastung des Knotens gewährleistet. Die niedrigste Suchleistung beträgt: Unter diesen ist M die maximale Anzahl von Teilbäumen, die für Nicht-Blattknoten festgelegt sind, und N ist die Gesamtzahl der Schlüsselwörter. Daher entspricht die Leistung des B-Baums immer der binären Suche (unabhängig vom M-Wert) und es gibt kein Problem mit dem B-Baum-Gleichgewicht. Aufgrund der Einschränkung von M/2 muss beim Einfügen eines Knotens, wenn der Knoten voll ist, der Knoten in zwei Knoten aufgeteilt werden, die jeweils M/2 belegen. Beim Löschen eines Knotens sind zwei Knoten erforderlich, die kleiner als M/2 sind Aufgeteilt werden. Geschwisterknoten werden zusammengeführt.
Optimierter Index-B-Baum
Merkmale
Ist eine Variante von B-Tree
Der Baumzeiger eines Nicht-Blattknotens entspricht der Anzahl der Schlüsselwörter
Der Teilbaumzeiger p[i] des Nicht-Blattknotens zeigt auf den Teilbaum, dessen Schlüsselwert zu [K[i], K[i 1]) gehört. Der B-Baum ist ein offenes Intervall.
Fügen Sie einen Linkzeiger zu allen Blattknoten hinzu
Alle Schlüsselwörter erscheinen in Blattknoten
B-Tree-Suchen treffen nur Blattknoten (B-Tree kann Nicht-Blattknoten treffen). Die Leistung entspricht einer binären Suche für den gesamten Satz von Schlüsselwörtern.
Alle Schlüsselwörter erscheinen in der verknüpften Liste der Blattknoten (dichter Index) und die verknüpfte Liste ist geordnet
Nicht-Blattknoten können nicht getroffen werden
Nicht-Blattknoten entsprechen dem Index von Blattknoten (Sparse-Index), und Blattknoten entsprechen der Datenschicht, in der Schlüsselwörter gespeichert werden.
Besser geeignet für Dateiindizierungssysteme
Die Abfrageeffizienz ist stabil
Der B*-Baum ist eine Variante des B-Baums mit weniger neuen Knoten und hoher Platzausnutzung.
Optimieren Sie Index-Hash und BitMap
Es können nur „=“ und „IN“ erfüllt werden und Bereichsabfragen können nicht verwendet werden.
Kann nicht zum Sortieren von Daten verwendet werden
Teilindexschlüssel können nicht für Abfragen verwendet werden
Dichte Indizes und spärliche Indizes
dichter Index
Jeder Indexcode in der dichten Indexdatei entspricht einem Indexwert
INNODB
Wenn ein Primärschlüssel definiert ist, wird der Primärschlüssel als dichter Index verwendet
Wenn kein Primärschlüssel definiert ist, wird der erste eindeutige, nicht leere Index der Tabelle als dichter Index verwendet.
Wenn kein Primärschlüssel und kein nicht leerer Index vorhanden ist, generiert innodb intern einen versteckten Primärschlüssel (dichten Index).
Der Nicht-Primärschlüsselindex speichert relevante Schlüsselbits und ihre entsprechenden Primärschlüsselwerte, einschließlich zweier Suchvorgänge
spärlicher Index
Sparse-Indexdateien erstellen nur Indexeinträge für bestimmte Werte des Indexcodes
MyISAM
Probleme bei der Indexoptimierung SQL optimieren
Überprüfen langsames Protokoll Langsames SQL positionieren
Verwenden Sie eine Show-Variable wie „%quer%“. Konfigurationsinformationen anzeigen
slow_query_log Öffnungsstatus des langsamen Abfrageprotokolls
setze global slow_query_log = ON
long_query_time Wie lange wird die langsame Abfragezeit geschrieben?
setze global long_query_time =1
slow_query_log_file Speicherort der langsamen Protokolldatei
Verwenden Sie „explain“ usw. Werkzeug SQL analysieren
erklären Hauptschlüsselwörter
AUSWEIS
Die Unterabfragesequenznummer der Auswahlabfrage stellt die Auswahlklausel oder die Reihenfolge der Operationstabelle dar. Bei gleicher ID erfolgt die Reihenfolge von oben nach unten. Wenn die IDs unterschiedlich sind, hat diejenige mit der größeren ID eine höhere Ausführungspriorität.
Art auswählen
Gibt den Typ der Abfrage an, der hauptsächlich zur Unterscheidung zwischen normalen Abfragen, gemeinsamen Abfragen, Unterabfragen und anderen komplexen Abfragen verwendet wird.
EINFACH
PRIMÄR
UNTERABFRAGE
ABGELEITET
UNION
GEWERKSCHAFTSERGEBNIS
Tisch
aktuelle Ausführungstabelle
mögliche_Schlüssel
Indizes, die in der aktuellen Tabelle vorhanden sind, müssen nicht unbedingt verwendet werden.
Schlüssel
Der tatsächlich verwendete Index bedeutet, dass der Index nicht verwendet wird (einschließlich, dass kein Index erstellt wurde oder dass der Index ungültig ist).
key_len
Die Anzahl der im Index verwendeten Bytes. Mithilfe dieser Spalte können Sie die in der Abfrage verwendete Indexlänge berechnen. Je kürzer die Länge, desto besser, ohne dass die Genauigkeit verloren geht. key_len stellt die maximal mögliche Länge des Indexfelds dar, nicht die tatsächliche Länge. Das heißt, key_len wird durch Tabellendefinition berechnet und nicht durch Tabellenabfrage erhalten.
ref
Gibt an, welche Spalte des Index verwendet wird, vorzugsweise eine Konstante, wenn möglich. Diese Spalten oder Konstanten werden verwendet, um den Wert in der Indexspalte zu finden.
Typ
Die Abfrage wurde vom besten zum schlechtesten sortiert
system>const>eq_ref>ref>fulltext>ref_or_null>index_merage>unique_subquery>index_subquery>range>index>all
Wenn index und all angezeigt werden, bedeutet dies, dass ein vollständiger Tabellenscan durchgeführt wird.
extral
extralWenn die folgende Situation auftritt, bedeutet dies, dass MYSQL den Index überhaupt nicht verwenden kann und die Effizienz stark beeinträchtigt wird. Optimieren Sie dies so weit wie möglich
Filesort verwenden
Gibt an, dass MYSQL eine externe Sortierung der Ergebnisse verwendet, anstatt den Inhalt aus der Tabelle in Indexreihenfolge zu lesen. Kann auf der Festplatte oder im Speicher sortiert werden. Der Sortiervorgang, der in MYSQL nicht mithilfe von Indizes abgeschlossen werden kann, wird als „Dateisortierung“ bezeichnet.
Temporär verwenden
Zeigt an, dass MYSQL temporäre Tabellen für Abfrageergebnisse verwendet. Wird häufig zum Sortieren nach und zum Gruppieren von Abfragen verwendet
Reihen
Schätzen Sie anhand der Tabellenstatistik und der Indexauswahl grob die Anzahl der Zeilen, die für die erforderliche Datensatzabfrage gelesen werden müssen. Je weniger Zeilen, desto besser.
Ändern Sie die SQL oder versuchen Sie, den SQL-Index zu erstellen
Grund für die Indexübereinstimmung ganz links
Prinzip des Abgleichs ganz links: MYSQL vergleicht immer rechts und stoppt den Abgleich, wenn es die Bereichsabfrage erreicht. Wenn Sie beispielsweise einen sequentiellen Index von a, b, c, d erstellen, werden die Bedingungen a=1 und b=2 und c>1 und d =2, d nicht verwendet. Wenn Sie einen sequentiellen Index abdc erstellen, abcd kann verwendet werden.
= und in können nicht in der richtigen Reihenfolge sein, und der MSQL-Abfrageoptimierer hilft Ihnen, den Index in eine erkennbare Form zu optimieren.
Grund
Die unterste Ebene des Index ist ein B-Baum. Natürlich ist der gemeinsame Index immer noch ein B-Baum, aber der Schlüsselwert des gemeinsamen Index ist nicht nur eins, sondern mehrere. Der Aufbau eines B-Baums kann nur auf der Grundlage eines Werts erfolgen, daher erstellt die Datenbank den B-Baum auf der Grundlage des Felds ganz links
Mehrere Matching-Situationen Wenn Sie einen gemeinsamen Index erstellen (ABC)
Vollständige Wertübereinstimmungsabfrage
Wählen Sie * aus Tabellenname aus, wobei a = '1' und b = '2' und c = '3' Wählen Sie * aus Tabellenname aus, wobei b = '2' und a = '1' und c = '3' Wählen Sie * aus Tabellenname aus, wobei c = '3' und b = '2' und a = '1' ...
Der verwendete Index und die Reihenfolge der Unterbedingungen haben keinen Einfluss auf die Ergebnisse. Der MySQL-Abfrageoptimierer optimiert automatisch die Abfragereihenfolge
Bei Übereinstimmung mit der Spalte ganz links
Wählen Sie * aus Tabellenname aus, wobei a = '1' Wählen Sie * aus Tabellenname aus, wobei a = '1' und b = '2' ist. Wählen Sie * aus Tabellenname aus, wobei a = '1' und b = '2' und c = '3'
Alles beginnt in der Spalte ganz links, kontinuierlicher Abgleich, unter Verwendung des Index
Wählen Sie * aus Tabellenname aus, wobei b = '2' ist. Wählen Sie * aus Tabellenname aus, wobei c = '3' Wählen Sie * aus Tabellenname aus, wobei b = '1' und c = '3' ist.
Keines davon beginnt ganz links. Die letzte Abfrage verwendet keinen Index und verwendet einen vollständigen Tabellenscan.
Wählen Sie * aus Tabellenname aus, wobei a = '1' und c = '3' ist.
Im diskontinuierlichen Zustand wird nur der Index von Spalte a und sowohl b als auch c verwendet.
übereinstimmen übereinstimmen nach vorne verschönert
select * from table_name where a like 'As%'; //Die Präfixe sind alle sortiert, verwenden Sie die Indexabfrage select * from table_name where a like '%As'//Full table query select * from table_name where a like '%As%'//Full table query
Wenn a ein Zeichentyp ist, besteht die Vergleichsregel darin, das erste Zeichen der Zeichenfolge zu vergleichen. Wenn das erste Zeichen gleich ist, wird das zweite Zeichen verglichen bald. Daher verwendet der Präfixabgleich den Index und der Suffixabgleich und der Infixabgleich den vollständigen Tabellenscan.
übereinstimmen übereinstimmen Lüfter umgeben Wert
Wählen Sie * aus Tabellenname aus, wobei a > 1 und a < 3
Sie können Bereichsabfragen für die Spalte ganz links durchführen und den Index verwenden
Wählen Sie * aus Tabellenname aus, wobei a > 1 und a < 3 und b > 1;
Bei der Abfrage in einem mehrspaltigen Bereich kann nur die Spalte a ganz links den Index für die Bereichsabfrage verwenden. Im Bereich 1<a<3 ist b ungeordnet und kann den Index nicht verwenden. Nachdem Sie die Datensätze 1<a<3 gefunden haben, können Sie sie nur einzeln gemäß der Bedingung b>1 filtern.
Passen Sie eine Spalte genau an und suchen Sie nach einer Spalte
Wählen Sie * aus Tabellenname aus, wobei a = 1 und b > 3;
Wenn a = 1 ist, ist b geordnet und die Bereichsabfrage verwendet den gemeinsamen Index.
Sortieren
Unter normalen Umständen verwendet MySQL die Dateisortierung, die relativ langsam ist. Wenn ein Index in der Reihenfolge vorhanden ist, kann der Schritt der Dateisortierung weggelassen werden.
select * from table_name order by a,b,c limit 10;
Index verwenden
select * from table_name order by b,c,a limit 10;
Kehren Sie die Reihenfolge um, ohne den Index zu verwenden
select * from table_name order by a limit 10; select * from table_name order by a,b limit 10;
Teilindex verwenden
select * from table_name where a =1 order by b,c limit 10;
Die Spalte ganz links im gemeinsamen Index ist eine Konstante und der Index kann für die nachfolgende Sortierung verwendet werden.
Datenlesen und Transaktionsisolierung
Probleme, die durch den Isolationsmechanismus für Parallelität und Transaktion des Sperrmoduls verursacht werden
Update verloren
Alle Transaktionsisolationsstufen von MySQL können auf Datenbankebene vermieden werden
schmutzige Lektüre
Die Transaktionsisolationsstufe READ_COMMITTED und höher kann vermieden werden
Die Erzeugung von Dirty Reads
Unter der Transaktionsisolationsstufe READ_UNCOMMITTED ändern zwei Transaktionen gleichzeitig dieselbe Zeile. Sobald in einer der Transaktionen ein ROLLBACK auftritt, führt dies dazu, dass die andere Transaktion einen Dirty Read generiert. (Transaktion A hat die Daten gelesen, die Transaktion B nicht senden konnte, und die tatsächlichen Daten wurden zurückgesetzt.)
nicht wiederholbares Lesen
nicht wiederholbare Lesegenerierung
Transaktion A liest eine Datensatzzeile mehrmals, und Transaktion B und Transaktion C ändern diese Datensatzzeile. Nachdem Transaktion B und Transaktion C die Transaktion übermittelt haben, hat Transaktion A zu diesem Zeitpunkt noch keine Transaktion B übermittelt nach dem anderen und nach der Übermittlung durch Transaktion C. Der Datensatz dieser Zeile wurde geändert und der gelesene Datensatz ist unterschiedlich.
Phantomlesung
Es kommt zu Phantomlesungen
Transaktion A liest mehrere Datenzeilen, indem sie die Ergebnismenge von Transaktion A durch Einfügen/Löschen ändert. Es ist wie eine Illusion (Datensätze, die nicht angezeigt werden sollten). )
Aktueller Lesevorgang und Snapshot-Lesevorgang
liest gerade
Wählen Sie *** im Freigabemodus sperren, wählen Sie *** für die Aktualisierung
aktualisieren, löschen, einfügen
Schnell finden und lesen
Nicht blockierendes Lesen ohne Sperren, auswählen
So implementieren Sie nicht blockierendes Lesen in InnoDB auf RC- und RR-Ebene
Felder DB_TRX_ID, DB_ROLL_PTR, DB_ROW_ID in der Datenzeile
Protokoll rückgängig machen
Leseansicht
So vermeiden Sie Phantomlesungen in RR
InnoDB fügt eine GAP-Sperre für den nächsten Schlüssel hinzu, um Phantom-Lesevorgänge zu vermeiden
Wird die GAP-Sperre für den Primärschlüsselindex oder den eindeutigen Index verwendet?
Wenn alle Where-Bedingungen erfüllt sind, wird die GAP-Sperre nicht verwendet und nur die Datensatzsperre hinzugefügt.
Unter der RR-Isolationsstufe werden Lückensperren in nicht eindeutigen Indizes oder in aktuellen Lesevorgängen verwendet, die den Index nicht durchlaufen.
erklärenAnalyse und Optimierung
Art auswählen (Typ jeder Select-Klausel in der Abfrage)
(1) SIMPLE (einfaches SELECT, keine UNION oder Unterabfrage usw.)
(2) PRIMÄR (wenn die Abfrage komplexe Unterteile enthält, wird die äußerste Auswahl als PRIMÄR markiert)
(3) UNION (die zweite oder nachfolgende SELECT-Anweisung in UNION)
(4) DEPENDENT UNION (die zweite oder nachfolgende SELECT-Anweisung in UNION, abhängig von der externen Abfrage)
(5) UNION-ERGEBNIS (das Ergebnis von UNION)
(6) SUBQUERY (das erste SELECT in der Unterabfrage)
(7) ABHÄNGIGE UNTERABFRAGE (das erste SELECT in der Unterabfrage, hängt von der äußeren Abfrage ab)
(8) DERIVED (SELECT der abgeleiteten Tabelle, Unterabfrage der FROM-Klausel)
(9) UNCACHEABLE UNTERABFRAGE (die Ergebnisse einer Unterabfrage können nicht zwischengespeichert werden und die erste Zeile des externen Links muss neu ausgewertet werden)
Typ (Die Art und Weise, wie MySQL die erforderliche Zeile in einer Tabelle findet, Auch bekannt als „Zugriffstyp“)
ALLE: Vollständiger Tabellenscan. MySQL durchsucht die gesamte Tabelle, um übereinstimmende Zeilen zu finden
Index: Vollständiger Index-Scan. Der Unterschied zwischen Index und ALL besteht darin, dass der Indextyp nur den Indexbaum durchläuft
Bereich: Rufen Sie nur Zeilen in einem bestimmten Bereich ab und verwenden Sie einen Index zum Auswählen von Zeilen (Alibaba benötigt am wenigsten).
ref: Gibt die Verbindungsübereinstimmungsbedingungen der obigen Tabelle an, dh welche Spalten oder Konstanten verwendet werden, um den Wert in der Indexspalte zu finden (Alibaba empfiehlt, dies am besten zu erreichen).
eq_ref: Ähnlich wie bei ref besteht der Unterschied darin, dass der verwendete Index ein eindeutiger Index ist und nur ein Datensatz in der Tabelle übereinstimmt. Vereinfacht ausgedrückt wird der Primärschlüssel oder der eindeutige Schlüssel als Zuordnungsbedingung verwendet Mehrtabellenverbindungen.
const, system: Diese Typen werden verwendet, wenn MySQL einen bestimmten Teil der Abfrage optimiert und in eine Konstante konvertiert. Wenn der Primärschlüssel in der Where-Liste steht, kann MySQL die Abfrage in eine Konstante umwandeln. Wenn die abgefragte Tabelle nur eine Zeile hat, verwenden Sie system
NULL: MySQL zerlegt die Anweisung während des Optimierungsprozesses und muss während der Ausführung nicht einmal auf die Tabelle oder den Index zugreifen. Beispielsweise kann die Auswahl des Mindestwerts aus einer Indexspalte durch eine separate Indexsuche erfolgen.
mögliche_Schlüssel
Welchen Index kann MySQL verwenden, um Datensätze in der Tabelle zu finden? Wenn für das an der Abfrage beteiligte Feld ein Index vorhanden ist, wird der Index aufgelistet, aber möglicherweise nicht von der Abfrage verwendet.
Schlüssel
Die Schlüsselspalte zeigt den Schlüssel (Index), den MySQL tatsächlich verwendet hat.
key_len
Gibt die Anzahl der im Index verwendeten Bytes an. Die Länge des in der Abfrage verwendeten Index kann über diese Spalte berechnet werden (der von key_len angezeigte Wert ist die maximal mögliche Länge des Indexfelds, nicht die tatsächlich verwendete Länge. key_len wird basierend auf der Tabellendefinition berechnet und nicht aus der Tabelle abgerufen), ohne an Genauigkeit zu verlieren. Je kürzer die Länge, desto besser
ref
Die Join-Übereinstimmungsbedingung der obigen Tabelle, dh welche Spalten oder Konstanten verwendet werden, um den Wert in der Indexspalte zu finden
Reihen
MySQL schätzt anhand von Tabellenstatistiken und Indexauswahl die Anzahl der Zeilen, die gelesen werden müssen, um die erforderlichen Datensätze zu finden.
Extra
Mit where: werden Spaltendaten aus einer Tabelle zurückgegeben, die nur die Informationen im Index verwendet, ohne die eigentliche Aktion zu lesen. Dies geschieht, wenn alle angeforderten Spalten für die Tabelle Teil desselben Index sind, was darauf hinweist, dass der MySQL-Server nach den Zeilen filtert werden von der Speicher-Engine abgerufen
Temporär verwenden: Zeigt an, dass MySQL temporäre Tabellen zum Speichern von Ergebnismengen verwenden muss, was bei Sortier- und Gruppierungsabfragen üblich ist.
(Wenn die beiden oben genannten roten Punkte „Temporär verwenden“ und „Dateisortierung verwenden“ angezeigt werden, bedeutet dies eine geringe Effizienz.)
Join-Puffer verwenden: Der geänderte Wert betont, dass beim Abrufen der Join-Bedingung kein Index verwendet wird und ein Join-Puffer zum Speichern von Zwischenergebnissen erforderlich ist. Wenn dieser Wert angezeigt wird, sollten Sie beachten, dass Sie je nach den spezifischen Bedingungen der Abfrage möglicherweise einen Index hinzufügen müssen, um die Leistung zu verbessern.
Unmögliches Where: Dieser Wert betont, dass die Where-Anweisung keine qualifizierenden Zeilen ergibt.
Verwenden von Filesort: Der Sortiervorgang, der in MySQL nicht mithilfe von Indizes durchgeführt werden kann, wird als „Dateisortierung“ bezeichnet.
Wegoptimierte Tabellen auswählen: Dieser Wert bedeutet, dass der Optimierer bei alleiniger Verwendung des Index möglicherweise nur eine Zeile aus dem Ergebnis der Aggregatfunktion zurückgibt
MySQL-Tuning
Felddesign
Versuchen Sie, Ganzzahlen zur Darstellung von Zeichenfolgen zu verwenden
Wählen Sie kleine Datentypen und geben Sie nach Möglichkeit kurze Längen an
Verwenden Sie nach Möglichkeit nicht null
Eine einzelne Tabelle sollte nicht zu viele Felder haben
Felder können reserviert werden
Normales Format
Erste Normalform 1NF: Feldatomizität
Zweite Normalform: Teilweise Abhängigkeit von Primärschlüsseln beseitigen
Dritte Normalform: Eliminieren Sie die transitive Abhängigkeit von Primärschlüsseln
Abfragecache
Es ist my.ini unter Windows und my.cnf unter Linux.
0: Nicht aktiviert
1: Aktivieren, alles standardmäßig zwischenspeichern, select sql-no-cache zur SQL-Anweisung hinzufügen, um den Cache zu verlassen
2: Aktivieren, standardmäßig kein Caching, fügen Sie select sql-cache zur SQL-Anweisung hinzu, um aktiv zwischenzuspeichern (häufig verwendet)
Problem mit der Cache-Ungültigmachung
Wenn die Datentabelle geändert wird, wird jeder auf der Datentabelle basierende Cache gelöscht.
Partition
Nur wenn das Suchfeld ein Partitionsfeld ist, wird die durch die Partitionierung erzielte Effizienzsteigerung deutlicher.
Horizontal und vertikal teilen
Horizontale Aufteilung: Speichern Sie Daten getrennt, indem Sie mehrere Tabellen mit derselben Struktur erstellen
Vertikale Aufteilung: Häufig verwendete Felder werden in einer separaten Tabelle zusammengefasst. Zwischen den geteilten Tabellendatensätzen besteht eine Eins-zu-eins-Entsprechung.
Typische Serverkonfiguration
max_connections, maximale Anzahl von Clientverbindungen
Variablen wie „max_connections“ anzeigen
table_open_cache, Tabellendatei-Handle-Cache
key_buffer_size, Index-Cache-Größe
innodb_buffer_pool_size, Größe des Innodb-Speicher-Engine-Cache-Pools
innodb_file_per_table
Stresstest-Tools
mysqlslap
Fehlerbehebung
Verwenden Sie den Befehl show Processlist, um alle aktuellen Verbindungsinformationen anzuzeigen
Verwenden Sie den Befehl EXPLAIN, um den Ausführungsplan der SQL-Anweisung abzufragen
Aktivieren Sie das Protokoll für langsame Abfragen und zeigen Sie die langsame SQL-Abfrage an
NoSQL
MongoDB
Erste Schritte mit MongoDB
Analyse von Nosql- und SQL-Nutzungsszenarien
grundlegendes Konzept
mongodb fortgeschritten
Allgemeine Befehle
Schnellstart
Mongodo-Client-Treiber
Hinzufügen, Löschen, Ändern, Suchen und Aggregieren
sicher kontrollieren
Fortgeschrittene Kenntnisse in Mongodb
Speicher-Engine
Index
Hohe Verfügbarkeit
Best Practices und Überlegungen
Datenstruktur
Stapel
Ein Stapel ist eine Tabelle, die das Einfügen und Löschen auf nur eine Position beschränkt. Diese Position ist das Ende der Tabelle und wird als oberste Position des Stapels bezeichnet.
Es gilt das Last-In-First-Out-Prinzip (LIFO). Es gibt nur zwei grundlegende Operationen auf dem Stapel: Push (in den Stapel) und Pop (aus dem Stapel). Ersteres entspricht dem Einfügen und letzteres entspricht dem Löschen des letzten Elements.
Warteschlange
Eine Warteschlange ist eine spezielle lineare Tabelle. Das Besondere daran ist, dass sie nur Löschvorgänge am vorderen Ende der Tabelle (vorne) und Einfügevorgänge am hinteren Ende (hinten) der Tabelle zulässt.
Eine Warteschlange ist eine lineare Liste mit eingeschränkten Operationen. Das Ende, das den Einfügevorgang ausführt, wird als Ende der Warteschlange bezeichnet, und das Ende, das den Löschvorgang ausführt, wird als Kopf der Warteschlange bezeichnet.
Verknüpfung
Eine verknüpfte Liste ist eine Datenstruktur auf derselben Ebene wie ein Array. Beispielsweise wird die ArrayList, die wir in Java verwenden, basierend auf einem Array implementiert.
Das Implementierungsprinzip von Linkedlist ist eine verknüpfte Liste.
Verknüpfte Listen sind beim Schleifendurchlauf nicht effizient, bieten aber beim Einfügen und Löschen offensichtliche Vorteile.
Hash-tabelle
Die Hash-Tabelle (auch Hash-Tabelle genannt) ist ein Suchalgorithmus, der bei der Suche keine Schlüsselwörter (Schlüsselwörter sind bestimmte Elemente in den Datenelementen) erfordert ein Datenelement, das zur Identifizierung eines Datenelements verwendet wird) Vergleichsvorgang.
Der Hash-Tabellenalgorithmus hofft, das gesuchte Datenelement durch einen einzigen Zugriff ohne Vergleich zu erhalten. Daher muss eine Bestimmung zwischen dem Speicherort des Datenelements und seinem Schlüsselwort (das durch einen Schlüssel dargestellt werden kann) hergestellt werden. Durch die entsprechende Beziehung entspricht jedes Schlüsselwort einem eindeutigen Speicherort in der Hash-Tabelle.
Methoden zum Erstellen von Hash-Funktionen sind:
(1) Direkte Adressierungsmethode: Nehmen Sie das Schlüsselwort oder einen linearen Funktionswert des Schlüsselworts als Hash-Adresse.
Das heißt: h(key) = key oder h(key) = a* key b wobei a und b Konstanten sind.
(2) Digitale Analysemethode
(3) Quadratwertmethode: Nehmen Sie die mittleren Ziffern nach der Quadrierung des Schlüsselworts als Hash-Adresse.
(4) Faltmethode: Teilen Sie das Schlüsselwort in mehrere Teile mit der gleichen Anzahl von Ziffern und verwenden Sie dann die Überlagerungssumme dieser Teile als Hash-Adresse.
(5) Division mit Restmethode: Der Rest, der erhalten wird, nachdem das Schlüsselwort durch eine Zahl p geteilt wird, die nicht größer als die Hash-Tabellenlänge m ist, ist die Hash-Adresse.
Das heißt: h(key) = key MOD p ps m
(6) Zufallszahlenmethode: Wählen Sie eine Zufallsfunktion und verwenden Sie den Zufallsfunktionswert des Schlüsselworts als Hash-Adresse.
Das heißt: h(key) = random(key)
sortierter Binärbaum
Jeder Knoten des sortierten Binärbaums erfüllt:
Alle Knotenwerte im linken Teilbaum sind kleiner als der Wert seines Wurzelknotens.
Und der Wert aller Knoten im rechten Teilbaum ist größer als der Wert seines Wurzelknotens
Einfügevorgang
Beginnen Sie zunächst am Stammknoten und suchen Sie die Position, die Sie einfügen möchten (dh den übergeordneten Knoten des neuen Knotens). Der spezifische Vorgang lautet: Vergleichen Sie den neuen Knoten mit dem aktuellen Knoten Sie sind bereits vorhanden und können nicht erneut eingefügt werden. Wenn sie kleiner als der aktuelle Knoten sind, suchen Sie im linken Teilbaum. Wenn der linke Teilbaum leer ist, ist der aktuelle Knoten der gesuchte übergeordnete Knoten und der neue Knoten in den linken Teilbaum des aktuellen Knotens eingefügt; wenn er größer als der aktuelle Knoten ist, suchen Sie im rechten Teilbaum. Wenn der rechte Teilbaum leer ist, ist der aktuelle Knoten der gesuchte übergeordnete Knoten, und der neue Knoten kann in den rechten Teilbaum des aktuellen Knotens eingefügt werden.
Vorgang löschen
Löschvorgänge werden hauptsächlich in drei Situationen unterteilt:
Der zu löschende Knoten hat keine untergeordneten Knoten
Der zu löschende Knoten hat nur einen untergeordneten Knoten
Der zu löschende Knoten hat zwei untergeordnete Knoten
1. Wenn der zu löschende Knoten keine untergeordneten Knoten hat, können Sie ihn direkt löschen, dh den untergeordneten Knoten des übergeordneten Knotens leer lassen.
2. Wenn der zu löschende Knoten nur einen untergeordneten Knoten hat, ersetzen Sie den zu löschenden Knoten durch seinen untergeordneten Knoten.
3. Wenn der zu löschende Knoten zwei untergeordnete Knoten hat, suchen Sie zuerst den Ersatzknoten des Knotens (dh den kleinsten Knoten im rechten Teilbaum), ersetzen Sie dann den zu löschenden Knoten durch den Ersatzknoten und löschen Sie ihn Ersatzknoten.
Abfragevorgang
Der Hauptprozess des Suchvorgangs ist:
Vergleichen Sie zuerst mit dem Wurzelknoten und kehren Sie zurück, wenn sie identisch sind.
Wenn er kleiner als der Wurzelknoten ist, suchen Sie rekursiv im linken Teilbaum.
Wenn er größer als der Wurzelknoten ist, suchen Sie rekursiv im rechten Teilbaum.
Daher ist es einfach, den Maximalwert (tiefster untergeordneter Knoten ganz rechts) und den minimalen Wert (tiefster untergeordneter Knoten ganz links) in einem sortierten Binärbaum zu ermitteln.
roter schwarzer Baum
Eigenschaften rotschwarzer Bäume
(1) Jeder Knoten ist entweder schwarz oder rot.
(2) Der Wurzelknoten ist schwarz.
(3) Jeder Blattknoten (NIL) ist schwarz. [Hinweis: Der Blattknoten bezieht sich hier auf den Blattknoten, der leer ist (N, L oder NULL)!
(4) Wenn ein Knoten rot ist, muss sein untergeordneter Knoten schwarz sein.
(5) Alle Pfade von einem Knoten zu den Nachkommenknoten des Knotens enthalten die gleiche Anzahl schwarzer Knoten.
Linkshändig
Linksdrehen × bedeutet, das „rechte Kind von x“ als „Vaterknoten von x“ festzulegen;
Daher bedeutet „links“ in der Linksdrehung „der gedrehte Knoten wird zu einem linken Knoten“.
LINKS DREHEN(T, x) y ← right[x] // Prämisse: Es wird angenommen, dass das rechte Kind von x y ist. Der offizielle Betrieb beginnt unten right[x] ← left[y] // Setze „ys linkes Kind“ auf „xs rechtes Kind“, d. h. setze β auf das rechte Kind von x p[left[y]] ← x // Setze „x“ auf „den Vater des linken Kindes von y“, d. h. setze den Vater von β auf x p[y] ← p[x] // Setze „xs Vater“ auf „ys Vater“ wenn p[x] = nil[T] then root[T] ← y // Fall 1: Wenn „x's Vater“ ein leerer Knoten ist, setze y als Wurzelknoten sonst wenn x = left[p[x]] then left[p[x]] ← y // Fall 2: Wenn x das linke Kind seines Elternteils ist, dann setze y auf „das linke Kind des Elternteils von x“ else right[p[x]] ← y // Fall 3: (x ist das rechte Kind seines Elternteils) Setze y auf „das rechte Kind des Elternteils von x“ left[y] ← x // Setze „x“ auf „ys linkes Kind“ p[x] ← y // Setze den „übergeordneten Knoten von x“ auf „y“
Rechtslauf
X nach rechts drehen bedeutet, das „linke Kind von x“ als „Vaterknoten von x“ festzulegen, d. h. x in einen rechten Knoten zu verwandeln (x wird zum rechten Kind von y)!
Daher bedeutet „rechts“ in der Rechtsdrehung „der gedrehte Knoten wird zu einem rechten Knoten“.
RECHTS DREHEN(T, y) x ← left[y] // Prämisse: Es wird angenommen, dass das linke Kind von y x ist. Der offizielle Betrieb beginnt unten left[y] ← right[x] // Setze „x's rechtes Kind“ auf „ys linkes Kind“, das heißt, setze β auf ys linkes Kind p[right[x]] ← y // Setze „y“ auf „den Vater des rechten Kindes von x“, d. h. setze den Vater von β auf y p[x] ← p[y] // Setze „ys Vater“ auf „xs Vater“ wenn p[y] = nil[T] then root[T] ← x // Fall 1: Wenn „ys Vater“ ein leerer Knoten ist, setze x als Wurzelknoten sonst wenn y = right[p[y]] then right[p[y]] ← x // Fall 2: Wenn y das rechte Kind seines Elternteils ist, dann setze x auf „das linke Kind von ys Elternteil“ else left[p[y]] ← x // Fall 3: (y ist das linke Kind seines Elternteils) Setze x auf „das linke Kind des Elternteils von y“ right[x] ← y // Setze „y“ auf das „rechte Kind von x“ p[y] ← x // Setze „ys übergeordneten Knoten“ auf „x“
Hinzufügen zu
Schritt 1: Behandeln Sie den Rot-Schwarz-Baum als binären Suchbaum und fügen Sie den Knoten ein.
Schritt 2: Färben Sie den eingefügten Knoten „rot“.
Schritt 3: Machen Sie ihn durch eine Reihe von Rotations- oder Färbevorgängen wieder zu einem rot-schwarzen Baum.
löschen
Schritt 1: Behandeln Sie den Rot-Schwarz-Baum als binären Suchbaum und löschen Sie die Knoten.
Dies ist dasselbe wie „Knoten in einem regulären binären Suchbaum löschen“. Es gibt 3 Situationen:
① Der gelöschte Knoten hat keine untergeordneten Knoten und ist ein Blattknoten. Dann ist es in Ordnung, den Knoten direkt zu löschen.
② Der gelöschte Knoten hat nur einen Sohn. Löschen Sie dann den Knoten direkt und ersetzen Sie seine Position durch den einzigen untergeordneten Knoten des Knotens.
③ Der gelöschte Knoten hat zwei Söhne. Suchen Sie dann zuerst seinen Nachfolgeknoten; kopieren Sie dann „den Inhalt seines Nachfolgeknotens“ in „den Inhalt dieses Knotens“ und löschen Sie dann „seinen Nachfolgeknoten“.
Schritt 2: Modifizieren Sie den Baum durch eine Reihe von „Rotationen und Neufärbungen“, um ihn wieder in einen rot-schwarzen Baum zu verwandeln.
Denn nach dem Löschen des Knotens im „ersten Schritt“ kann es zu einer Verletzung der Eigenschaften des Rot-Schwarz-Baums kommen. Der Baum muss also durch „Drehen und Umfärben“ korrigiert werden, um ihn wieder in einen rot-schwarzen Baum zu verwandeln.
Wählen Sie aus 3 Umfärbungsfällen.
① Situationsbeschreibung: x ist ein „rot-schwarzer“ Knoten.
Verarbeitungsmethode: x direkt auf Schwarz setzen und beenden. Zu diesem Zeitpunkt sind alle Eigenschaften des rot-schwarzen Baumes wiederhergestellt.
2⃣️Situationsbeschreibung: x ist ein „schwarzer“ Knoten und x ist die Wurzel.
Lösung: Nichts tun und Schluss machen. Zu diesem Zeitpunkt sind alle Eigenschaften des rot-schwarzen Baumes wiederhergestellt.
③ Beschreibung der Situation: x ist ein „schwarzer“ Knoten und x ist keine Wurzel.
B-BAUM
Der B-Baum wird auch als ausgeglichener Mehrpfad-Suchbaum bezeichnet. Die Eigenschaften eines B-Baums m-Ordnung (m-ary-Baum) sind wie folgt (wobei ceil(x) eine Obergrenzenfunktion ist):
1. Jeder Knoten im Baum hat höchstens m Kinder;
2. Mit Ausnahme des Wurzelknotens und der Blattknoten hat jeder andere Knoten mindestens ceil(m / 2) Kinder;
3. Wenn der Wurzelknoten kein Blattknoten ist, muss er mindestens zwei untergeordnete Knoten haben (Sonderfall: ein Wurzelknoten ohne untergeordnete Elemente, dh der Wurzelknoten ist ein Blattknoten und der gesamte Baum hat nur einen Wurzelknoten). ;
4. Alle Blattknoten erscheinen in derselben Ebene und Blattknoten enthalten keine Schlüsselwortinformationen (kann als externe Knoten oder Abfragen betrachtet werden).
Ausgefallene Knoten (tatsächlich existieren diese Knoten nicht und die Zeiger, die auf diese Knoten zeigen, sind null).
5. Jeder nichtterminale Knoten enthält n Schlüsselwortinformationen: (n, PO, K1, P1, K2, P2, Kn, Pn). In:
a) Ki(=1..n) ist das Schlüsselwort und die Schlüsselwörter werden in der Reihenfolge K(-1)<Ki sortiert.
b) Pi ist ein Knoten, der auf die Wurzel des Teilbaums zeigt, und der Zeiger P(-1) zeigt auf die Schlüssel aller Knoten im Teilbaum, die kleiner als Ki, aber größer als K(i-1) sind.
c) Die Anzahl der Schlüsselwörter n muss Folgendes erfüllen: ceil(m / 2)-1 <=n <=m-1.
Der Unterschied zwischen einem B-Baum der Ordnung m und einem B-Baum der Ordnung m ist:
1. Knoten mit n Teilbäumen enthalten n Schlüsselwörter (B-Baum besteht aus n Teilbäumen mit n-1 Schlüsselwörtern).
2. Alle Blattknoten enthalten Informationen zu allen Schlüsselwörtern und Verweise auf Datensätze, die diese Schlüsselwörter enthalten. Die Blattknoten selbst sind in der Reihenfolge von kleinen zu großen Schlüsselwörtern verknüpft. (Die Blattknoten des B-Baums enthalten nicht alle Informationen, die gefunden werden müssen)
3. Alle nichtterminalen Knoten können als Indexteil betrachtet werden, und der Knoten enthält nur das größte (oder kleinste) Schlüsselwort im Wurzelknoten seines Unterbaums. (Die nichtterminalen Knoten des B-Baums enthalten auch gültige Informationen, die gefunden werden müssen.)
Bitmap
Das Prinzip der Bitmap besteht darin, ein Bit zu verwenden, um zu identifizieren, ob eine Zahl vorhanden ist, und ein Bit zum Speichern eines Datenelements zu verwenden, sodass dadurch erheblich Platz gespart werden kann.
Bitmap ist eine sehr häufig verwendete Datenstruktur, wie sie beispielsweise im Bloom-Filter zum Sortieren sich nicht wiederholender Ganzzahlen usw. verwendet wird.
Bitmap wird normalerweise basierend auf einem Array implementiert. Jedes Element im Array kann als eine Reihe von Binärzahlen betrachtet werden, und alle Elemente bilden einen größeren Binärsatz.
Basiskonzept
Grundlegende Java-Konzepte
JDK und JRE
JDK ist das Java Development Kit, das die Tools, IDE und JRE enthält, die zum Kompilieren und Ausführen von Java erforderlich sind.
JRE ist eine Java-Laufzeitumgebung, einschließlich JVM (Java Virtual Machine) und einer Systemklassenbibliothek
Beziehungsdiagramm
JavaEE (Java Platform Enterprise Edition)
Enthält technische Standards
Applet
Ist ein Java-Programm. Es wird normalerweise in einem Java-fähigen Webbrowser ausgeführt
Applets sind für die Einbettung in eine HTML-Seite konzipiert
Wenn ein Benutzer eine HTML-Seite durchsucht, die ein Applet enthält, wird der Code des Applets auf den Computer des Benutzers heruntergeladen
EJB
JNDI
Java-Benennungs- und Verzeichnisschnittstelle
JDBC
Servlet
Ein Programm, das auf einem Webserver oder Anwendungsserver ausgeführt wird
Es fungiert als mittlere Schicht zwischen einer Datenbank oder Anwendung eines Webbrowsers und einem HTTP-Server
Vergleiche mit CGI
Bessere Leistung und Plattformunabhängigkeit
Führen Sie die Ausführung innerhalb des Adressraums des Webservers durch, wodurch die Notwendigkeit entfällt, einen separaten Prozess zur Bearbeitung jeder Client-Anfrage zu erstellen
Servlet ist vertrauenswürdig, da der Java-Sicherheitsmanager eine Reihe von Einschränkungen durchsetzt
Für Servlets steht die gesamte Funktionalität der Java-Klassenbibliothek zur Verfügung
Architekturdiagramm
Wirkung
Verwalten Sie vom Benutzer geschriebene Servlet-Klassen und -Objekte nach der Instanziierung
Stellen Sie einen HTTP-Dienst bereit, der einem vereinfachten Server entspricht
JSP
Java IDL (Interface Definition Language)/CORBA
XML
JMS (Java Message Service)
JTA (Java-Transaktionsarchitektur)
JTS (Java-Transaktionsdienst)
JavaMail
JAF (JavaBeans Activation Framework)
Einstufung
JavaWeb
Entwickeln Sie Webprogramme
JavaSE
C/S-Architektur für die Entwicklung und Bereitstellung von Java-Anwendungen für den Einsatz in Desktop-, Server-, eingebetteten und Echtzeitumgebungen
JavaME
Laufumgebung auf mobilen Geräten und eingebetteten Geräten (Mobiltelefone, PAD usw.)
Beziehungsdiagramm
(Common Gateway Interface, öffentliche Gateway-Schnittstelle) CGI
JavaBeans
Ist eine objektorientierte Programmierschnittstelle
Es handelt sich um einen Java-Kurs, der sich hauptsächlich auf die Integration von Anwendungen in Entwicklungstools konzentriert.
POJO (einfaches gewöhnliches Java-Objekt)
Bezieht sich auf gewöhnliche Java-Objekte, die keine Entity Beans verwenden
Im Wesentlichen kann es als einfache Entitätsklasse verstanden werden
Sie können die POJO-Klasse problemlos als Objekt verwenden und natürlich auch problemlos ihre Get- und Set-Methoden aufrufen.
Die POJO-Klasse bringt auch großen Komfort in unsere Konfiguration im Struts-Framework.
Servlet
jsp
eingebaute Objekte
1 Anfrage javax.servlet.http.HttpServletRequest
Client-Anforderungsinformationen: HTTP-Protokoll-Header-Informationen, Cookie, Anforderungsparameter usw.
2 Antwort javax.servlet.http.HttpServletResponse
Wird vom Server verwendet, um auf Clientanfragen zu antworten und Informationen zurückzugeben
3 pageContext javax.servlet.jsp.PageContext
Seitenkontext
4 Sitzung javax.servlet.http.HttpSession
Sitzung zwischen Client und Server
5 Anwendung javax.servlet.ServletContext
Wird verwendet, um Informationen zum serverseitigen Anwendungslebenszyklus zu erhalten
6 aus javax.servlet.jsp.JspWriter
Ausgabestream, der zur Übertragung von Inhalten vom Server zum Client verwendet wird
7 Konfiguration javax.servlet.ServletConfig
Während der Initialisierung werden die Informationen von der Jsp-Engine an die Jsp-Seite übergeben
8 Seiten java.lang.Object
Verweist auf die Jsp-Seite selbst
9 Ausnahme java.lang.Throwable
Auf der Seite tritt eine Ausnahme auf und das Ausnahmeobjekt wird generiert
Umfang
Seite aktueller Seitenbereich
Die in diesem Bereich gespeicherten Attributwerte können nur von der aktuellen Seite abgerufen werden.
Anforderungsbereich anfordern
Der Umfang ist die Zeit von der Erstellung der Anfrage bis zum Tod der Anfrage. Eine Anfrage kann mehrere Seiten umfassen.
Sitzungssitzungsbereich
Der Bereich ist ein Zeitraum, in dem Client und Server kontinuierlich verbunden sind.
Der Benutzer hat die betreffende Seite während der Gültigkeitsdauer der Sitzung mehrmals angefordert
globalen Geltungsbereich der Anwendung
Der Geltungsbereich reicht vom Start bis zum Stopp der serverseitigen Webanwendung und den beteiligten Seiten aller Anforderungen in der gesamten Webanwendung.
Servlet-Komponente
Was ist ein Servlet?
Kann dynamische HTML-Antworten bereitstellen
Es handelt sich um eine Java-Klasse, die auf dem Server ausgeführt wird
Wird zur vollständigen dynamischen Reaktion auf Kundenanfragen unter der B/S-Architektur verwendet
Diese Java-Klasse muss der JSP/Servlet-Spezifikation entsprechen
Wie schreibe ich ein Servlet?
Drei Wege
Erstellen Sie ein dynamisches Webprojekt und schreiben Sie eine Java-Klasse, die die abstrakte Klasse javax.servlet.http.HttpServlet erbt. Überschreiben Sie die Methode doGet() oder doPost()
Implementieren Sie die Schnittstelle javax.servlet.Servlet und überschreiben Sie alle ihre Methoden
Erben Sie die abstrakte Klasse javax.servlet.GenericServlet und überschreiben Sie die service()-Methode
Sie müssen web-inf herunterladen und web.xml konfigurieren
Stellen Sie das Projekt auf dem Webserver bereit und verwenden Sie das URL-Format, um den Test anzufordern
Erstellen Sie dynamische Webprojekte
Dynamisches Web
Hinweis: Wählen Sie die Tomcat-Laufumgebung und die Webversion aus
//Der Server weist den Browser an, in HTML zu übersetzen und in UTF-8 zu kodieren resp.setContentType("text/html;charset=utf-8;");
//Schreiben Sie in den Browser und erhalten Sie ein Ausgabeobjekt für den Browser PrintWriter p = resp.getWriter(); p.write("<h1>" s "<h2>");
web.xml
<!-- Servlet konfigurieren --> <Servlet> <servlet-name>Konsistent</servlet-name> <servlet-class>Paketname.Klassenname</servlet-class> </servlet> <Servlet-Mapping> <servlet-name>Konsistent</servlet-name> <url-pattern>/Schreiben Sie es selbst</url-pattern> </servlet-mapping>
Die Beziehung zwischen Servlet, GenericServlet und HttpServlet
Servlet-Lebenszyklus
Erstellung eines Servlet-Objekts
Standardmäßig wird das Servlet erstellt, wenn die erste Anfrage eingeht
(über Konstruktor)
Sie können das XML-Tag <load-on-startup> (wird beim Start geladen) mit einem Wert größer oder gleich 0 übergeben. Es wird empfohlen, 1 zu schreiben
Initialisierung von Servlet-Objekten
Unmittelbar nach der Erstellung des Objekts wird void init() aufgerufen, um die Initialisierung abzuschließen.
Servlet Kontinuierlicher Service von Objekten
void doGet(HttpServletRequest request,HttpServletResponse Response) löst ServletException, IOException aus //Wenn der Browser direkt das Senden von Doget anfordert void doPost(HttpServletRequest request,HttpServletResponse Response) throws ServletException, IOException //Wenn das Formular eine Psot-Anfrage sendet, rufen Sie doPost auf void service(HttpServletRequest request,HttpServletResponse Response) throws ServletException, IOException //Kann sowohl Get- als auch Post-Anfragen verarbeiten
Beim Senden einer Doget-Anfrage meldet nur das doPost-Methodenprogramm 405
@Override protected void doGet(HttpServletRequest request,HttpServletResponse Response) löst ServletException, IOException { doPost(Anfrage, Antwort); }
lösen
Der bevorstehende Untergang von Servlet-Objekten
void destroy()
Nach dem Aufruf gelangt das Objekt in das Garbage-Collection-System. Es ist noch nicht zu Garbage geworden. Erst wenn die Methode aufgerufen wird, kann es zu Garbage werden, da Java-Programmierer nur Vorschläge für Garbage-Collection-Rechte haben.
sterben
Thread-Sicherheitsprobleme von Servlets
Servlet-Thread aus unsicheren Gründen
Es gibt nur ein Servlet-Objekt, das derselben Anforderung entspricht, wenn mehrere Servlets dieselbe Mitgliedsvariable ausführen Beim Schreiben von Vorgängen kommt es zu Thread-Unsicherheit.
Wie löst man
über synchronisiert(this){}
Sperren, damit Threads in die Warteschlange gestellt werden
Weisen Sie einfach jedem Methodenaufruf eine unabhängige Variable zu und machen Sie sie nicht zu einer Mitgliedsvariablen
ServletContext-Objekt
Was ist ein ServletContext-Objekt?
Wenn das Projekt auf dem Webserver bereitgestellt wird, wird ein Objekt vom Typ ServletContext für das Projekt generiert. Dieses Objekt kann das Problem des Informationsaustauschs und der Informationsübertragung zwischen mehreren Servlets lösen
Wie bekomme ich es?
request.getServletContext()
Oder this.getServletContext() in der Servet-Service-Methode
ServletContext-API
Daten festlegen
setAttribute("name",value)
Daten abrufen
setAttribute("name")
Daten löschen
removeAttribute("name")
aaaaaaa
getRealPath("Ordnername")
Rufen Sie globale Parameterdaten ab, die in web.xml konfiguriert sind
getInitParameter("name");
Globale Parameter konfigurieren:
<context-param>Kontextparameter
<Kontextname>xx
<Kontextwert>utf-8
ServletConfig-Objekt
Was ist ein ServletConfig-Objekt?
Jedes unabhängige Servlet-Objekt verfügt über eine eigene ServletConfig Ein Objekt vom Typ ServletConfig kann es bedienen Rufen Sie die relevanten Informationen und Konfigurationsinformationen des Servlet-Objekts ab.
Wie bekomme ich es?
In der Servet-Service-Methode this.getServletContext()
ServletConfig-API
getServletName() Ruft den Namen des Servlets ab
Bezieht sich auf <Servlet-Name>
getServletContext() Ruft das Objekt der gemeinsam genutzten Servlet-Informationen ab
getInitParameter("name") Ruft die Konfigurationsinformationen für dieses Servlet-Objekt basierend auf dem Namen ab
Geschrieben in <servlet> <init-param> <param-name> <param-value>
Weiterleitung von Servlet-Anfragen
Arbeitsprinzip
Merkmale
Die Anforderungsweiterleitung unterstützt keinen domänenübergreifenden Zugriff und kann nur zu Ressourcen in der aktuellen Anwendung springen.
Nachdem die Anfrage weitergeleitet wurde, ändert sich die URL in der Adressleiste des Browsers nicht, sodass der Browser nicht weiß, dass eine Weiterleitung innerhalb des Servers stattgefunden hat, geschweige denn die Anzahl der Weiterleitungen.
An der Anforderungsweiterleitung beteiligte Webressourcen nutzen dasselbe Anforderungsobjekt und Antwortobjekt.
Da die Methode „forward()“ zunächst den Antwortpuffer löscht, wird die generierte Antwort erst an den Client gesendet, wenn sie an die letzte Webressource weitergeleitet wird.
Anforderungsdomänenobjekt
Vergleichen Sie mit dem Kontextdomänenobjekt
1) Unterschiedliche Lebenszyklen
2) Verschiedene Bereiche
3) Die Anzahl der Webanwendungen ist unterschiedlich
4) Verschiedene Möglichkeiten zum Datenaustausch
Verteilte Systeme und Anrufe
(Enterprise Java Beans)EJB
Es handelt sich um eine Komponente, die auf einem unabhängigen Server ausgeführt wird. Der Client ruft das EJB-Objekt über das Netzwerk auf.
EJB-Clusterdienst
Dabei werden Server über RMI-Kommunikation mit unterschiedlichen Funktionsmodulen verbunden, um eine vollständige Funktion zu erreichen.
Versuchen Sie, kein EJB zu verwenden
Einfache reine Webanwendungsentwicklung, keine Notwendigkeit, EJB zu verwenden
In Verbindung mit anderen Dienstprogrammen kann das aufgerufene oder zurückgegebene Netzwerkprotokoll gelöst werden
Anwendungen mit C/S-Struktur, auf die viele Personen gleichzeitig zugreifen
(Remote-Methodenaufruf)RMI
Die technische Grundlage von EJB ist RMI, das Fernanrufe über RMI ermöglicht.
Es handelt sich um eine Methode, die den Objektserialisierungsmechanismus verwendet, um verteiltes Rechnen und Remote-Aufrufe zu implementieren.
CORBA
Common Object Request Broker-Architektur, Common Object Request Broker-Architektur
Objektorientierte verteilte Anwendungssystemspezifikation, eine Lösung für die Verbindung von Hardware- und Softwaresystemen in heterogenen verteilten Umgebungen
Allgemeine Begriffe
OBR
Objektanforderungsbroker, Objektanforderungsbroker
In einer objektorientierten verteilten Umgebung kann ORB wichtige Kommunikationsmöglichkeiten für die Verteilung von Nachrichten zwischen Anwendungen, Servern und Netzwerkeinrichtungen bereitstellen.
Es ist die Kernkomponente von CORBA und bietet eine Rahmenstruktur zum Identifizieren und Lokalisieren von Objekten, zum Verwalten des Verbindungsmanagements, zum Übertragen von Daten und zum Anfordern von Kommunikation.
CORBA-Objekte
Es handelt sich um eine „virtuelle“ Entität, die von einem Object Request Broker (ORB) gefunden und von Client-Programmanforderungen aufgerufen werden kann.
IOR
Interoperable Objektreferenz: Interoperable Objektreferenz
Speichert fast alle Inter-ORB-Protokollinformationen, die zum Aufbau der Kommunikation zwischen Clients und Zielobjekten verwendet werden, und stellt ein standardisiertes Objektreferenzformat für die ORB-Interoperabilität bereit.
Jeder IOR umfasst einen Hostnamen, eine TCP/IP-Portnummer und einen Objektschlüssel, der das Zielobjekt anhand des Hostnamens und Ports identifiziert
Es besteht im Wesentlichen aus drei Teilen: Lager-ID, Endpunktinformationen und Objektschlüssel
CORBA-Systemdiagramm
Aufrufschritte für CORBA-Anfragen
(1).Suchen Sie das Zielobjekt
(2) Rufen Sie die Serveranwendung auf
(3). Übergeben Sie die für den Aufruf erforderlichen Parameter
(4). Aktivieren Sie ggf. das Servoprogramm, das das Zielobjekt aufruft
(5) Warten Sie, bis die Anfrage beendet ist
(6). Wenn der Aufruf erfolgreich ist, geben Sie die Out/Inout-Parameter zurück und übergeben Sie den Rückgabewert an den Client.
(7). Wenn der Aufruf fehlschlägt, geben Sie eine Ausnahme an den Client zurück.
Besonderheit
Realisiert plattform- und sprachübergreifende Datenübertragung unter verteilten Systemen
Lokaler Aufruf von Remote-Methoden implementiert (Methoden auf dem Remote-Server lokal aufrufen und den Rückgabewert erhalten)
Prinzipien heterogener verteilter Systeme
Suche nach plattformunabhängigen Modellen und Abstraktionen
Verstecken Sie zugrunde liegende komplexe Details so weit wie möglich, ohne zu große Einbußen bei der Leistung hinnehmen zu müssen
andere
Java-Funktionen
Vergleiche mit C
C unterstützt Zeiger, aber Java kennt kein Zeigerkonzept
C unterstützt Mehrfachvererbung, Java unterstützt jedoch keine Mehrfachvererbung
Java ist eine vollständig objektorientierte Sprache
Java recycelt Speicher automatisch, während in C Speicherressourcen vom Programm freigegeben werden müssen.
Java unterstützt keine Operatorüberladung, die als herausragendes Merkmal von C gilt
Java ermöglicht die Vorverarbeitung, unterstützt jedoch nicht die Präprozessorfunktion. Um die Vorverarbeitung zu implementieren, führen Sie Anweisungen ein (Import).
Java unterstützt keine Standardparameterfunktionen, C jedoch schon
C und C unterstützen keine String-Variablen
Java bietet keine goto-Anweisung
Java unterstützt keine automatischen Umwandlungen in C
ausfallsicher
Standard bezieht sich auf einen Fehlererkennungsmechanismus von Java-Sammlungen
Wenn mehrere Threads strukturelle Änderungen an einem Teil der Sammlung vornehmen, kann ein Fail-Fast-Mechanismus auftreten.
Werkzeug
Bearbeitung des Quellcodes
Notizblock
EditPlus
UltraEdit
Erhabener Text
vim
IDE
Eclipse-IDE
MyEclipse
Intellij-IDEE
NetBeans
Servlet-Container/Server
Kater
Strukturdiagramm
JBoss
Anlegestelle
WebSphere
WebLogic
Glasfische
Codegenerierung
Xdoclet
Komprimierungsalgorithmus
Gzip
Hohes Kompressionsverhältnis, langsame Geschwindigkeit
entleeren
entleeren (lvl=1)
Geringe Komprimierung, schnell
. . .
Luft ablassen (Stufe = 9)
Hohes Kompressionsverhältnis, langsame Geschwindigkeit
Bzip2
LZMA
XZ
LZ4
LZ4 (hoch)
LZ4 (schnell)
Sehr schnell, bis zu 320 M/S
LZO
Bissig
Snappy (gerahmt)
Bissig (normal)
Programmierideen und Designmuster
Design-Prinzipien
Prinzip der Einzelverantwortung
Offen-Geschlossen-Prinzip
Liskov-Substitutionsprinzip
Prinzip der Abhängigkeitsumkehr
Prinzip der Schnittstellenisolation
Prinzip der synthetischen Wiederverwendung
Demeters Gesetz
Designmuster
Schöpfungsmuster
(1) Singleton-Modus (Singleton)
(2) Einfaches Factory-Muster (SimpleFactory)
(3) Factory-Methodenmuster (FactoryMothod)
(4)Abstraktes Fabrikmuster (AbstratorFactory)
(5)Builder-Muster
(6)Prototypmuster
Strukturmuster
(7)Adaptermuster
(8)Brückenmuster
(9)Dekorationsmuster
(10)Verbundmuster
(11)Fassadenmuster
(12)Fliegengewichtsmuster
(13)Proxy-Muster
Verhaltensmuster
(14)Vorlagenmethode
(15)Befehlsmuster
(16)Iteratormuster
(17)Beobachtermuster
(18)Mediatormuster
(19)Zustandsmuster
(20)Strategiemuster
(21)Verantwortungskettenmodell
(22)Vistor-Muster
(23) Erinnerungsmuster
(24)Dolmetschermodus
Programmierideen
AOP Aspektorientiert
einführen
Trennung von Belangen: Unterschiedliche Probleme werden durch unterschiedliche Teile gelöst
Aspektorientierte Programmierung AOP ist die Verkörperung dieser Technologie
Die Implementierung universeller Funktionen entspricht dem sogenannten Aspekt (Aspekt).
Nachdem der Geschäftsfunktionscode und der Aspektcode getrennt wurden, wird die Architektur stark kohäsiv und weist eine geringe Kopplung auf.
Um die Integrität der Funktionen sicherzustellen, müssen Aspekte letztendlich in das Geschäft integriert werden (Weave, zusammengestellt)
AOP drei Webmethoden
Weben zur Kompilierungszeit (statische Proxys)
Es ist ein spezieller Java-Compiler erforderlich, geben Sie AspectJ ein
Weben während der Unterrichtsladung
Erfordert einen speziellen Java-Compiler wie AspectJ, AspectWerkz
Laufzeitweben (dynamische Proxys)
Spring verwendet diese Methode, um eine einfache Implementierung durch dynamischen Proxy zu erreichen
Frühlings-AOP
Dynamischer JDK-Proxy
Die Proxy-Klasse wird durch Reflektion empfangen und die Proxy-Klasse muss eine Schnittstelle implementieren.
InvocationHandler-Schnittstelle Proxy.newProxyInstance()
Dynamischer CGLIB-Proxy
Es handelt sich um eine Klassenbibliothek zur Codegenerierung, die zur Laufzeit dynamisch Unterklassen einer bestimmten Klasse generieren kann.
Dynamisches Proxying erfolgt durch Vererbung. Wenn also eine Klasse als endgültig markiert ist, Dann kann CGLIB nicht als dynamischer Proxy verwendet werden
MethodInterceptor-Schnittstelle Enhancer-Klasse
AOP-Hauptnomenkonzepte
Aspekt
Aspekt: Der Code für allgemeine Funktionen ist die Implementierung
Ziel
Ziel: soll in das Aspect-Objekt eingewebt werden
Verbindungspunkt
Möglichkeiten, die als Einstiegspunkte genutzt werden können, alle Methoden können als Einstiegspunkte genutzt werden
Pointcut
Definieren Sie den Verbindungspunkt, an dem Aspect tatsächlich angewendet wird, und unterstützen Sie reguläre Ausdrücke
Beratung
Methoden in der Klasse und wie diese Methode in die Zielmethode eingebunden ist
Einstufung
Vor der Benachrichtigung
AfterRunning-Benachrichtigung
AusnahmebenachrichtigungAfterThrowing
Letzte Mitteilung danach
Rund um Benachrichtigungen Rund um
Weberei
AOP-Implementierungsprozess
JDKProxy, Cglib zum Generieren von Proxy-Objekten
Die Details werden von AopProxyFactory basierend auf der Konfiguration des AdvisedSupport-Objekts bestimmt.
Die Strategie besteht darin, dass, wenn das Ziel eine Schnittstelle ist, standardmäßig JDKProxy zur Implementierung verwendet wird, andernfalls Letzteres verwendet wird
JDKProxy
Der dynamische JDK-Proxy ist eine Implementierungsmethode des Proxy-Modus. Er empfängt die zu vertretende Klasse durch Reflektion und erfordert, dass die zu vertretende Klasse die Schnittstelle implementiert.
JDKProxy-Kern
InvocationHandler-Schnittstelle und Proxy-Klasse
Der Reflexionsmechanismus ist beim Generieren von Klassen effizienter
Cglib
Implementieren Sie den Proxy der Zielklasse durch Vererbung, und die unterste Ebene wird mithilfe von ASM implementiert
Wenn die Zielklasse auf final gesetzt ist und nicht vererbt werden kann Sie können den dynamischen Cglib-Proxy nicht verwenden
ASM ist im Ausführungsprozess nach dem Generieren von Klassen effizienter.
Proxy-Modus
Schnittstelle Reale Implementierungsklasse Proxy-Klasse
Proxy-Implementierung im Frühjahr
Die Logik der realen Implementierungsklasse ist in der getBean-Methode enthalten
Was die getBean-Methode zurückgibt, ist tatsächlich eine Instanz von Proxy
Die Proxy-Instanz wird von Spring dynamisch mit JDKProxy oder Cglib generiert
IOC Kontrolle umkehren
Der Kernteil von Spring Core
Abhängigkeitsinversion, Abhängigkeitsinjektion
Beispiel: Die Oberstruktur hängt von der Unterstruktur ab, ein solcher Code ist nahezu nicht wartbar Wenn Sie das Rad ändern möchten, müssen Sie alle Klassen ändern
Die Bedeutung der Abhängigkeitsinjektion: Übergeben Sie die untere Klasse als Parameter an die obere Klasse, um die „Kontrolle“ der oberen Schicht über die untere Schicht zu realisieren
Injektionsmethode
Injektion einstellen
Schnittstelleninjektion
Anmerkungsinjektion
Konstruktorinjektion
Vorteile von IOC-Containern
Vermeiden Sie die Verwendung von „New Everywhere“, um Klassen zu erstellen und diese einheitlich zu verwalten
Beim Erstellen einer Instanz müssen Sie die Details nicht kennen
Was passiert, wenn ein Projekt startet?
1. Wenn Spring beginnt, lesen Sie die von der Anwendung bereitgestellten Bean-Informationen .2. Generieren Sie eine Bean-Konfigurationsregistrierung aus den gelesenen Bean-Konfigurationsinformationen. 3. Instanziieren Sie das Bean gemäß der Bean-Registrierung, stellen Sie die Abhängigkeiten des Beans zusammen und stellen Sie eine betriebsbereite Umgebung für die obere Ebene bereit. 4. Verwenden Sie die Reflexionsfunktion von Java, um Beans zu instanziieren und Abhängigkeiten zwischen Beans herzustellen
Welche Funktionen unterstützt IOC?
Abhängigkeitsspritze
Abhängigkeitsprüfung
Automatische Montage
Unterstützen Sie Sammlungen
Entwickeln Sie eine erste Methode und eine Zerstörungsmethode
Support-Rückruf für bestimmte Methoden
Spring IOC-Container-Kernschnittstelle
BeanFactory
Stellt einen IOC-Konfigurationsmechanismus bereit
Enthält verschiedene Definitionen von Bohnen, um die Instanziierung von Bohnen zu erleichtern
Abhängigkeiten zwischen Beans herstellen
Kontrolle des Bohnenlebenszyklus
Anwendungskontext
Erbt mehrere Schnittstellen
BeanFactory
Kann Beans verwalten und zusammenstellen
ResourcePatternResolver
Möglichkeit zum Laden von Ressourcendateien
Nachrichtenquelle
Fähigkeit zur Implementierung internationalisierungsbezogener Funktionen
ApplicationEventPublisher
Möglichkeit, Zuhörer zu registrieren und Überwachungsmechanismen zu implementieren
BeanDefinition
Wird hauptsächlich zur Beschreibung von Bean-Definitionen verwendet
BeanDefinitionRegistry
Stellt Methoden zum Registrieren von BeanDefinition-Objekten beim IOC-Container bereit
BeanFactory- und ApplicationContext-Vergleich
BeanFactory ist die Infrastruktur von Spring ApplicationContext ist für Spring-Framework-Entwickler
Aktualisierungsmethode
Stellen Sie Bedingungen für die Lebenszyklusverwaltung von IOC-Containern und Beans bereit
Aktualisieren Sie die Spring-Kontextinformationen und definieren Sie den Spring-Kontextladeprozess
getBean-Methode
BeanName konvertieren
Instanz aus dem Cache laden
Bohnen instanziieren
Erkennen Sie parentBeanFactory
Abhängige Beans initialisieren
Bohnen herstellen
Häufige Fragen im Vorstellungsgespräch
Spring Bean Scope
Singleton
Im Standardbereich des Spring-Containers gibt es eine eindeutige Bean-Instanz im Container
Geeignet für staatenlose Bohnen
Prototyp
Für jede getBean-Anfrage erstellt der Container eine neue Bean-Instanz
Geeignet für Stateful Beans
Für jede HTTP-Anfrage wird eine Bean-Instanz erstellt
Sitzung
Für jede Sitzung wird eine Bean-Instanz erstellt
globaleSitzung
Für jede globale HTTP-Sitzung wird eine Bean-Instanz erstellt. Dieser Bereich ist nur für Portlets wirksam
Zusätzliche Unterstützung für Webcontainer
Lebenszyklus einer Bohne
InstantiateBean
Aware (Bean-ID, BeanFactory, AppCtx injizieren)
Aware-Schnittstelle deklariert Abhängigkeiten
BeanPostProcessor(s) postProcessBeforeInitization
Vorinitialisierungsmethode Nachdem Spring die Instanziierung abgeschlossen hat, Fügen Sie den vom Spring-Container instanziierten Beans eine benutzerdefinierte Verarbeitungslogik hinzu
InitializingBeans(s).afterPropertiesSet
Angepasste bean.init-Methode
BeanPosProcessor(s). postProcessAfterInitization
Methode nach der Initialisierung Nachdem die Bean-Initialisierung abgeschlossen ist, Benutzerdefinierte Operationen
Bean-Initialisierung abgeschlossen
Bohnenkreation
Prozess der Bohnenvernichtung
Wenn die Schnittstelle „DisposableBean“ implementiert ist, wird die Methode destroy aufgerufen
Wenn das Attribut destroy-method konfiguriert ist, wird die zuvor konfigurierte Zerstörungsmethode aufgerufen.
Bohnenzerstörung
Erweiterte Java-Grundlagen
Theoretische Basis
Stapel-, Heap- und Methodenbereich
Variablen grundlegender Datentypen, Objektreferenzen und Funktionsaufrufe werden mithilfe des Stapelspeichers in der JVM gespeichert.
Mit dem Schlüsselwort new und dem Konstruktor erstellte Objekte werden im Heap-Bereich platziert
Der Methodenbereich und der Heap sind Speicherbereiche, die von jedem Thread gemeinsam genutzt werden und zum Speichern von Klasseninformationen, Konstanten, statischen Variablen, vom JIT-Compiler kompiliertem Code usw. verwendet werden, die von der JVM geladen wurden.
Der Stapelspeicher ist am schnellsten zu bedienen, aber normalerweise wird eine große Anzahl von Objekten im Heapspeicher abgelegt.
Sowohl die Stapel- als auch die Heap-Größe können über JVM-Startparameter angepasst werden.
Wenn nicht genügend Stapelspeicherplatz vorhanden ist, wird ein StackOverflowError verursacht, während unzureichender Heapspeicher und konstanter Poolspeicherplatz einen OutOfMemoryError verursachen.
Grundtypen und Verpackungstypen
Wrapper-Typen können null sein, Basistypen nicht
Wrapper-Typen können mit Generika verwendet werden, Basistypen nicht
Primitive Typen sind effizienter als verpackte Typen
Basistypen speichern bestimmte Werte direkt auf dem Stapel, während Wrapper-Typen Referenzen im Heap speichern.
Die Werte zweier Wrapper-Typen können gleich, aber nicht gleich sein
Ganzzahl chenmo = new Integer(10); Integer wanger = new Integer(10); System.out.println(chenmo == wanger); // false System.out.println(chenmo.equals(wanger)); // true
Ein- und Auspacken
Der Prozess der Konvertierung von Basistypen in verpackte Typen wird als Boxen bezeichnet
Der Vorgang des Konvertierens eines umschlossenen Typs in einen Basistyp wird als Unboxing bezeichnet
String und StringBuilder, StringBuffer
String ist ein schreibgeschützter String, was bedeutet, dass der Inhalt des Strings, auf den String verweist, nicht geändert werden kann.
Das durch die StringBuffer/StringBuilder-Klasse dargestellte String-Objekt kann direkt geändert werden
StringBuilder wird in einem einzelnen Thread verwendet und ist threadunsicher, aber seine Leistung ist viel höher als die von StringBuffer.
final, endlich, finalisieren
Finale
Wenn eine Klasse als endgültig deklariert wird, bedeutet dies, dass sie keine neuen Unterklassen ableiten kann, das heißt, sie kann nicht vererbt werden, was das Antonym von abstrakt ist.
Deklarieren Sie Variablen als endgültig, um sicherzustellen, dass sie während der Verwendung nicht geändert werden
Endlich
Die Struktur wird normalerweise nach try...catch... platziert und führt den Codeblock immer aus. Dies bedeutet, dass der Code hier ausgeführt werden kann, unabhängig davon, ob das Programm normal ausgeführt wird oder eine Ausnahme auftritt, solange die JVM nicht geschlossen ist.
abschließen
Java ermöglicht die Verwendung der finalize()-Methode, um notwendige Aufräumarbeiten durchzuführen, bevor der Garbage Collector das Objekt aus dem Speicher löscht.
static final/final static
Eine mit static final geänderte Eigenschaft bedeutet, dass ein einmal angegebener Wert nicht mehr geändert werden kann und über den Klassennamen darauf zugegriffen werden kann.
Statische endgültige modifizierte Methode, die angibt, dass die Methode nicht überschrieben werden kann und ohne ein neues Objekt aufgerufen werden kann
== und hashCode und equal-Methoden
equal() kann bestätigen, ob sie wirklich gleich sind.
Die Standardimplementierung in der Object-Klasse lautet: return this == obj. True wird nur zurückgegeben, wenn this und obj auf dasselbe Objekt verweisen.
Gleiches überschreiben
Reflexivität: x.equals(x) muss wahr sein
Für null: x.equals(null) muss falsch sein
Symmetrie: x.equals(y) und y.equals(x) haben das gleiche Ergebnis
Transitivität: a und b sind gleich, b und c sind gleich, dann müssen auch a und c gleich sein.
Konsistenz: Während einer bestimmten Laufzeit haben Änderungen im Zustand der beiden Objekte keinen Einfluss auf das Entscheidungsergebnis von equal
hashCode() wird verwendet, um den Suchbereich einzugrenzen
Gleiches umschreiben, Sie müssen auch hashCode neu schreiben
Die Felder, die an der Funktion „equals“ beteiligt sind, müssen auch an der Berechnung von hashCode beteiligt sein.
Äquivalente Objekte (der Aufruf von „equals“ gibt „true“ zurück) müssen denselben Hash-Code erzeugen. Für nicht äquivalente Objekte ist es nicht erforderlich, dass die resultierenden Hash-Codes unterschiedlich sind.
Die Felder, die Gleichheit messen, nehmen an der Hash-Operation teil. Jedes wichtige Feld generiert eine Hash-Komponente und trägt zum endgültigen Hash-Wert bei.
== Bestimmen Sie, ob die Objektadressen gleich sind
RPC-Aspekt
Der Grund, warum die Serialisierung und Deserialisierung des Protokollpuffers einfach und schnell ist, ist
1. Die Kodierungs-/Dekodierungsmethode ist einfach (nur einfache mathematische Operationen = Verschiebung usw.)
2. Verwenden Sie den eigenen Framework-Code und Compiler von Protocol Buffer, um den Vorgang abzuschließen
Die Gründe, warum der Protokollpuffer einen guten Datenkomprimierungseffekt hat (d. h. das Datenvolumen nach der Serialisierung ist gering), sind:
1. a. Übernehmen Sie eine eindeutige Kodierungsmethode, z. B. Varint, Zigzag-Kodierungsmethode usw.
2. b. Übernehmen Sie die T-L-V-Datenspeichermethode: Reduzieren Sie die Verwendung von Trennzeichen und die Datenspeicherung ist kompakt
Datenbank
Wiederholbares Lesen von INNODB: Welche cleveren Methoden werden verwendet, um Phantomlesen zu vermeiden?
Darstellung des Snapshot-Lesens (nicht blockierendes Lesen), Pseudo-MVCC
Intrinsisches Next-Key-Schloss-Lückenschloss
Sie müssen etwas über Redo Log wissen