手机版

php和存储实现秒杀活动的流程

时间:2021-08-21 来源:互联网 编辑:宝哥软件园 浏览:

一说明

前段时间面试的时候,一直被问到如何设计一个秒杀活动,但是无奈没有此方面的实际经验,所以只好凭着自己的理解和一些资料去设计这么一个程序

主要利用到了存储的线和字符串集主要是利用它的k-v结构去对库存进行处理,也可以用目录的数据结构来处理商品的库存,设置则用来确保用户进行重复的提交

其中我们最主要解决的问题是

-防止并发产生超抢/超卖

2流程设计

3代码

3.1 服务端代码

类苗莎{ const MSG_REPEAT_USER='请勿重复参与;'' const MSG_EMPTY_STOCK='库存不足;const MSG_KEY_NOT_EXIST='key不存在;const IP _ POLL=' IP _ POLL const USER _ POLL=' USer _ POLL/* * @ var Redis */public $ Redis;public $ key public function _ _ construct($ key=' '){ $ this-CheckKey($ key);$ this-Redis=new Redis();//todo连接池$ this-redis-connect(' 127。0 .0 .1 ');}公共函数checkKey($key='') { if(!$ key){ 0抛出新异常(self :3360 msg _ KEY _ NOT _ EXIST);} else { $ this-key=$ key;} }公共函数setStock($ value=0){ if($ this-redis-exists($ this-key)=0){ $ this-redis-set($ this-key,$ value);} }公共函数checkIp($ip=0) { $sKey=$this-key .self:IP _ POOLif(!$ IP | | $ this-redis-SisMember($ Skey,$ IP)){ 0抛出新的异常(自身: msg _ REPEAT _ USER);} }公共函数check USer($ USer=0){ $ Skey=$ this-key .self:USER _ POOLif(!$ USER | | $ this-redis-SisMember($ Skey,$ USER)){ 0抛出新的异常(自身: msg _ REPEAT _ USER);} }公共函数checkStock($user=0,$ IP=0){ $ num=$ this-redis-decr($ this-key);if($ num 0){ 0抛出新的异常(self : msg _ EMPTY _ STOCK);} else { $ this-redis-SadD($ this-key).self:USER_POOL,$ user);$this-redis-sAdd($this-key .self:IP_POOL,$ IP);//todo添加到mysql echo "成功"。PHP _ EOL错误日志('成功。$用户.PHP_EOL,3 ',/var/www/html/demo/log/debug。日志';} } /** * @note:此种做法不能防止并发* @ func checkStockFail * @ param int $ user * @ param int $ IP * @抛出异常*/public func checkStockFail($ user=0,$ IP=0){ $ num=$ this-redis-get($ this-key);if($ num 0){ $ this-redis-sAdd($ this-key).self:USER_POOL,$ user);$this-redis-sAdd($this-key .self:IP_POOL,$ IP);//todo添加到mysql echo "成功"。PHP _ EOL错误日志('成功。$用户.PHP_EOL,3 ',/var/www/html/demo/log/debug。日志';$ num-;$this-redis-set($this-key,$ num);} else {抛出新异常(self :3360 msg _ EMPTY _ STOCK);} }}

3.2 客户端测试代码

function test(){ try { $ key=' cup _ ';$handler=新苗莎($ key);$ handler-setStock(10);$user=兰特(1,10000);$ IP=$ user $ handler-CheckIP($ IP);$ handler-检查用户($ user);$handler-checkStock($user,$ IP);} catch(\ Exception $ e){ echo $ e-getMessage().PHP _ EOLerror _ log(失败).$e-getMessage().PHP_EOL,3 ',/var/www/html/demo/log/debug。日志';} }函数测试2(){ try { $ key=' cup _ ';$handler=新苗莎($ key);$ handler-setStock(10);$user=兰特(1,10000);$ IP=$ user $ handler-CheckIP($ IP);$ handler-检查用户($ user);$handler-checkStockFail($user,$ IP);//不能防止并发的} catch(\ Exception $ e){ echo $ e-getMessage().PHP _ EOLerror _ log(失败).$e-getMessage().PHP_EOL,3 ',/var/www/html/demo/log/debug。日志';}}

四测试

测试环境说明

ubantu16.04 redis2.8.4 php5.5在服务端代码里面我们有两个函数分别是检查库存和checkStockFail,其中checkStockFail不能在高并发的情况下效果很差,不能在存储层面保证库存为0的时候终止操作。

我们利用腹肌工具进行测试

其中www.hello.com是配置的虚拟主机名称flash-sale.php是我们脚本的名称

#第一种情况500并发下用客户端的测试2()去执行ab-n 500-c 100 www.hello.com/flash-sale.php

原木日志的记录结果:

#在第二种情况下,5000使用客户端的test2()来执行AB-N 5000-C 1000 www.hello.com/flash-sale.php

记录日志:的结果

#第三种情况500使用客户端的测试()来执行AB-n500-c100 www.hello.com/flash-sale.phplog日志:的记录结果

#在第四种情况下,5000使用客户端的测试()来执行AB-N 5000-C 1000 www.hello.com/flash-sale.php

记录日志:的结果

5摘要

从日志中我们可以清楚地看到,在案例3和案例4中,货物的数量总是可以保证为我们设定的库存值的10倍,但是在案例1和案例2中,会发生超卖

Redis主要利用其api是原子操作的优势来控制并发。从checkStock和checkStockFail可以看出,一种是直接从库存中减去一,所以没有并发性,但另一种方法是先取出库存值,减去一再重新赋值。在这种情况下,在并发下,多个进程将读取多个库存值1,这将导致超卖。

以上就是边肖介绍的用php和redis实现spike活动的过程,希望对大家有所帮助。如果你有任何问题,请给我留言,边肖会及时回复你。非常感谢您对我们网站的支持!如果你觉得这篇文章对你有帮助,请转载,请注明出处,谢谢!

版权声明:php和存储实现秒杀活动的流程是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。