高并发库存控制_限购库存并发控制-程序员宅基地

技术标签: delay  string  function  高并发 库存 PHP  服务器  mysql  sql  

如今,在电商行业,秒杀活动已经是家常便饭,面对这种高并发压力之下,又有什么办法来缓解这种压力呢?

秒杀就像过年回家的时候买火车票,需要遵守以下几个原则:

1.公平性,机会均等,遵守FIFO原则。

2.快速处理能力,增加售票窗口,增加售票渠道。

3.稳定性,适当的入口数量,保证售票厅内人满为患。


那么,在现实开发当中,怎么去实现呢?以下图为例:


1.有n个购票者守候在售票大厅外面,交通方便的肯定会挤在靠近入口的位置,通过入口的机会就越大.

 好比秒杀时疯狂的购物者都在等待秒杀开始,大家都在刷新网页,带宽给力的肯定进去的胜算比较大.

2.我们设置了30个入口,因为我们没有更大的地方,因为现在地皮也比较贵,

 那么,对应到秒杀,这个入口就是我们服务器同时处理并发处理能力大小,如果我们通过控制这30个入口的吞吐量,

那我们就可以有效的控制住服务器接受外来的压力,把强大的力量堵在第一个关口,保证服务器接受到的压力能够快速处理.

3.这30个入口我们看做一个管道(tube),假定每一个购票者给大概5分钟可以完成购票,那么超过5分钟后或者已经买到票,就会让出位置让后面的人进入售票大厅,当然这是理想化想法,但至少我们把压力控制在我们可以处理的能力之内,要不然服务器宕机,欲哭无泪。


这是第一步,缓解了压力,让压力陆续进来,到这一步我们也可以松口气了,说了这么多该怎么实现呢?  Beanstalkd可以帮你,具体介绍请移步http://rdc.taobao.com/blog/cs/?p=1201

创建管道:

/** 
     * 创建管道 默认30个入口
     * @param string $tubeName
     * @param int $max
     * @return bool
     */
    static public function createTube($tubeName, $max = 30) {
        if (!$beanstalk = Common::getBeanstalkHandle()) return false;
        $beanstalk->use_tube($tubeName);
        $i = 0;
        while ($i < $max) {
            $beanstalk->put(1);
            $i++;
        }   
        return true;
    }   


实现管道锁

/** 
     * 采用管道方式进行加锁,以限制同时进行某个流程的并发数
     * @param string $name 管道名称
     * @param int $delay 出管理延迟时间默认为5秒
     * @return bool
     */
    public function tubeLock($name, $delay = 5) {
        $beanstalk = Common::getBeanstalkHandle();
        $beanstalk->watch($name);
        $return = false;
        $job = $beanstalk->reserve_with_timeout();
        if ($job['id'] > 0)  $return = $beanstalk->release($job['id'], 1024, $delay);
        $beanstalk->ignore($name);
        return $return;
    }   


提前创建好管道,在并发流程中:

$tubeName = 'tube_' . $goods['id'];
if (Common::getLockHandle()->tubeLock($tubeName) == false)  return false; //如果管理已经加锁,直接返回

到此为止,如我们所愿,我们已经控制了并发,我们已经把我们能力范围内可以控制的人放进来了,其它人只能继续等待...

剩下就是库存问题了,库存控制原则:

1.库存数不能<0,否则问题大了,商品超卖了,用户下了单,但没货发给卖家,那你就等着投诉吧。

请看下面一个sql(数据库是InnoDB):

/** 
     * 
     * 更新库存
     * @param int $num
     * @param int $id
     */
    public function updateQuantity($num, $goodsid) {
        $sqlPart = $num < 0 ? ' AND quantity >= ' . abs($num) : ''; 
        $sql = 'UPDATE %s SET quantity = quantity + ?, sale_num = sale_num - ? WHERE id = ?' . $sqlPart;
        return $this->_update($sql, array(intval($num), intval($num), intval($goodsid));
    }  

重点看sqlPart部分,这里巧妙和利用mysql的行级锁,把库存不可能为0的控制权交给了mysql来处理,此乃点晴之笔。





版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/rainkid/article/details/7289927

智能推荐

ITK图像分割三个示例_itek 分段取图模式-程序员宅基地

文章浏览阅读4.2k次。ITK图像分割三个示例https://blog.csdn.net/hacker_long/article/details/40922811_itek 分段取图模式

修改tomcat目录下tomcat-users.xml文件不起效果,eclispe中只要启动tomcat就会把tomcat目录下的tomcat-users.xml文件的改动给覆盖掉_ubuntu apache-tomcat-9.0.76 修改 tomcat-users.xml不起作-程序员宅基地

文章浏览阅读2.6k次,点赞2次,收藏5次。想给tomcat服务器增加个管理用户打开tomcat安装目录下的tomcat-users.xml文件如下图:在eclispe中,重新启动tomcat在浏览器中访问tomcat界面,输入刚才tomcat目录下的tomcat-users.xml文件中增加的那个用户名和密码,用户名admin密码1234,发现登录不了,试了好几次都登录不了。没关系,接着_ubuntu apache-tomcat-9.0.76 修改 tomcat-users.xml不起作用

RabbitMq应用在发送短信_rabbitmq发送短信-程序员宅基地

文章浏览阅读5.5k次。RabbitMq应用在发送短信:首先安装mq在机器上,注册用户名和密码短信发送分为两部分:1、server端,2、client端server端的配置和编写在maven中配置下载mq的依赖包dependency> groupId>org.springframework.amqpgroupId> artifactId>spring-rabbitartifactId>_rabbitmq发送短信

将前端传过来的base64加密图片保存到本地,并且判断来自于哪个终端_后端保存 签字 base64-程序员宅基地

文章浏览阅读437次。文章目录代码测试结果二、使用步骤1.引入库总结代码@PostMapping(value = "/check") public Map png2(@RequestParam String path,@RequestParam String useragent) throws IOException { Map<String, Object> map = new HashMap(); util util = new util(); if ._后端保存 签字 base64

电脑连接不上WiFi无线网,网络显示出现黄星号,或者感叹号最有效的解决方法:_无线网卡显示黄色星号-程序员宅基地

文章浏览阅读1w次。电脑连接不上WiFi无线网,网络显示出现黄星号,或者感叹号最有效的解决方法:_无线网卡显示黄色星号

随便推点

django csrf 防护_@method_decorator(csrf_protect,name="方法名")-程序员宅基地

文章浏览阅读81次。作用:防止跨站伪请求配置文件:MIDDLEWARE = [ 'django.middleware.csrf.CsrfViewMiddleware', ]模板:{% csrf_token%}视图类视图函数默认都加入csrf验证from django.views.decorators.csrf import csrf_exempt,csrf_protectfbv:去掉csrf防护@csrf_exempt加入csrf防护@csrf_pro..._@method_decorator(csrf_protect,name="方法名")

Python + Selenium(十三)鼠标操作-链式操作_selenium send_keys key能否链式操作-程序员宅基地

文章浏览阅读2.3k次,点赞4次,收藏24次。当你需要执行复杂的操作时,比如将一个元素按住拖动到另一个元素上去,需要移动鼠标然后点击并按下键盘某个按键等等。当然,在 Web 页面上,这种操作好像比较少。但是,如果遇到了怎么办呢?这就需要用到 ActionChains 这个类啦。ActionChains 提供了对动作的链式操作,也就是可以生成一个操作的队列,将复杂的操作过程分解成单个操作,然后组合起来一次性执行。这里面主要是鼠标操作,加..._selenium send_keys key能否链式操作

python自动发送邮件自定义邮件发件人和收件人的显示内容_python3 smtp 自定义中文收件人-程序员宅基地

文章浏览阅读7.5k次。#自定义处理邮件收发地址的显示内容 def _format_addr(s): name,addr = parseaddr(s) print name print addr #将邮件的name转换成utf-8格式,addr如果是unicode,则转换utf-8输出,否则直接输出addr return form..._python3 smtp 自定义中文收件人

linux普通用户执行管理员权限visudo_linux 新家用户执行管理员#-程序员宅基地

文章浏览阅读2.6k次。因为服务器很多,为了方便发布版本,弄了个简单的版本管理器,但是普通用户在执行管理员权限的时候一直提示sudo cp /tmp/test.war /opt/test is not allowed to execute也查了一些资料 说是在提权后用超级管理员用户执行visudo添加test ALL=(ALL) NOPASSWD: ALL (放_linux 新家用户执行管理员#

java内存模型_java [goforit]-程序员宅基地

文章浏览阅读100次。例子: import java.util.Random;public class MemoryTest { int x, y,read_x,read_y; public void randomSleep(){ try { Thread.sleep(new Random().nextInt(30)); ..._java [goforit]

bootstrap table 选中一行_bootstraptable只允许选中一行-程序员宅基地

文章浏览阅读7.8k次。//获取表格选中行var rows = $table.bootstrapTable('getSelections');//判断是否选择行if (!rows || rows.length == 0) { alert(&quot;请先选中一行!&quot;) return;}_bootstraptable只允许选中一行

推荐文章

热门文章

相关标签