当前位置:首页 > 日记 > 正文

关于php 高并发解决的一点思路

关于php 高并发解决的一点思路

我的思路如下(伪代码):

sql1:查询商品库存

if(库存数量 > 0){//生成订单...sql2:同时库存-1}

当没有并发时,上面的流程看起来是再正常不过了,假设同时两个人下单,而库存只有1个了,在sql1阶段两个人查询到的库存都是>0的,于是最终都执行了sql2,库存最后变为-1,超售了,这不是我们想要的结果吧。

解决这个问题比较流行的思路我总结了下:
1.用额外的单进程处理一个队列,下单请求放到队列里,一个个处理,就不会有并发的问题了,但是要额外的开启后台进程以及延迟问题,这里暂不予考虑。这里我可使用消息队列,我们常用到Memcacheq、Radis。 比如:有100张票可供用户抢,那么就可以把这100张票放到缓存中,读写时不要加锁。 当并发量大的时候,可能有500人左右抢票成功,这样对于500后面的请求可以直接转到活动结束的静态页面。进去的500个人中有400个人是不可能获得商品的。所以可以根据进入队列的先后顺序只能前100个人购买成功。后面400个人就直接转到活动结束页面。当然进去500个人只是举个例子,至于多少可以自己调整。而活动结束页面一定要用静态页面,不要用数据库。这样就减轻了数据库的压力。
2.mysql乐观锁,意思是比如总库存是2,抢购事件提交时,立马将库存+1,那么此时库存是3,然后订单生成后,在更新库存前再查询一次库存(因为订单生成理所当然库存-1,但是先不急,再查一次库存返回结果是3),看看跟预期的库存数量(这里预期的库存是3)是否保持一致,不一致就回滚,提示用户库存不足。这里说道悲观锁,可能有朋友会问,那一定有乐观锁了吧??这里我就浅谈下我所了解的悲观与乐观锁了

悲观锁与乐观锁是两种常见的资源并发锁设计思路,也是并发编程中一个非常基础的概念。本文将对这两种常见的锁机制在数据库数据上的实现进行比较系统的介绍。

悲观锁(Pessimistic Lock)

悲观锁的特点是先获取锁,再进行业务操作,即“悲观”的认为获取锁是非常有可能失败的,因此要先确保获取锁成功再进行业务操作。通常所说的“一锁二查三更新”即指的是使用悲观锁。通常来讲在数据库上的悲观锁需要数据库本身提供支持,即通过常用的select … for update操作来实现悲观锁。当数据库执行select for update时会获取被select中的数据行的行锁,因此其他并发执行的select for update如果试图选中同一行则会发生排斥(需要等待行锁被释放),因此达到锁的效果。select for update获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。

这里需要注意的一点是不同的数据库对select for update的实现和支持都是有所区别的,例如oracle支持select for update no wait,表示如果拿不到锁立刻报错,而不是等待,mysql就没有no wait这个选项。另外mysql还有个问题是select for update语句执行中所有扫描过的行都会被锁上,这一点很容易造成问题。因此如果在mysql中用悲观锁务必要确定走了索引,而不是全表扫描。

乐观锁(Optimistic Lock)

乐观锁的特点先进行业务操作,不到万不得已不去拿锁。即“乐观”的认为拿锁多半是会成功的,因此在进行完业务操作需要实际更新数据的最后一步再去拿一下锁就好。

乐观锁在数据库上的实现完全是逻辑的,不需要数据库提供特殊的支持。一般的做法是在需要锁的数据上增加一个版本号,或者时间戳,然后按照如下方式实现:

1. SELECT data AS old_data, version AS old_version FROM …;2. 根据获取的数据进行业务操作,得到new_data和new_version3. UPDATE SET data = new_data, version = new_version WHERE version = old_versionif (updated row > 0) {  // 乐观锁获取成功,操作完成} else {  // 乐观锁获取失败,回滚并重试}

乐观锁是否在事务中其实都是无所谓的,其底层机制是这样:在数据库内部update同一行的时候是不允许并发的,即数据库每次执行一条update语句时会获取被update行的写锁,直到这一行被成功更新后才释放。因此在业务操作进行前获取需要锁的数据的当前版本号,然后实际更新数据时再次对比版本号确认与之前获取的相同,并更新版本号,即可确认这之间没有发生并发的修改。如果更新失败即可认为老版本的数据已经被并发修改掉而不存在了,此时认为获取锁失败,需要回滚整个业务操作并可根据需要重试整个过程。好吧,在此唠叨总结下这两个锁:

总结

  • 乐观锁在不发生取锁失败的情况下开销比悲观锁小,但是一旦发生失败回滚开销则比较大,因此适合用在取锁失败概率比较小的场景,可以提升系统并发性能

  • 乐观锁还适用于一些比较特殊的场景,例如在业务操作过程中无法和数据库保持连接等悲观锁无法适用的地方

3.根据update结果来判断,我们可以在sql2的时候加一个判断条件update table set 库存=xxx where 库存>0,如果返回false,则说明库存不足,并回滚事务。
4.借助文件排他锁,在处理下单请求的时候,用flock锁定一个文件,如果锁定失败说明有其他订单正在处理,此时要么等待要么直接提示用户"服务器繁忙"

大致代码如下:
阻塞(等待)模式

<?php$fp = fopen("lock.txt", "w+");if(flock($fp,LOCK_EX))  //锁定当前指针,,,{ //..处理订单 flock($fp,LOCK_UN);}fclose($fp);?>

非阻塞模式

<?php$fp = fopen("lock.txt", "w+");if(flock($fp,LOCK_EX | LOCK_NB)){ //..处理订单 flock($fp,LOCK_UN);}else{ echo "系统繁忙,请稍后再试";} fclose($fp);?>

5.如果是分布式集群服务器,就需要一个或多个队列服务器 小米和淘宝的抢购还是有稍许不同的,小米重在抢的那瞬间,抢到了名额,就是你的,你就可以下单结算。而淘宝则重在付款的时候的过滤,做了多层过滤,比如要卖10件商品,他会让大于10的用户抢到,在付款的时候再进行并发过滤,一层层的减少一瞬间的并发量。

6.使用redis锁 product_lock_key 为票锁key 当product_key存在于redis中时,所有用户都可以进入下单流程。 当进入支付流程时,首先往redis存放sadd(product_lock_key, “1″),如果返回成功,进入支付流程。如果不成,则说明已经有人进入支付流程,则线程等待N秒,递归执行sadd操作。

当然类似于淘宝双11的疯抢架构远远比我说滴这些复杂多啦....更多解决方案需要不停滴去实战中获取心得....大家有好的解决思路清随时共享留言哈

相关文章

Javascript调试之console对象——

Javascript调试之console对象——

调试,对象,你不知道,小技巧,电脑软件,前言写过前端Javascript代码的同学肯定不会对console对象感到陌生,在调试的过程中我们经常会用console对象在控制台输出一些常量或者变量。但是相信很多人也就只用过console.log()这一个方法,今天我们就…

Excel怎样设置输入数据自动变成数

Excel怎样设置输入数据自动变成数

输入,设置,数据,方法,数值,  在Excel编辑的时候,在添加数据后自动变成了日期,怎么修改?在Excel中,可以通过设置禁止将数据转换为日期。接下来小编举例简单的例子告诉大家Excel如何设置输入数据自动变成数字。Excel设置输入数据自动变成数值…

excel表格的筛选教程

excel表格的筛选教程

教程,筛选,表格,电脑软件,excel,  Excel的筛选功能如何筛选数据呢?接下来是小编为大家带来的excel表格的筛选教程,供大家参考。excel表格的筛选教程:  筛选步骤1:比如我们建立有三列数据的Excel表来进行说明,分别是商品类别、商品名称和商…

AI基础教程:手把手教你绘制萌萌的

AI基础教程:手把手教你绘制萌萌的

绘制,驯鹿,插画,基础教程,手把手教你,效果图:主要过程:12 3 4 5 阅读全文1 23 4 5 阅读全文1 2 34 5 阅读全文1 2 3 45 阅读全文教程结束,以上就是AI基础教程:手把手教你绘制萌萌的小驯鹿插画的全部内容,希望大家喜欢!相关教程推荐:Illustrat…

jquery 一键复制到剪切板的实例

jquery 一键复制到剪切板的实例

剪切板,一键,实例,电脑软件,jquery,今天做项目有一个功能,通过点击事件复制一段文本到剪切板,在网上找了一些,整理了一下,方便需要的朋友使用。<a id="copy" data-text="123456">复制文本</a>$(function(){ var clipboard = new Clipboa…

微信小程序-获得用户输入内容

微信小程序-获得用户输入内容

输入,用户,程序,内容,电脑软件,在微信小程序里,如何获得用户输入的内容??js: document.getElementById("Content").valuejq:$("#Content").val()在微信小程序中并不能这样写。可以通过组件的属性 bindchange 将用户输入的储存存起来test.wxm…

AngularJS实现上传和预览功能的方

AngularJS实现上传和预览功能的方

方法,上传,功能,电脑软件,AngularJS,本文实例讲述了AngularJS实现图片上传和预览功能的方法。分享给大家供大家参考,具体如下:html5原生方法先看一下html5原生方法上传和预览图片的实现:// <img id="img-preview">var imgPreview = document…

ps背景图层和普通图层怎么互相转换

ps背景图层和普通图层怎么互相转换

背景图层,转换,图层,电脑软件,ps,PS中,怎样把背景图层转换成普通图层呢?普通图层又如何转换成背景图层?下面,小编一 一说下操作方法。软件名称:Adobe Photoshop 8.0 中文完整绿色破解版软件大小:150.1MB更新时间:2015-11-04在操作界面右下方,这里显…

WPS表格怎么添加下拉列表WPS表格添

WPS表格怎么添加下拉列表WPS表格添

下拉列表,方法,下拉菜单,步骤,表格,  如何在WPS中添加下拉列表呢?通过使用下拉列表,可以更加方便的选择已知项,简各类选择操作。下面小编教你WPS表格怎么添加下拉列表。希望对你有帮助!WPS表格添加下拉列表的步骤首先,在WPS表格中输入要使用…

PHP中error_reporting函数用法详细

PHP中error_reporting函数用法详细

函数用法,详细介绍,电脑软件,PHP,error_reporting,PHP中error_reporting函数用法详细介绍PHP中对错误的处理会用到error_reporting函数,看到最多的是error_reporting(E_ALL ^ E_NOTICE),这个是什么意思呢?下面我们具体分析error_reporting函数…

详细分析单线程JS执行问题

详细分析单线程JS执行问题

执行,单线程,详细,电脑软件,JS,大家在学习javascript的时候很多朋友在执行问题上有疑惑,小编通过本篇文章给大家详细的分析介绍了JS的执行问题,希望能够帮助到你理解。一、介绍随着js不断学习,你可能会慢慢的好奇,用了这么久的js,却不知道这js在…

ps怎么做北极光效果? ps给添加北极

ps怎么做北极光效果? ps给添加北极

教程,北极光,效果,怎么做,电脑软件,ps想要设计激光,该怎么设计呢?下面我们就来看看详细的教程,请看下文详介绍。软件名称:Adobe photoshop 7.01 官方正式简体中文版软件大小:154MB更新时间:2013-04-191、首先打开我们的天空素材,新建一个空白图层,…