Heim  >  Artikel  >  Backend-Entwicklung  >  Mehrere Lösungen für PHP-Parallelitätsszenarien

Mehrere Lösungen für PHP-Parallelitätsszenarien

步履不停
步履不停Original
2019-07-01 15:30:333341Durchsuche

Mehrere Lösungen für PHP-Parallelitätsszenarien

In gleichzeitigen Szenarien wie Flash-Sales und Rush-Sales kann es zu Überverkäufen kommen. In der PHP-Sprache gibt es keine native Parallelitätslösung, daher müssen Sie einen anderen Weg nutzen, um dies zu erreichen Parallelitätskontrolle.

Die aufgeführten gängigen Lösungen sind:

  1. Verwenden Sie eine Warteschlange, starten Sie einen zusätzlichen Prozess zur Bearbeitung der Warteschlange, und gleichzeitige Anforderungen werden in die Warteschlange gestellt und seriell von der verarbeitet Bei einem zusätzlichen Prozess besteht kein Parallelitätsproblem, es sind jedoch zusätzliche Prozessunterstützung und schwerwiegende Verarbeitungsverzögerungen erforderlich. In diesem Artikel wird diese Methode nicht zuerst erläutert.
  2. Verwenden Sie die Transaktionsmerkmale der Datenbank, um atomare Aktualisierungen durchzuführen. Diese Methode basiert auf den Transaktionsmerkmalen der Datenbank.
  3. Mit Hilfe der exklusiven Dateisperre können Sie bei der Bearbeitung einer Bestellanfrage eine Datei mit Flock sperren. Nur diejenigen, die die Sperre erfolgreich erhalten, können die Bestellung bearbeiten.

1. Redis-Transaktionsfunktionen nutzen

Redis-Transaktionen sind atomare Vorgänge, die sicherstellen können, dass die Daten während der Auftragsverarbeitung nicht durch andere gleichzeitige Prozesse geändert werden.

Beispielcode:

<?php
$http = new swoole_http_server("0.0.0.0", 9509);   // 监听 9509

$http->set(array(
    'reactor_num' => 2,  //reactor thread num
    'worker_num' => 4    //worker process num
));

$http->on('request', function (swoole_http_request $request, swoole_http_response $response) {
    $uniqid = uniqid('uid-', TRUE);    // 模拟唯一用户ID
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);    // 连接 redis

    $redis->watch('rest_count');  // 监测 rest_count 是否被其它的进程更改

    $rest_count = intval($redis->get("rest_count"));  // 模拟唯一订单ID
    if ($rest_count > 0){
        $value = "{$rest_count}-{$uniqid}";  // 表示当前订单,被当前用户抢到了

        // do something ... 主要是模拟用户抢到单后可能要进行的一些密集运算
        $rand  = rand(100, 1000000);
        $sum = 0;
        for ($i = 0; $i < $rand; $i++) {$sum += $i;}

      // redis 事务
        $redis->multi();
        $redis->lPush('uniqids', $value);
        $redis->decr('rest_count');
        $replies = $redis->exec();  // 执行以上 redis 事务

      // 如果 rest_count 的值被其它的并发进程更改了,以上事务将回滚
        if (!$replies) {
            echo "订单 {$value} 回滚" . PHP_EOL;
        }
    }
    $redis->unwatch();
});

$http->start();

Ab-Test verwenden

$ ab -t 20 -c 10 http://192.168.1.104:9509/

2. Datei-Exklusivsperre verwenden (Blockierungsmodus)

Im Blockierungsmodus, wenn der Prozess ausgeführt wird Erwerb Wenn die Datei exklusiv gesperrt ist und andere Prozesse die Sperre belegen, bleibt der Prozess hängen und wartet darauf, dass andere Prozesse die Sperre aufheben. Anschließend erhält er die Sperre selbst, bevor er fortfährt.

Beispielcode:

<?php
$http = new swoole_http_server("0.0.0.0", 9510);

$http->set(array(
    'reactor_num' => 2,  //reactor thread num
    'worker_num' => 4    //worker process num
));

$http->on('request', function (swoole_http_request $request, swoole_http_response $response) {

    $uniqid = uniqid('uid-', TRUE);
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);

    $fp = fopen("lock.txt", "w+");

    // 阻塞(等待)模式, 要取得独占锁定(写入的程序)
    if (flock($fp,LOCK_EX)) {  //锁定当前指针

      // 成功取得锁后,放心处理订单
        $rest_count = intval($redis->get("rest_count"));
        $value = "{$rest_count}-{$uniqid}";
        if ($rest_count > 0) {
            // do something ...
            $rand = rand(100, 1000000);
            $sum = 0;
            for ($i = 0; $i < $rand; $i++) {$sum += $i;}

            $redis->lPush('uniqids', $value);
            $redis->decr('rest_count');
        }

      // 订单处理完成后,再释放锁
        flock($fp, LOCK_UN);
    }
    fclose($fp);

});

$http->start();

Ab-Test verwenden

$ ab -t 20 -c 10 http://192.168.1.104:9510/

3. Datei-exklusive Sperre verwenden (nicht blockierender Modus)

Im nicht blockierenden Modus Wenn der Prozess beim Erwerb einer exklusiven Dateisperre andere Prozesse die Sperre belegt, stellt der Prozess sofort fest, dass der Erwerb der Sperre fehlgeschlagen ist, und setzt die Ausführung fort.

Beispielcode:

<?php
$http = new swoole_http_server("0.0.0.0", 9511);

$http->set(array(
    'reactor_num' => 2,  //reactor thread num
    'worker_num' => 4    //worker process num
));

$http->on('request', function (swoole_http_request $request, swoole_http_response $response) {

    $uniqid = uniqid('uid-', TRUE);
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);

    $fp = fopen("lock.txt", "w+");

    // 非阻塞模式, 如果不希望 flock() 在锁定时堵塞,则给 lock 加上 LOCK_NB
    if(flock($fp,LOCK_EX | LOCK_NB))   //锁定当前指针
    {
      // 成功取得锁后,放心处理订单
        $rest_count = intval($redis->get("rest_count"));
        $value = "{$rest_count}-{$uniqid}";
        if($rest_count > 0){
            // do something ...
            $rand  = rand(100, 1000000);
            $sum=0;
            for ($i=0;$i<$rand;$i++){ $sum+=$i; }

            $redis->lPush('uniqids', $value);
            $redis->decr('rest_count');
        }

      // 订单处理完成后,再释放锁
        flock($fp,LOCK_UN);
    } else {
      // 如果获取锁失败,马上进入这里执行
        echo "{$uniqid} - 系统繁忙,请稍后再试".PHP_EOL;
    }
    fclose($fp);

});

$http->start();

Ab-Test verwenden

$ ab -t 20 -c 10 http://192.168.1.104:9511/

Abschließend werden die Testergebnisse der drei Verarbeitungsmethoden verglichen

Redis-Transaktionsmethode:

......
Concurrency Level:      10
Time taken for tests:   20.005 seconds
Complete requests:      17537
Failed requests:        0
Total transferred:      2578380 bytes
HTML transferred:       0 bytes
Requests per second:    876.62 [#/sec] (mean)
Time per request:       11.407 [ms] (mean)
Time per request:       1.141 [ms] (mean, across all concurrent requests)
Transfer rate:          125.86 [Kbytes/sec] received
......

Exklusive Dateisperre (Blockierungsmodus):

......
Concurrency Level:      10
Time taken for tests:   20.003 seconds
Complete requests:      8205
Failed requests:        0
Total transferred:      1206282 bytes
HTML transferred:       0 bytes
Requests per second:    410.19 [#/sec] (mean)
Time per request:       24.379 [ms] (mean)
Time per request:       2.438 [ms] (mean, across all concurrent requests)
Transfer rate:          58.89 [Kbytes/sec] received
......

Exklusive Dateisperre (nicht blockierender Modus):

......
Concurrency Level:      10
Time taken for tests:   20.002 seconds
Complete requests:      8616
Failed requests:        0
Total transferred:      1266846 bytes
HTML transferred:       0 bytes
Requests per second:    430.77 [#/sec] (mean)
Time per request:       23.214 [ms] (mean)
Time per request:       2.321 [ms] (mean, across all concurrent requests)
Transfer rate:          61.85 [Kbytes/sec] received
......

Nach dem Vergleich der Testergebnisse ist die Redis-Transaktionsmethode besser als Die dateiexklusive Sperrmethode Im dateiexklusiven Sperrmodus ist der nicht blockierende Modus besser als der blockierende Modus.

Weitere technische Artikel zum Thema PHP finden Sie in der Spalte PHP-Tutorial, um mehr darüber zu erfahren!

Das obige ist der detaillierte Inhalt vonMehrere Lösungen für PHP-Parallelitätsszenarien. 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