Vorwort Im vorherigen Artikel habe ich Ihnen anhand des Beispiels von Flash-Verkäufen in E-Commerce-Szenarien gezeigt, wie Sie Sperren in einer monolithischen Architektur verwenden. Viele Anwendungssysteme sind jedoch mittlerweile recht groß und viele Anwendungssysteme sind Systeme mit Microservice-Architektur. Wie sollten wir also in diesem JVM-übergreifenden Szenario die Parallelität lösen? Einschränkungen monolithischer AnwendungssperrenBevor wir in die eigentliche Praxis einsteigen, möchte ich kurz mit Ihnen über die architektonische Entwicklung von Internetsystemen sprechen. Zu Beginn der Entwicklung des Internetsystems war der Ressourcenverbrauch relativ gering und die Anzahl der Benutzer relativ gering. Wir mussten nur eine Tomcat-Anwendung bereitstellen, um die Anforderungen zu erfüllen. Wir können einen Tomcat als JVM-Prozess betrachten. Wenn eine große Anzahl von Anfragen gleichzeitig beim System eintrifft, fallen alle Anfragen nur auf diesen Tomcat. Wenn einige Anfragemethoden gesperrt werden müssen, wie beispielsweise das im vorherigen Artikel erwähnte Szenario von Flash-Sales und Bestandsreduzierung, kann dies den Anforderungen entsprechen. Wenn jedoch die Anzahl der Besuche zunimmt, kann ein Tomcat dies nicht unterstützen. Derzeit müssen wir Tomcat in einem Cluster bereitstellen und mehrere Tomcats verwenden, um das System zu unterstützen. Nach der einfachen Entwicklung in der obigen Abbildung setzen wir zwei Tomcats ein, um das System gemeinsam zu unterstützen. Wenn eine Anfrage beim System eintrifft, durchläuft sie zunächst nginx, das als Lastenausgleich fungiert und die Anfrage entsprechend seiner eigenen Lastenausgleichskonfigurationsstrategie an einen der Tomcats weiterleitet. Wenn auf eine große Zahl von Anfragen gleichzeitig zugegriffen wird, teilen sich die beiden Tomcats den gesamten Datenverkehr. Können wir danach, wenn wir zur Lagerreduzierung Flash-Verkäufe durchführen, die Nachfrage immer noch mit einer einzigen Anwendungssperre decken? Die Sperre, die wir zuvor hinzugefügt haben, ist die von JDK bereitgestellte Sperre. Diese Sperre funktioniert unter einer einzelnen JVM. Wenn es zwei oder mehr gibt, wird eine große Anzahl gleichzeitiger Anfragen an verschiedene Tomcats verteilt. Gleichzeitigkeit kann in jedem Tomcat verhindert werden. Zwischen mehreren Tomcats erzeugt die Anfrage zum Erhalt der Sperre in jedem Tomcat jedoch erneut Gleichzeitigkeit. Daher bleibt das Problem des Lagerbestandsabzugs bestehen. Dies ist die Einschränkung der Einzelanwendungssperre. Wie lösen wir also dieses Problem? Als Nächstes werde ich das verteilte Schloss mit Ihnen teilen. Verteilte Sperren Was ist eine verteilte Sperre? Was ist also eine verteilte Sperre? Bevor wir über verteilte Sperren sprechen, sehen wir, dass die Eigenschaft einer einzelnen Anwendungssperre darin besteht, dass sie in einer JVM wirksam ist, aber nicht JVMs und Prozesse überschreiten kann. Daher können wir eine weniger offizielle Definition geben: Eine verteilte Sperre ist eine Sperre, die mehrere JVMs und mehrere Prozesse umfassen kann. Eine solche Sperre ist eine verteilte Sperre. Gestaltungsideen Da Tomcat von Java gestartet wird, kann jeder Tomcat als JVM betrachtet werden und die Sperre innerhalb der JVM kann nicht mehrere Prozesse umfassen. Wenn wir verteilte Sperren implementieren, können wir daher nur außerhalb dieser JVMs danach suchen und sie über andere Komponenten implementieren. In der obigen Abbildung verwenden die beiden Tomcats Komponenten von Drittanbietern, um JVM- und prozessübergreifende verteilte Sperren zu implementieren. Dies ist die Lösung für verteilte Sperren. DurchführungWelche Komponenten von Drittanbietern stehen derzeit zur Verfügung, um dies zu erreichen? Die beliebtesten sind die folgenden:
Lao Mao demonstriert die oben genannten Implementierungsmethoden noch einmal einzeln anhand spezifischer Codebeispiele. Verteilte Sperre basierend auf Datenbank Idee: Implementieren Sie verteilte Sperren basierend auf pessimistischen Datenbanksperren, hauptsächlich unter Verwendung von „Select ...“ zum Aktualisieren. Der Zweck von „select ... for update“ besteht darin, die abgefragten Daten während der Abfrage zu sperren. Wenn der Benutzer diese Art von Vorgang ausführt, dürfen andere Threads die Daten nicht ändern oder löschen. Sie müssen warten, bis der vorherige Thread den Vorgang abgeschlossen und freigegeben hat, bevor sie fortfahren können, wodurch der Sperreffekt erzielt wird. Umsetzung: Wir zeigen euch den Code am Beispiel von Overselling im E-Commerce. Lassen Sie uns das Beispiel des Überverkaufs in der letzten monolithischen Architektur mit Ihnen teilen. Wir werden den letzten Code ändern und eine neue Tabelle namens „distribute_lock“ erstellen. Der Hauptzweck dieser Tabelle besteht darin, Datenbanksperren bereitzustellen. Schauen wir uns die Situation dieser Tabelle an. Da wir ein Szenario mit überverkauften Bestellungen simulieren, verfügen wir in der obigen Abbildung über Sperrdaten für eine Bestellung. Wir werden den Code im vorherigen Artikel ändern, um einen Controller zu extrahieren und dann den Anruf über Postman anzufordern. Natürlich werden im Hintergrund zwei JVMs gestartet, um zu arbeiten, nämlich Port 8080 und Port 8081. Der vollständige Code lautet wie folgt: /** * @author [email protected] * @date 2021/1/3 10:48 * @desc Öffentliches Konto „Programmer Old Cat“ */ @Service @Slf4j öffentliche Klasse MySQLOrderService { @Ressource privater KdOrderMapper OrderMapper; @Ressource privater KdOrderItemMapper orderItemMapper; @Ressource privater KdProductMapper ProduktMapper; @Ressource privater DistributeLockMapper distributeLockMapper; //Produkt-ID kaufen private int KaufProduktID = 100100; //Menge der gekauften Waren private int purchaseProductNum = 1; @Transactional(Ausbreitung = Ausbreitung.ERFORDERLICH) öffentliche Ganzzahl createOrder() wirft Ausnahme{ log.info("Methode aufgerufen"); DistributeLock Sperre = distributeLockMapper.selectDistributeLock("Bestellung"); if(lock == null) throw new Exception("Die verteilte Sperre für dieses Unternehmen ist nicht konfiguriert"); log.info("habe das Schloss bekommen"); //Hier schlafen wir 1 Minute, um die Parallelität manuell zu demonstrieren. Thread.sleep(60000); KdProduct-Produkt = productMapper.selectByPrimaryKey(purchaseProductId); wenn (Produkt==null){ throw new Exception("Produkt kaufen: "+purchaseProductId+" existiert nicht"); } //Aktueller Lagerbestand des Produkts Integer currentCount = product.getCount(); log.info(Thread.currentThread().getName()+"Inventarzahl"+currentCount); //Lagerbestand prüfen if (purchaseProductNum > currentCount) { throw new Exception("Product"+purchaseProductId+" hat nur noch "+currentCount+" Artikel übrig, kann nicht gekauft werden"); } //Reduzierungsvorgang in der Datenbank abschließen productMapper.updateProductCount(purchaseProductNum,"kd",new Date(),product.getId()); //Reihenfolge generieren ... Die Anzahl wird weggelassen. Der Quellcode kann von Lao Maos Github heruntergeladen werden: https://github.com/maoba/kd-distribute gibt order.getId() zurück; } } Das SQL wird wie folgt geschrieben: wählen * von distribute_lock wobei business_code = #{business_code,jdbcType=VARCHAR} für Update Das Obige ist die Hauptimplementierungslogik. Beachten Sie die folgenden Punkte im Code:
Werfen wir einen Blick auf den endgültigen Laufeffekt. Sehen wir uns zunächst das Konsolenprotokoll an. Das Konsolenprotokoll von 8080 lautet wie folgt:
Das Konsolenprotokoll von 8081 lautet wie folgt:
Aus dem Protokoll können wir ersehen, dass die erste Anfrage an 8080 von zwei verschiedenen JVMs zuerst die Sperre erhält, sodass die Anfrage an 8081 auf die Freigabe der Sperre wartet, bevor sie ausgeführt werden kann. Dies zeigt, dass unsere verteilte Sperre wirksam ist. Anfrage für 8080:
Anfrage für 8081:
Offensichtlich schlug die zweite Anfrage aufgrund mangelnden Inventars fehl. Natürlich entspricht dieses Szenario auch unserem normalen Geschäftsszenario. Schließlich sieht unsere Datenbank folgendermaßen aus: Selbstverständlich sind auch die Lagerbestände und Bestellmengen in dieser Datenbank korrekt. An diesem Punkt ist unsere praktische Demonstration verteilter Sperren basierend auf der Datenbank abgeschlossen. Lassen Sie uns die Vor- und Nachteile der Verwendung dieser Art von Sperren zusammenfassen.
Abschließende GedankenWas die oben erwähnten verteilten Datenbanksperren betrifft, werden sie in unserer täglichen Entwicklung tatsächlich selten verwendet. Redis- und ZK-basierte Sperren werden häufiger verwendet. Ursprünglich wollte ich in diesem Artikel Redis- und ZK-Sperren zusammen beschreiben, aber wenn sie im selben Artikel beschrieben würden, wäre der Umfang zu groß. Daher werde ich in diesem Artikel diese Art von verteilten Sperren mit Ihnen teilen. Sie können den Quellcode von Lao Maos GitHub herunterladen. Die Adresse lautet: https://github.com/maoba/kd-distribute Dies ist das Ende dieses Artikels darüber, wie MySQL tatsächlich verteilte Sperren implementieren kann. Weitere relevante Inhalte zu verteilten MySQL-Sperren finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird! Das könnte Sie auch interessieren:
|
<<: TCP-Socket-SYN-Warteschlange und Accept-Warteschlangen-Unterschiedsanalyse
Bei der Verwendung einer MySQL-Datenbank treten h...
1. Ursache Die Anforderung besteht darin, zwei Ze...
Inhaltsverzeichnis Primärschlüsseleinschränkung E...
Ich möchte eine Situation erreichen, in der die B...
Routensprung dies.$router.push('/kurs'); ...
Übersicht über MySQL MySQL ist ein relationales D...
Inhaltsverzeichnis 1. Im Hintergrund laufende Job...
Verwenden Sie Javascript, um eine feste Seitenlei...
Inhaltsverzeichnis Allgemeine Versionseinführung ...
Vorwort Kürzlich habe ich festgestellt, dass die ...
So schreiben Sie ein Vue-foreach-Array und durchl...
1. Umgebungsbeschreibung (1) CentOS-7-x86_64, Ker...
Inhaltsverzeichnis Experimentelle Umgebung Instal...
In diesem Artikelbeispiel wird der spezifische Co...
Der ps-Befehl in Linux ist die Abkürzung für „Pro...