Heim  >  Artikel  >  Einige Gedanken zu Lösungen mit hoher Parallelität in PHP

Einige Gedanken zu Lösungen mit hoher Parallelität in PHP

无忌哥哥
无忌哥哥Original
2018-06-27 14:37:592148Durchsuche

Bei Eilverkäufen, Blitzverkäufen, Lotterieverlosungen, dem Sammeln von Tickets und anderen Aktivitäten ist die Lagermenge begrenzt, um Überverkäufe zu vermeiden. Wenn jedoch die Anzahl der Personen, die gleichzeitig Bestellungen aufgeben, den Lagerbestand übersteigt Menge, es wird zu Überverkaufsproblemen führen. Wie lösen wir dieses Problem? Meine Idee ist wie folgt (Pseudocode): sql1: Produktinventar abfragen, wenn (Inventarmenge> 0) { //Bestellung generieren...
sql2: Gleichzeitige Inventur-1}

Wenn keine Parallelität besteht, sieht der obige Vorgang normal aus. Angenommen, zwei Personen geben gleichzeitig Bestellungen auf und es gibt nur einen Bestand. In der SQL1-Phase beträgt der von beiden Personen abgefragte Bestand > 0, also wurde sql2 schließlich ausgeführt und der Bestand wurde schließlich -1, was überverkauft ist. Dies ist nicht das gewünschte Ergebnis.

Ich habe die beliebtesten Ideen zur Lösung dieses Problems zusammengefasst:

1. Verwenden Sie einen zusätzlichen Einzelprozess, um eine Warteschlange zu verarbeiten, die Bestellanfragen in die Warteschlange zu stellen und sie einzeln zu verarbeiten Es gibt Parallelitätsprobleme, aber es müssen zusätzliche Hintergrundprozesse und Verzögerungsprobleme geöffnet werden, die hier vorerst nicht berücksichtigt werden. Hier kann ich die Nachrichtenwarteschlange verwenden, wir verwenden oft Memcacheq und Radis. Beispiel: Wenn Benutzer 100 Tickets abrufen können, können sie diese 100 Tickets in den Cache legen und sie beim Lesen und Schreiben nicht sperren. Wenn die Parallelität groß ist, können etwa 500 Personen erfolgreich Tickets erhalten, sodass Anfragen nach 500 am Ende der Veranstaltung direkt auf die statische Seite übertragen werden können. Für 400 von 500 Menschen ist es unmöglich, die Ware zu bekommen. Daher können nur die ersten 100 Personen entsprechend der Reihenfolge, in der sie in die Warteschlange gelangen, erfolgreich einkaufen. Die nächsten 400 Personen gelangen direkt zur Endseite der Veranstaltung. Die Eingabe von 500 Personen ist natürlich nur ein Beispiel. Sie können die Zahl selbst anpassen. Die Aktivitätsendseite muss eine statische Seite und keine Datenbank verwenden. Dadurch wird der Druck auf die Datenbank verringert.

2. Die optimistische MySQL-Sperre bedeutet, dass zum Beispiel, wenn der Gesamtbestand 2 beträgt, der Bestand sofort +1 beträgt, wenn das Eilkaufereignis übermittelt wird, und dass der Bestand zu diesem Zeitpunkt 3 beträgt Führen Sie dann nach der Generierung der Bestellung eine erneute Abfrage durch, bevor Sie den Lagerbestand aktualisieren (da die Bestellung generiert wird, beträgt der Lagerbestand -1, aber keine Sorge, überprüfen Sie den Lagerbestand erneut und das Ergebnis ist 3) und prüfen Sie, ob er konsistent ist mit der erwarteten Lagerbestandsmenge (der erwartete Lagerbestand beträgt hier 3). Wenn er inkonsistent ist, führen Sie einen Rollback durch und fordern Sie den Benutzer auf, nicht über ausreichend Lagerbestand zu verfügen. Hier sprechen wir über pessimistische Sperren. Einige Freunde fragen sich vielleicht, dass es doch optimistische Sperren geben muss, oder? Hier werde ich kurz über die pessimistischen und optimistischen Sperren sprechen, die ich kenne Üblicherweise ist die Idee des Ressourcen-Parallelitätssperren-Designs auch ein sehr grundlegendes Konzept in der gleichzeitigen Programmierung. Dieser Artikel bietet eine vergleichende und systematische Einführung in die Implementierung dieser beiden gängigen Sperrmechanismen für Datenbankdaten.

Pessimistische Sperre

Das Merkmal der pessimistischen Sperre besteht darin, zuerst die Sperre zu erwerben und dann Geschäftsvorgänge auszuführen. Das heißt, „pessimistisch“ geht davon aus, dass der Erwerb der Sperre sehr wahrscheinlich fehlschlägt Es ist notwendig, zunächst sicherzustellen, dass die Sperre erfolgreich erhalten wird, bevor Geschäftsvorgänge ausgeführt werden. Der allgemein als „eine Sperre, zwei Prüfungen und drei Aktualisierungen“ bezeichnete Begriff bezieht sich auf die Verwendung pessimistischer Sperren. Im Allgemeinen erfordert das pessimistische Sperren der Datenbank Unterstützung durch die Datenbank selbst, dh das pessimistische Sperren wird durch den häufig verwendeten Vorgang „Auswählen ... für Aktualisierung“ implementiert. Wenn die Datenbank „Auswahl zur Aktualisierung“ ausführt, erhält sie die Zeilensperre der Datenzeile in der Auswahl. Wenn daher andere gleichzeitig ausgeführte „Auswahl zur Aktualisierung“ versuchen, dieselbe Zeile auszuwählen, erfolgt ein Ausschluss (es muss gewartet werden, bis die Zeilensperre aktiviert ist). freigegeben werden), sodass der Sperreffekt erreicht wird. Die durch „select for update“ erworbene Zeilensperre wird am Ende der aktuellen Transaktion automatisch freigegeben und muss daher innerhalb der Transaktion verwendet werden.

Hier ist zu beachten, dass verschiedene Datenbanken unterschiedliche Implementierungen und Unterstützung für „Select for Update“ haben. Beispielsweise unterstützt Oracle „Select for Update No Wait“, was bedeutet, dass ein Fehler auftritt, wenn die Sperre nicht erhalten werden kann sofort gemeldet, anstelle von Warten verfügt MySQL nicht über die Option „Kein Warten“. Ein weiteres Problem bei MySQL besteht darin, dass alle gescannten Zeilen während der Ausführung der Select-for-Update-Anweisung gesperrt werden, was leicht zu Problemen führen kann. Wenn Sie in MySQL pessimistisches Sperren verwenden, achten Sie daher darauf, den Index anstelle eines vollständigen Tabellenscans zu verwenden.

Optimistische Sperre

Die Merkmale der optimistischen Sperre bestehen darin, zuerst den Geschäftsbetrieb durchzuführen und die Sperre erst zu ergreifen, wenn dies unbedingt erforderlich ist. Mit anderen Worten, „optimistisch“ geht davon aus, dass die Sperre in den meisten Fällen erfolgreich sein wird. Nehmen Sie die Sperre also einfach nach dem letzten Schritt vor, bei dem die Daten nach Abschluss des Geschäftsvorgangs tatsächlich aktualisiert werden.

Die Implementierung des optimistischen Sperrens auf der Datenbank ist völlig logisch und erfordert keine besondere Unterstützung durch die Datenbank. Der allgemeine Ansatz besteht darin, den zu sperrenden Daten eine Versionsnummer oder einen Zeitstempel hinzuzufügen und diese dann wie folgt zu implementieren:

1. SELECT data AS old_data, version AS old_version FROM …; Die erhaltenen Daten führen Geschäftsoperationen durch und erhalten neue_Daten und neue_Version3. UPDATE SET data = new_data, version = new_version WHERE version = old_versionif (aktualisierte Zeile > 0) { // Optimistische Sperre ist erfolgreich, Vorgang abgeschlossen} else { // Optimistische Sperre Die Erfassung schlägt fehl. Geben Sie Roll zurück und versuchen Sie es erneut.🎜>

Es spielt eigentlich keine Rolle, ob eine Transaktion eine optimistische Sperre enthält. Der zugrunde liegende Mechanismus ist wie folgt: Beim Aktualisieren derselben Zeile innerhalb der Datenbank ist keine Parallelität zulässig, d. h. die Datenbank erhält jedes Mal die aktualisierte Zeile führt eine Update-Anweisung aus. Die Schreibsperre wird erst aufgehoben, wenn die Zeile erfolgreich aktualisiert wurde. Ermitteln Sie daher vor der Ausführung des Geschäftsvorgangs die aktuelle Versionsnummer der Daten, die gesperrt werden müssen, und vergleichen Sie die Versionsnummer erneut, um sicherzustellen, dass sie mit der Versionsnummer übereinstimmt, die Sie zuvor erhalten haben, als die Daten tatsächlich aktualisiert wurden Aktualisieren Sie die Versionsnummer, um zu bestätigen, dass keine gleichzeitigen Änderungen vorgenommen wurden. Wenn die Aktualisierung fehlschlägt, kann davon ausgegangen werden, dass die alte Version der Daten gleichzeitig geändert wurde und nicht mehr vorhanden ist. Zu diesem Zeitpunkt wird davon ausgegangen, dass die Sperre fehlgeschlagen ist und der gesamte Geschäftsbetrieb zurückgesetzt werden muss Der gesamte Vorgang kann bei Bedarf wiederholt werden.

Hier ist eine knappe Zusammenfassung dieser beiden Sperren:

1 Die Kosten für optimistische Sperren sind geringer als die für pessimistische Sperren, wenn kein Sperrfehler auftritt, aber sobald ein Fehler auftritt, sind die Kosten höher Der Rollback ist relativ groß und eignet sich daher für den Einsatz in Szenarien, in denen die Wahrscheinlichkeit eines Sperrfehlers relativ gering ist, was die Parallelitätsleistung des Systems verbessern kann.

2. Optimistisches Sperren eignet sich auch für einige spezielle Szenarien, z. B. wenn die Verbindung zur Datenbank während des Geschäftsbetriebs nicht aufrechterhalten werden kann und an anderen Orten, an denen pessimistisches Sperren nicht angewendet werden kann.

3. Basierend auf dem Aktualisierungsergebnis können wir eine Bewertungsbedingungsaktualisierungstabelle hinzufügen, wobei in sql2 „inventory>0“ angegeben ist zurückgerollt.

4. Verwenden Sie bei der Verarbeitung einer Bestellanforderung Flock, um eine Datei zu sperren. Dies bedeutet, dass zu diesem Zeitpunkt andere Bestellungen verarbeitet werden müssen entweder warten oder direkt „Server ausgelastet“ melden. Der ungefähre Code lautet wie folgt:

Blockierender (Warte-)Modus

$fp = fopen("lock.txt", "w+");if(flock($fp,LOCK_EX)) { // 锁定当前指针,,,
    //..处理订单
    flock($fp,LOCK_UN);
}fclose($fp);

Nicht-blockierender Modus

$fp = fopen("lock.txt", "w+");if(flock($fp,LOCK_EX | LOCK_NB)) {    //..处理订单
    flock($fp,LOCK_UN);
} else {  echo "系统繁忙,请稍后再试";
}fclose($fp);

5 Wenn es sich um einen verteilten Cluster-Server handelt, benötigen Sie einen oder Mehr Warteschlangenserver Xiaomi Es unterscheidet sich geringfügig vom Eilkauf in Taobao. Sobald Sie das Kontingent erhalten haben, können Sie eine Bestellung aufgeben und die Zahlung begleichen. Taobao hingegen konzentriert sich auf die Filterung während der Zahlung. Wenn beispielsweise 10 Artikel verkauft werden sollen, werden diese während der Zahlung gleichzeitig gefiltert Dadurch wird die Anzahl der Elemente Schicht für Schicht im Handumdrehen reduziert.

6. Verwenden Sie die Redis-Sperre „product_lock_key“ als Ticket-Sperrschlüssel. Wenn „product_key“ in Redis vorhanden ist, können alle Benutzer den Bestellvorgang starten. Wenn Sie den Zahlungsvorgang aufrufen, speichern Sie zunächst sadd(product_lock_key, „1“) in Redis. Wenn die Rückgabe erfolgreich ist, geben Sie den Zahlungsvorgang ein. Wenn dies fehlschlägt, bedeutet dies, dass bereits jemand in den Zahlungsvorgang eingetreten ist. Der Thread wartet N Sekunden und führt die Sadd-Operation rekursiv aus.


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn