In seconds kill, snapping up concurrent scenarios, such as oversold phenomenon, may arise in the PHP language was not native with concurrent solutions, so you need to use other ways to achieve concurrency control, there are a variety of solutions, today just for chestnut topic, there are other better solution you can go to play.

The three common solutions listed are:

With queues, where an extra process processes the queue and concurrent requests are placed in the queue and processed sequentially by the extra process, the concurrency problem does not exist, but the additional process support and processing delays are significant enough that this approach is not discussed in this article.

Using the database transaction characteristics to do atomic update, this method needs to rely on the database transaction characteristics.

With file-exclusive locking, flock can lock a file when processing an order request, and only after successfully obtaining the lock can the order be processed.

1. Use the Redis transaction feature

Redis transactions are atomic operations that ensure that the data is not modified by other concurrent processes while the order is being processed.

Example code:


      
$http = new swoole_http_server("0.0.0.0".9509);   / / to 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 the unique user ID
 $redis = new Redis();
 $redis->connect('127.0.0.1'.6379);    / / connect to redis
 $redis->watch('rest_count');  // Check whether rest_count has been changed by other processes
 $rest_count = intval($redis->get("rest_count"));  // Simulate a unique order ID
 if ($rest_count > 0) {$value = "{$rest_count}-{$uniqid}";  // indicates the current order, which is grabbed by the current user
 // do something ... It mainly simulates some intensive operations that users may have to carry out after grabbing the order
 $rand = rand(100.1000000);
 $sum = 0;
 for ($i = 0; $i < $rand; $i{+ +)$sum+ =$i; }/ / redis transactions
 $redis->multi();
 $redis->lPush('uniqids'.$value);
 $redis->decr('rest_count');
 $replies = $redis->exec();  // Execute the above redis transaction
 If the rest_count value is changed by another concurrent process, the transaction will be rolled back
 if (!$replies) {
 echo "The order{$value}Roll back". PHP_EOL; }}$redis->unwatch();
});
$http->start();
Copy the code

Using ab tests

$ ab -t 20 -c 10 http:/ / 192.168.1.104, : 9509 /
Copy the code

2. Using file exclusive locking (blocking mode)

In blocking mode, if a process acquires a file exclusive lock while another process is holding the lock, the process suspends until the other process releases the lock, and then acquires the lock itself before proceeding.

Example code:


      
$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) mode to obtain exclusive lock (write program)
 if (flock($fp,LOCK_EX)) {  // Lock the current pointer
 // After the lock is successfully obtained, the order can be safely processed
 $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 is processed
 flock($fp, LOCK_UN);
 }
 fclose($fp);
});
$http->start();
Copy the code

Using ab tests

$ ab -t 20 -c 10 http:/ / 192.168.1.104, : 9510 /
Copy the code

3. Use file exclusive locking (non-blocking mode)

In non-blocking mode, if a process acquies a file exclusive lock while another process is occupying the lock, the process immediately determines that the lock has failed and continues to execute. \

Example code:


      
$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+");
 // Non-blocking mode. If you don't want flock() to block when locking, add LOCK_NB to lock
 if(flock($fp,LOCK_EX | LOCK_NB))   // Lock the current pointer
 {
 // After the lock is successfully obtained, the order can be safely processed
 $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 is processed
 flock($fp,LOCK_UN);
 } else {
 // If the lock fails to be acquired, enter here immediately for execution
 echo "{$uniqid}- The system is busy, please try again later".PHP_EOL;
 }
 fclose($fp);
});
$http->start();
Copy the code

Using ab tests

$ ab -t 20 -c 10 http:/ / 192.168.1.104, : 9511 /
Copy the code

Finally, the test results of the three methods are compared

Redis transactions:

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
Copy the code

File exclusive locking (blocking mode) :

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
Copy the code

File exclusive locking (non-blocking mode) :

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
Copy the code

The test results show that the redis transaction mode is better than the file exclusive locking mode, while the non-blocking mode is better than the blocking mode.

The above content hope to help you, many PHPer in the advanced time will encounter some problems and bottlenecks, business code write too much without sense of direction, do not know where to start to improve, for this I sorted out some information, including but not limited to: Distributed Architecture, High Scalability, High Performance, High Concurrency, Server Performance Tuning, TP6, Laravel, Redis, Swoole, Swoft, Kafka, Mysql optimization, shell scripts, Docker, microservices, Nginx and other knowledge points advanced advanced dry goods need can be free to share with you, you need to click here PHP advanced architects >>> actual video, large factory interview documents for free access to