Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to solve the problem of High concurrency in PHP

2025-01-15 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

Most people do not understand the knowledge points of this article "how to solve the high concurrency problem of PHP", so the editor summarizes the following content, detailed content, clear steps, and has a certain reference value. I hope you can get something after reading this article. Let's take a look at this "how to solve the problem of high concurrency of PHP" article.

The second kill will produce a high concurrency in an instant, and using the database will increase the access pressure of the database and reduce the access speed, so we should use cache to reduce the access pressure of the database.

You can see that the operation here is different from the original order: the second kill advance order generated will not be written to the database immediately, but will be written to the cache first, and when the user pays successfully, the status will be modified and written to the database.

Suppose num is a field stored in the database that holds the remaining number of products that were killed in seconds.

If ($num > 0) {/ / user snapped up successfully. Record user information $num--;}

Suppose that in a scenario with high concurrency, when the value of num in the database is 1, multiple processes may read num as 1 at the same time, and the program determines that the condition is met, and the num is reduced by one.

This will lead to overdistribution of goods. There are only 10 items that can be snapped up, which may be grabbed by more than 10 people. At this time, the num is negative after the rush purchase is completed.

There are many solutions to solve this problem, which can be simply divided into solutions based on mysql and redis. The performance of redis is due to mysql, so it can carry higher concurrency. However, the solutions described below are all based on a single mysql and redis, and higher concurrency requires distributed solutions, which are not covered in this article.

1. Mysql-based solution

Commodity list goods

CREATE TABLE `goods` (`id` int (11) NOT NULL, `num` int (11) DEFAULT NULL, `version` int (11) DEFAULT NULL, PRIMARY KEY (`id`) ENGINE=InnoDB DEFAULT CHARSET=utf8

Panic purchase result table log

CREATE TABLE `log` (`id` int (11) NOT NULL AUTO_INCREMENT, `good_ id` int (11) DEFAULT NULL, PRIMARY KEY (`id`) ENGINE=InnoDB DEFAULT CHARSET=utf8

① pessimistic lock

The pessimistic locking scenario uses exclusive reading, that is, only one process can read the value of num at a time. After the transaction is committed or rolled back, the lock is released so that other processes can read it.

The scheme is the most simple and easy to understand, and it can be used directly when the performance requirement is not high. It is important to note that SELECT... FOR UPDATE should use indexes as much as possible to lock as few rows as possible

Exclusive locks are released after the completion of transaction execution, not after reading, so transactions used should be committed or rolled back as early as possible to release exclusive locks as early as possible.

$this- > mysqli- > begin_transaction (); $result = $this- > mysqli- > query ("SELECT num FROM goods WHERE id=1 LIMIT 1 FOR UPDATE"); $row = $result- > fetch_assoc (); $num= intval ($row ['num']); if ($num > 0) {usleep (100); $this- > mysqli- > query ("UPDATE goods SET num=num-1"); $affected_rows = $this- > mysqli- > affected_rows If ($affected_rows = = 1) {$this- > mysqli- > query ("INSERT INTO log (good_id) VALUES ({$num})"); $affected_rows = $this- > mysqli- > affected_rows; if ($affected_rows = = 1) {$this- > mysqli- > commit (); echo "success:". $num;} else {$this- > mysqli- > rollback (); echo "fail1:". $num;}} else {$this- > mysqli- > rollback () Echo "fail2:". $num;}} else {$this- > mysqli- > commit (); echo "fail3:". $num;}

② optimistic lock

The optimistic lock scheme does not add an exclusive lock to read the data, but solves the problem that multiple processes read the same num and then update successfully through a version field that increases itself with each update. When each process reads num, it also reads the value of version, and updates version while updating num, and adds the equivalent judgment of version when updating.

Suppose 10 processes read that the value of num is 1 and the version value is 9, then the update statements executed by these 10 processes are all UPDATE goods SET num=num-1,version=version+1 WHERE version=9.

However, when one of the processes executes successfully, the value of version in the database will become 10, and the remaining 9 processes will not execute successfully, which ensures that the goods will not be overissued, and the value of num will not be less than 0, but this also leads to a problem, that is, the earlier users who issued the rush purchase request may not be able to grab it, but will be robbed by the later request.

$result = $this- > mysqli- > query ("SELECT num,version FROM goods WHERE id=1 LIMIT 1"); $row = $result- > fetch_assoc (); $num= intval ($row ['num']); $version= intval ($row [' version']); if ($num > 0) {usleep (100); $this- > mysqli- > begin_transaction (); $this- > mysqli- > query ("UPDATE goods SET num=num-1,version=version+1 WHERE version= {$version}"); $affected_rows = $this- > mysqli- > affected_rows If ($affected_rows = = 1) {$this- > mysqli- > query ("INSERT INTO log (good_id) VALUES ({$num})"); $affected_rows = $this- > mysqli- > affected_rows; if ($affected_rows = = 1) {$this- > mysqli- > commit (); echo "success:". $num;} else {$this- > mysqli- > rollback (); echo "fail1:". $num;}} else {$this- > mysqli- > rollback () Echo "fail2:". $num;}} else {echo "fail3:". $num;}

③ where condition (atomic operation)

The pessimistic locking scheme ensures that the value of num in the database can only be read and processed by one process at a time, that is, concurrent reading processes are queued for execution.

Optimistic lock scheme although the value of num can be read by multiple processes at the same time, the equivalence judgment of version in update operation can ensure that only one concurrent update operation can be updated successfully at the same time.

There is also a simpler solution, which only adds a condition restriction of num > 0 to the update operation. Although the schemes restricted by where conditions seem to be similar to optimistic locking schemes, they can prevent the occurrence of oversending problems, but the performance is still very different when the num is large.

If the num is 10 and five processes read the num=10 at the same time, for the optimistic lock scheme, due to the equivalent judgment of the version field, only one of the five processes will be updated successfully, and the num will be 9 after the execution of the five processes.

For the scheme of where condition judgment, as long as num > 0, the num is 5 after the completion of the execution of the five processes.

$result = $this- > mysqli- > query ("SELECT num FROM goods WHERE id=1 LIMIT 1"); $row = $result- > fetch_assoc (); $num= intval ($row ['num']); if ($num > 0) {usleep (100); $this- > mysqli- > begin_transaction (); $this- > mysqli- > query ("UPDATE goods SET num=num-1 WHERE num > 0"); $affected_rows = $this- > mysqli- > affected_rows If ($affected_rows = = 1) {$this- > mysqli- > query ("INSERT INTO log (good_id) VALUES ({$num})"); $affected_rows = $this- > mysqli- > affected_rows; if ($affected_rows = = 1) {$this- > mysqli- > commit (); echo "success:". $num;} else {$this- > mysqli- > rollback (); echo "fail1:". $num;}} else {$this- > mysqli- > rollback () Echo "fail2:". $num;}} else {echo "fail3:". $num;} II. Redis-based solution

Optimistic locking Scheme of ① based on watch

Watch is used to monitor one (or more) key, and if the key (or these) is altered by other commands before the transaction is executed, the transaction will be interrupted.

This scheme is similar to the optimistic locking scheme in mysql, and the performance is the same.

$num = $this- > redis- > get ('num'); if ($num > 0) {$this- > redis- > watch (' num'); usleep (100); $res = $this- > redis- > multi ()-> decr ('num')-> lPush (' result',$num)-> exec (); if ($res = = false) {echo "fail1";} else {echo "success:". $num;}} else {echo "fail2";

② queue Scheme based on list

The queue-based scheme takes advantage of the atomicity of the redis dequeue operation. Before the rush purchase starts, the item number is first placed in the response queue, and the operation is popped out of the queue in turn during the rush purchase, which ensures that each item can only be obtained and operated by one process, and there is no overdelivery.

The advantage of this scheme is that it is easy to understand and implement, but the disadvantage is that when there are a large number of goods, a large amount of data needs to be stored in the queue, and different goods need to be stored in different message queues.

Public function init () {$this- > redis- > del ('goods'); for ($iridis > lPush (' goods',$i);} $this- > redis- > del ('result'); echo' init done';} public function run () {$goods_id = $this- > redis- > rPop ('goods'); usleep (100); if ($goods_id = = false) {echo "fail1";} else {$res = $this- > redis- > lPush (' result',$goods_id) If ($res = = false) {echo "writelog:". $goods_id;} else {echo "success". $goods_id;}

The scheme of ③ based on decr return value

If we set the remaining num to a key value type, the problem of oversending will not be solved by get and then decr each time.

However, the decr operation in redis will return the result after execution, which can solve the problem of oversending. We first determine the value from get to num to avoid updating the value of num every time, then perform decr operation on num and judge the return value of decr. If the returned value is not less than 0, it means that decr was greater than 0 and users snapped up successfully.

Public function run () {$num = $this- > redis- > get ('num'); if ($num > 0) {usleep (100); $retNum = $this- > redis- > decr (' num'); if ($retNum > = 0) {$res = $this- > redis- > lPush ('result',$retNum); if ($res = = false) {echo "writeLog:". $retNum;} else {echo "success:". $retNum } else {echo "fail1";}} else {echo "fail2";}}

④ exclusive lock scheme based on setnx

Redis does not have exclusive locks like those in mysql, but exclusive locks can be implemented in some ways, just as php uses file locks to implement exclusive locks.

Setnx implements the functions of exists and set instructions. If a given key already exists, setnx does not do any action and returns 0; if key does not exist, it performs an operation similar to set and returns 1.

We set a timeout timeout and try the setnx operation every certain time. If the setting is successful, we obtain the corresponding lock, execute the decr operation of the num, delete the corresponding key, and simulate the operation of releasing the lock.

Public function run () {do {$res = $this- > redis- > setnx ("numKey", 1); $this- > timeout-= 100; usleep (100);} while ($res = = 0 & & $this- > timeout > 0); if ($res = 0) {echo 'fail1';} else {$num = $this- > redis- > get (' num'); if ($num > 0) {$this- > redis- > decr ('num'); usleep (100) $res = $this- > redis- > lPush ('result',$num); if ($res = = false) {echo "fail2";} else {echo "success:". $num;}} else {echo "fail3";} $this- > redis- > del ("numKey") }} the above is the content of this article on "how to solve the problem of high concurrency in PHP". I believe we all have a certain understanding. I hope the content shared by the editor will be helpful to you. If you want to know more about the relevant knowledge, please follow the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report