Solutions for high concurrency scenarios like seckill

Keywords: PHP Redis REST

Atomic transaction operation of redis

<?php

$http = new swoole_http_server("0.0.0.0", 9509);   // Monitor 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);    // Simulate unique user ID

    $redis = new Redis();

    $redis->connect('127.0.0.1', 6379);    // Connect redis

 

    $redis->watch('rest_count');  // Monitor rest_count Is it changed by other processes?

 

    $rest_count = intval($redis->get("rest_count"));  // Simulate unique order ID

    if ($rest_count > 0){

        $value = "{$rest_count}-{$uniqid}";  // Indicates the current order, which is seized by the current user

 

        // do something... Is mainly to simulate some intensive operations that may be carried out after the user grabs the order.

        $rand  = rand(100, 1000000);

        $sum = 0;

        for ($i = 0; $i < $rand; $i++) {$sum += $i;}

 

      // redis affair

        $redis->multi();

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

        $redis->decr('rest_count');

        $replies = $redis->exec();  // Execute above redis affair

 

      // If the value of "rest" count is changed by other concurrent processes, the above transactions will be rolled back

        if (!$replies) {

            echo "Order {$value} RollBACK" . PHP_EOL;

        }

    }

    $redis->unwatch();

});

 

$http->start();

2

Using file exclusive lock (blocking mode)

In blocking mode, if other processes are occupying the lock when the process acquires the exclusive lock of the file, the process will suspend and wait for other processes to release the lock, acquire the lock itself, and then execute again.

<?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+");

 

    // block(wait for)Mode, to get exclusive lock (written program)

    if (flock($fp,LOCK_EX)) {  //Lock current pointer

 

      // Handle orders with confidence after successful lock acquisition

        $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');

        }

 

      // Release the lock after the order processing is completed

        flock($fp, LOCK_UN);

    }

    fclose($fp);

 

});

 

$http->start();

III. using file exclusive lock (non blocking mode)

In non blocking mode, if other processes are occupying the lock while acquiring the exclusive lock of the file, the process will immediately judge the failure of acquiring the lock and continue to execute. "

$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+");

 

    // Nonblocking mode, if you do not want flock() If it is blocked during locking, the lock Add LOCK_NB

    if(flock($fp,LOCK_EX | LOCK_NB))   //Lock current pointer

    {

      // Handle orders with confidence after successful lock acquisition

        $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');

        }

 

      // Release the lock after the order processing is completed

        flock($fp,LOCK_UN);

    } else {

      // If the lock acquisition fails, enter here to execute immediately

        echo "{$uniqid} - The system is busy. Please try again later".PHP_EOL;

    }

    fclose($fp);

 

});

 

$http->start();

Three ways 1, 3, 2

Posted by chu70077 on Thu, 17 Oct 2019 08:53:18 -0700