Heim  >  Artikel  >  Backend-Entwicklung  >  So lösen Sie hohe Parallelität in PHP

So lösen Sie hohe Parallelität in PHP

小云云
小云云Original
2018-03-26 10:39:506039Durchsuche

In diesem Artikel erfahren Sie hauptsächlich, wie Sie hohe Parallelität in PHP lösen können. Wenn es um Eilkäufe, Flash-Verkäufe, Lotterieziehungen, Ticketraub und andere Aktivitäten geht, ist die Lagerbestandsmenge begrenzt, aber wenn Die Anzahl der Personen, die gleichzeitig Bestellungen aufgeben, übersteigt die Lagermenge. Dies führt zu Überverkaufsproblemen. Wie lösen wir dieses Problem? Meine Idee ist wie folgt (Pseudocode):

sql1: Produktinventar abfragen

if(库存数量 > 0)
{
  //生成订单...
  sql2:同时库存-1
}

Wenn keine Parallelität besteht, sieht der obige Prozess aus Es scheint normal zu sein. Angenommen, zwei Personen geben gleichzeitig eine Bestellung auf und es ist nur 1 Artikel auf Lager. In der SQL1-Phase ist der von beiden Personen abgefragte Lagerbestand > 0, sodass sie schließlich SQL2 und den Lagerbestand ausführen wird -1. , überverkauft, das ist nicht das gewünschte Ergebnis.

Ich habe die gängigeren Ideen zur Lösung dieses Problems zusammengefasst:
1. Verwenden Sie einen zusätzlichen Einzelprozess, um eine Warteschlange zu bearbeiten, Bestellanfragen in die Warteschlange zu stellen und sie einzeln zu bearbeiten, damit dies der Fall ist Es gibt keine Parallelität. Es ist ein Problem, aber es erfordert zusätzliche Hintergrundprozesse und Verzögerungen, 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 beispielsweise der Gesamtbestand 2 beträgt. Wenn das Eilkaufereignis übermittelt wird, beträgt der Bestand sofort +1, dann beträgt der Bestand zu diesem Zeitpunkt 3 und dann die Bestellung generiert, wird der Lagerbestand erneut abgefragt, bevor der Lagerbestand aktualisiert wird (denn Wenn eine Bestellung generiert wird, ist der Lagerbestand natürlich -1, aber keine Sorge, überprüfen Sie den Lagerbestand erneut und das Rückgabeergebnis ist 3), um festzustellen, ob dies der Fall ist stimmt mit der erwarteten Lagerbestandsmenge überein (der erwartete Lagerbestand beträgt hier 3), führen Sie einen Rollback durch und weisen Sie den Benutzer darauf hin, dass der Lagerbestand nicht ausreicht. 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 eine Auswahl zur Aktualisierung ausführt, erhält sie die Zeilensperre der Datenzeile in der Auswahl, sodass andere gleichzeitig ausgeführte Auswahlen ausgeführt werden Wenn bei der Aktualisierung versucht wird, dieselbe Zeile auszuwählen, kommt es zum Ausschluss (es muss gewartet werden, bis die Zeilensperre aufgehoben wird), wodurch der Sperreffekt erzielt 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. Das heißt, wir sind „optimistisch“ und glauben, dass die Sperre höchstwahrscheinlich erfolgreich sein wird. Nehmen Sie die Sperre also einfach nach dem letzten Schritt der tatsächlichen Aktualisierung der Daten nach Abschluss des Geschäftsbetriebs vor.

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 …;2. 根据获取的数据进行业务操作,得到new_data和new_version3. UPDATE SET data = new_data, version = new_version WHERE version = old_versionif (updated row > 0) {    // 乐观锁获取成功,操作完成
} else {    // 乐观锁获取失败,回滚并重试
}

乐观锁是否在事务中其实都是无所谓的,其底层机制是这样:在数据库内部update同一行的时候是不允许并发的,即数据库每次执行一条update语句时会获取被update行的写锁,直到这一行被成功更新后才释放。因此在业务操作进行前获取需要锁的数据的当前版本号,然后实际更新数据时再次对比版本号确认与之前获取的相同,并更新版本号,即可确认这之间没有发生并发的修改。如果更新失败即可认为老版本的数据已经被并发修改掉而不存在了,此时认为获取锁失败,需要回滚整个业务操作并可根据需要重试整个过程。好吧,在此唠叨总结下这两个锁:

  • 乐观锁在不发生取锁失败的情况下开销比悲观锁小,但是一旦发生失败回滚开销则比较大,因此适合用在取锁失败概率比较小的场景,可以提升系统并发性能

  • 乐观锁还适用于一些比较特殊的场景,例如在业务操作过程中无法和数据库保持连接等悲观锁无法适用的地方

3.根据update结果来判断,我们可以在sql2的时候加一个判断条件update table set 库存=xxx where 库存>0,如果返回false,则说明库存不足,并回滚事务。
4.借助文件排他锁,在处理下单请求的时候,用flock锁定一个文件,如果锁定失败说明有其他订单正在处理,此时要么等待要么直接提示用户"服务器繁忙"

大致代码如下:
阻塞(等待)模式

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

非阻塞模式

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

5.如果是分布式集群服务器,就需要一个或多个队列服务器 小米和淘宝的抢购还是有稍许不同的,小米重在抢的那瞬间,抢到了名额,就是你的,你就可以下单结算。而淘宝则重在付款的时候的过滤,做了多层过滤,比如要卖10件商品,他会让大于10的用户抢到,在付款的时候再进行并发过滤,一层层的减少一瞬间的并发量。

6.使用redis锁 product_lock_key 为票锁key 当product_key存在于redis中时,所有用户都可以进入下单流程。 当进入支付流程时,首先往redis存放sadd(product_lock_key, “1″),如果返回成功,进入支付流程。如果不成,则说明已经有人进入支付流程,则线程等待N秒,递归执行sadd操作。

当然类似于淘宝双11的疯抢架构远远比我说滴这些复杂多啦....更多解决方案需要不停滴去实战中获取心得....大家有好的解决思路清随时共享留言哈。

相关推荐:

php高并发应当用Apache还是IIS

php高并发访问写文件

php高并发下的疑问。

Das obige ist der detaillierte Inhalt vonSo lösen Sie hohe Parallelität in PHP. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

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