Php+redis Message Queuing Implementation snapping steps (with code)

Source: Internet
Author: User
This time to bring you php+redis Message Queuing to achieve snapping steps in detail (with code), Php+redis message queue to achieve the attention of snapping, the following is the actual case, together to see.

Implementation features:

1. Based on Redis queue, prevent high concurrency of oversold
2. mysql-based transaction lock to prevent high concurrent oversold

Based on the Redis queue workflow:

1. The administrator creates the Redis commodity inventory queue based on the inventory in the goods table
2. Client Access seconds Kill API
3. The Web server first queries the remaining inventory key content from the Redis inventory queue
4. Redis queue has surplus, then create order in MySQL, go to inventory, snapping success
5. There is no remaining in the Redis queue, then the inventory is insufficient and the focus of the failure is snapped.

Workflow based on MySQL transaction and exclusive lock:

1. Turn on the transaction
2. Check inventory and display the settings write lock (exclusive lock): SELECT * FROM goods WHERE id = 1 for UPDATE
3. Generate Order
4. Go to inventory, implicit set write lock (exclusive lock): UPDATE goods set counts = counts–1 WHERE id = 1
5. Commit, Release the lock

Note: The second step allows you to set a shared lock, or it may cause a deadlock.

Code:

<?php/*********************************************** Snapping Module * * @author liubin* @date 2016-02-10** ab-n 1000-c http ://192.168.16.73/seckill/buy.php**/class Seckill extends common{private $_ordermodel = null; private $_goodsmodel = null ; Private $_redis = null; /* * ERROR message */protected $_error = '; /** * * */Public Function construct () {if ($this->_ordermodel = = = null) {$this->_ordermodel = new Ordermod  El ();  } if ($this->_goodsmodel = = = null) {$this->_goodsmodel = new Goodsmodel ();   } if ($this->_redis = = = null) {$this->_redis = new Qredis ();  }}//* seconds Kill API * * @author Liubin * @date 2017-02-10 */Public Function addqsec () {$gid = Intval ($_get[' gid ']); $type = isset ($_get[' type ')?  $_get[' type ']: ' MySQL ';    Switch ($type) {case ' mysql ': $this->order_check_mysql ($gid);    echo $this->geterror ();   Break    Case ' Redis ': $this->order_check_redis ($gid);    echo $this->geterror ();   Break Case ' transaction ': $thiS->order_check_transaction ($gid);    echo $this->geterror ();   Break    Default:echo ' type error ';  Break  Get error message * * @author liubin * @date 2017-02-10 */Public Function GetError () {return $this->_error;}/*   * Based on MySQL verification inventory information * @desc High concurrency will cause oversold * * @author liubin * @date 2017-02-10 */protected function Order_check_mysql ($gid) {  $model = $this->_goodsmodel;  $pdo = $model->gethandler ();  $gid = Intval ($gid); /* * 1: $sql _forlock If no transaction, no write lock: * Oversold is very serious, do not say * 2: $sql _forlock If not added transaction, only write lock: * First session read $sql_forlock write lock, first session $sql   _forlock The row lock is released at the end of the query. * Second session after the first session is released read $sql_forlock write lock, will again $sql_forlock check inventory * cause oversold phenomenon * */$sql _forlock = ' SELECT * from goods where id =  '. $gid. ' Limit 1 for update ';  $sql _forlock = ' SELECT * from goods where id = '. $gid. ' Limit 1 ';  $result = $pdo->query ($sql _FORLOCK,PDO::FETCH_ASSOC);  $goodsInfo = $result->fetch ();   if ($goodsInfo [' counts ']>0) {//go to stock $gid = $goodsInfo [' id ']; $sql _inventory = ' UPDATE goods SET counts = counts-1 WHERE id = '. $gid;   $result = $this->_goodsmodel->exect ($sql _inventory);    if ($result) {//create order $data = [];    $data [' order_id '] = $this->_ordermodel->buildorderno ();    $data [' goods_id '] = $goodsInfo [' id '];    $data [' addtime '] = time ();    $data [' uid '] = 1;    $order _rs = $this->_ordermodel->create_order ($data);     if ($order _rs) {$this->_error = ' purchased successfully ';    return true;  }}} $this->_error = ' Insufficient inventory '; return false;  }/* * Verify inventory information based on Redis queue * @desc Redis is a single-threaded, command execution is atomic, including Lpush,lpop. High concurrency does not cause oversold * * @author Liubin * @date 2017-02-10  */protected function Order_check_redis ($gid) {$goodsInfo = $this->_goodsmodel->getgoods ($gid);   if (! $goodsInfo) {$this->_error = ' product does not exist ';  return false;  } $key = ' goods_list_ '. $goodsInfo [' id '];  $count = $this->_redis->gethandel ()->lpop ($key);   if (! $count) {$this->_error = ' Insufficient inventory ';  return false;  }//Generate Order $data = []; $data [' order_id '] = $this->_ordermodel->buildorderno ();  $data [' goods_id '] = $goodsInfo [' id '];  $data [' addtime '] = time ();  $data [' uid '] = 1;  $order _rs = $this->_ordermodel->create_order ($data);  Inventory Reduction $gid = $goodsInfo [' id '];  $sql = ' UPDATE goods SET counts = counts-1 WHERE id = '. $gid;  $result = $this->_goodsmodel->exect ($sql);  $this->_error = ' purchase success '; return true; }/* * Verify inventory information based on MySQL transaction * @desc transaction and row lock mode, high concurrency will not lead to oversold, but the efficiency will be slower * @author Liubin * @date 2017-02-10 Description: If $sql_forlock does not add  Write lock, when concurrent, $sql _forlock query record is more than 0, can reduce inventory operations. If $sql_forlock has a write lock, concurrent, $sql _forlock query is the query that waits for the first link to be released. So inventory is 5 */protected function order_check_transaction ($gid) {$  Model = $this->_goodsmodel;  $pdo = $model->gethandler ();  $gid = Intval ($gid); try{$pdo->begintransaction ();//Open Transaction */* 1: $sql _forlock If only transaction, no write Lock: * Open Transaction * Because there is no lock, read $sql_forlock, concurrency    Sql_inventory can be read again before. * $sql _inventory and before commit will be locked * There is no conflict between oversold and transactional consistency * * 2: $sql _forlock If you add a transaction and read the lock: * Open Transaction * FirstWhen the session reads the $sql_forlock lock, while concurrent, the second session also allows to obtain the $sql_forlock read lock, * But when the first session performs a go inventory operation (write lock), the write lock waits for the second session to read the lock, and the second session performs a write operation. The write lock waits for the first session to read the lock, * There is a deadlock * 3: $sql _forlock If a transaction is added and a write lock is added: * Open transaction * When the first session reads $sql_forlock The write lock is not released until the commit will release the write lock, and the concurrent query will not appear oversold    Like.   * */$sql _forlock = ' SELECT * from goods where id = '. $gid. ' Limit 1 for update ';   $sql _forlock = ' SELECT * from goods where id = '. $gid. ' Limit 1 LOCK in SHARE MODE ';   $sql _forlock = ' SELECT * from goods where id = '. $gid. ' Limit 1 ';   $result = $pdo->query ($sql _FORLOCK,PDO::FETCH_ASSOC);   $goodsInfo = $result->fetch ();    if ($goodsInfo [' counts ']>0) {//go to stock $gid = $goodsInfo [' id '];    $sql _inventory = ' UPDATE goods SET counts = counts-1 WHERE id = '. $gid;    $result = $this->_goodsmodel->exect ($sql _inventory);     if (! $result) {$pdo->rollback ();     $this->_error = ' Inventory reduction failed ';    return false;    }//Create order $data = [];    $data [' id '] = ' null '; $data [' order_id '] = $this->_ordermodel->buildorderno ();    $data [' goods_id '] = $goodsInfo [' id '];    $data [' uid '] = ' abc ';    $data [' addtime '] = time (); $sql = ' INSERT INTO orders (Id,order_id,goods_id,uid,addtime) VALUES ('. $data [' id ']. '. $data [' order_id ']. ' "," '. $       data[' goods_id ', ' "'. $data [' uid ']. '", "'. $data [' Addtime '].    $result = $pdo->exec ($sql);     if (! $result) {$pdo->rollback ();     $this->_error = ' order creation failed ';    return false;    } $pdo->commit ();//submit $this->_error = ' purchase success ';   return true;    }else{$this->_error = ' Insufficient inventory ';   return false;   }}catch (Pdoexception $e) {echo $e->getmessage ();  $pdo->rollback ();  }/* * Create order * MySQL thing processing, also can use stored procedure * */Private Function Create_order ($goodsInfo) {//Generate order $data = [];  $data [' order_id '] = $this->_ordermodel->buildorderno ();  $data [' goods_id '] = $goodsInfo [' id '];  $data [' addtime '] = time ();  $data [' uid '] = 1;  $order _rs = $this->_ordermodel->create_order ($data);  Inventory Reduction $gid = $goodsInfo [' id ']; $sql = ' UPDATE goods SET counts = counts-1 WHERE id = '. $gid;  $result = $this->_goodsmodel->exect ($sql); return true; }}

Believe that you have read the case of this article you have mastered the method, more exciting please pay attention to the PHP Chinese network other related articles!

Recommended reading:

PHP processing snapped high-class concurrent request implementation of the detailed

How PHP gets real-time CPU memory usage in Windows

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.