我的编程空间,编程开发者的网络收藏夹
学习永远不晚

PHP怎么解决高并发问题

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

PHP怎么解决高并发问题

这篇文章主要介绍了PHP怎么解决高并发问题,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

举个例子,高速路口,1秒钟来5部车,每秒通过5部车,高速路口运作正常。突然,这个路口1秒钟只能通过4部车,车流量仍然依旧,结果必定出现大塞车。(5条车道忽然变成4条车道的感觉)

同理,某一个秒内,20*500个可用连接进程都在满负荷工作中,却仍然有1万个新来请求,没有连接进程可用,系统陷入到异常状态也是预期之内。

PHP怎么解决高并发问题

其实在正常的非高并发的业务场景中,也有类似的情况出现,某个业务请求接口出现问题,响应时间极慢,将整个Web请求响应时间拉得很长,逐渐将Web服务器的可用连接数占满,其他正常的业务请求,无连接进程可用。

更可怕的问题是,是用户的行为特点,系统越是不可用,用户的点击越频繁,恶性循环最终导致“雪崩”(其中一台Web机器挂了,导致流量分散到其他正常工作的机器上,再导致正常的机器也挂,然后恶性循环),将整个Web系统拖垮。

重启与过载保护

如果系统发生“雪崩”,贸然重启服务,是无法解决问题的。最常见的现象是,启动起来后,立刻挂掉。这个时候,最好在入口层将流量拒绝,然后再将重启。如果是redis/memcache这种服务也挂了,重启的时候需要注意“预热”,并且很可能需要比较长的时间。

秒杀和抢购的场景,流量往往是超乎我们系统的准备和想象的。这个时候,过载保护是必要的。如果检测到系统满负载状态,拒绝请求也是一种保护措施。在前端设置过滤是最简单的方式,但是,这种做法是被用户“千夫所指”的行为。更合适一点的是,将过载保护设置在CGI入口层,快速将客户的直接请求返回

高并发下的数据安全

我们知道在多线程写入同一个文件的时候,会存现“线程安全”的问题(多个线程同时运行同一段代码,如果每次运行结果和单线程运行的结果是一样的,结果和预期相同,就是线程安全的)。如果是MySQL数据库,可以使用它自带的锁机制很好的解决问题,但是,在大规模并发的场景中,是不推荐使用MySQL的。秒杀和抢购的场景中,还有另外一个问题,就是“超发”,如果在这方面控制不慎,会产生发送过多的情况。我们也曾经听说过,某些电商搞抢购活动,买家成功拍下后,商家却不承认订单有效,拒绝发货。这里的问题,也许并不一定是商家奸诈,而是系统技术层面存在超发风险导致的。

超发的原因

假设某个抢购场景中,我们一共只有100个商品,在最后一刻,我们已经消耗了99个商品,仅剩最后一个。这个时候,系统发来多个并发请求,这批请求读取到的商品余量都是99个,然后都通过了这一个余量判断,最终导致超发。(同文章前面说的场景)

PHP怎么解决高并发问题

在上面的这个图中,就导致了并发用户B也“抢购成功”,多让一个人获得了商品。这种场景,在高并发的情况下非常容易出现。

优化方案1:将库存字段number字段设为unsigned,当库存为0时,因为字段不能为负数,将会返回false

 <?php //优化方案1:将库存字段number字段设为unsigned,当库存为0时,因为字段不能为负数,将会返回false include('./mysql.php'); $username = 'wang'.rand(0,1000); //生成唯一订单 function build_order_no(){   return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8); } //记录日志 function insertLog($event,$type=0,$username){     global $conn;     $sql="insert into ih_log(event,type,usernma)     values('$event','$type','$username')";     return mysqli_query($conn,$sql); } function insertOrder($order_sn,$user_id,$goods_id,$sku_id,$price,$username,$number) {       global $conn;       $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price,username,number)       values('$order_sn','$user_id','$goods_id','$sku_id','$price','$username','$number')";      return  mysqli_query($conn,$sql); } //模拟下单操作 //库存是否大于0 $sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id' "; $rs=mysqli_query($conn,$sql); $row = $rs->fetch_assoc();   if($row['number']>0){//高并发下会导致超卖       if($row['number']<$number){         return insertLog('库存不够',3,$username);       }       $order_sn=build_order_no();       //库存减少       $sql="update ih_store set number=number-{$number} where sku_id='$sku_id' and number>0";       $store_rs=mysqli_query($conn,$sql);       if($store_rs){           //生成订单           insertOrder($order_sn,$user_id,$goods_id,$sku_id,$price,$username,$number);           insertLog('库存减少成功',1,$username);       }else{           insertLog('库存减少失败',2,$username);       }   }else{       insertLog('库存不够',3,$username);   } ?>

悲观锁思路

解决线程安全的思路很多,可以从“悲观锁”的方向开始讨论。

悲观锁,也就是在修改数据的时候,采用锁定状态,排斥外部请求的修改。遇到加锁的状态,就必须等待。

PHP怎么解决高并发问题

虽然上述的方案的确解决了线程安全的问题,但是,别忘记,我们的场景是“高并发”。也就是说,会很多这样的修改请求,每个请求都需要等待“锁”,某些线程可能永远都没有机会抢到这个“锁”,这种请求就会死在那里。同时,这种请求会很多,瞬间增大系统的平均响应时间,结果是可用连接数被耗尽,系统陷入异常。

优化方案2:使用MySQL的事务,锁住操作的行

 <?php //优化方案2:使用MySQL的事务,锁住操作的行 include('./mysql.php'); //生成唯一订单号 function build_order_no(){   return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8); } //记录日志 function insertLog($event,$type=0){     global $conn;     $sql="insert into ih_log(event,type)     values('$event','$type')";     mysqli_query($conn,$sql); } //模拟下单操作 //库存是否大于0 mysqli_query($conn,"BEGIN");  //开始事务 $sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id' FOR UPDATE";//此时这条记录被锁住,其它事务必须等待此次事务提交后才能执行 $rs=mysqli_query($conn,$sql); $row=$rs->fetch_assoc(); if($row['number']>0){     //生成订单     $order_sn=build_order_no();     $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)     values('$order_sn','$user_id','$goods_id','$sku_id','$price')";     $order_rs=mysqli_query($conn,$sql);     //库存减少     $sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";     $store_rs=mysqli_query($conn,$sql);     if($store_rs){       echo '库存减少成功';         insertLog('库存减少成功');         mysqli_query($conn,"COMMIT");//事务提交即解锁     }else{       echo '库存减少失败';         insertLog('库存减少失败');     } }else{   echo '库存不够';     insertLog('库存不够');     mysqli_query($conn,"ROLLBACK"); } ?>

FIFO队列思路

那好,那么我们稍微修改一下上面的场景,我们直接将请求放入队列中的,采用FIFO(First Input First Output,先进先出),这样的话,我们就不会导致某些请求永远获取不到锁。看到这里,是不是有点强行将多线程变成单线程的感觉哈。

PHP怎么解决高并发问题

然后,我们现在解决了锁的问题,全部请求采用“先进先出”的队列方式来处理。那么新的问题来了,高并发的场景下,因为请求很多,很可能一瞬间将队列内存“撑爆”,然后系统又陷入到了异常状态。或者设计一个极大的内存队列,也是一种方案,但是,系统处理完一个队列内请求的速度根本无法和疯狂涌入队列中的数目相比。也就是说,队列内的请求会越积累越多,最终Web系统平均响应时候还是会大幅下降,系统还是陷入异常。

文件锁的思路

对于日IP不高或者说并发数不是很大的应用,一般不用考虑这些!用一般的文件操作方法完全没有问题。但如果并发高,在我们对文件进行读写操作时,很有可能多个进程对进一文件进行操作,如果这时不对文件的访问进行相应的独占,就容易造成数据丢失

优化方案4:使用非阻塞的文件排他锁

 <?php //优化方案4:使用非阻塞的文件排他锁 include ('./mysql.php'); //生成唯一订单号 function build_order_no(){   return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8); } //记录日志 function insertLog($event,$type=0){     global $conn;     $sql="insert into ih_log(event,type)     values('$event','$type')";     mysqli_query($conn,$sql); } $fp = fopen("lock.txt", "w+"); if(!flock($fp,LOCK_EX | LOCK_NB)){     echo "系统繁忙,请稍后再试";     return; } //下单 $sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id'"; $rs =  mysqli_query($conn,$sql); $row = $rs->fetch_assoc(); if($row['number']>0){//库存是否大于0     //模拟下单操作     $order_sn=build_order_no();     $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)     values('$order_sn','$user_id','$goods_id','$sku_id','$price')";     $order_rs =  mysqli_query($conn,$sql);     //库存减少     $sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";     $store_rs =  mysqli_query($conn,$sql);     if($store_rs){       echo '库存减少成功';         insertLog('库存减少成功');         flock($fp,LOCK_UN);//释放锁     }else{       echo '库存减少失败';         insertLog('库存减少失败');     } }else{   echo '库存不够';     insertLog('库存不够'); } fclose($fp);  ?>
 <?php //优化方案4:使用非阻塞的文件排他锁 include ('./mysql.php'); //生成唯一订单号 function build_order_no(){   return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8); } //记录日志 function insertLog($event,$type=0){     global $conn;     $sql="insert into ih_log(event,type)     values('$event','$type')";     mysqli_query($conn,$sql); } $fp = fopen("lock.txt", "w+"); if(!flock($fp,LOCK_EX | LOCK_NB)){     echo "系统繁忙,请稍后再试";     return; } //下单 $sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id'"; $rs =  mysqli_query($conn,$sql); $row = $rs->fetch_assoc(); if($row['number']>0){//库存是否大于0     //模拟下单操作     $order_sn=build_order_no();     $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)     values('$order_sn','$user_id','$goods_id','$sku_id','$price')";     $order_rs =  mysqli_query($conn,$sql);     //库存减少     $sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";     $store_rs =  mysqli_query($conn,$sql);     if($store_rs){       echo '库存减少成功';         insertLog('库存减少成功');         flock($fp,LOCK_UN);//释放锁     }else{       echo '库存减少失败';         insertLog('库存减少失败');     } }else{   echo '库存不够';     insertLog('库存不够'); } fclose($fp);  ?>

乐观锁思路

这个时候,我们就可以讨论一下“乐观锁”的思路了。乐观锁,是相对于“悲观锁”采用更为宽松的加锁机制,大都是采用带版本号(Version)更新。实现就是,这个数据所有请求都有资格去修改,但会获得一个该数据的版本号,只有版本号符合的才能更新成功,其他的返回抢购失败。这样的话,我们就不需要考虑队列的问题,不过,它会增大CPU的计算开销。但是,综合来说,这是一个比较好的解决方案。

PHP怎么解决高并发问题

有很多软件和服务都“乐观锁”功能的支持,例如Redis中的watch就是其中之一。通过这个实现,我们保证了数据的安全。

优化方案5:Redis中的watch

 <?php $redis = new redis();  $result = $redis->connect('127.0.0.1', 6379);  echo $mywatchkey = $redis->get("mywatchkey");  $rob_total = 100;   //抢购数量 if($mywatchkey<=$rob_total){     $redis->watch("mywatchkey");     $redis->multi(); //在当前连接上启动一个新的事务。     //插入抢购数据     $redis->set("mywatchkey",$mywatchkey+1);     $rob_result = $redis->exec();     if($rob_result){          $redis->hSet("watchkeylist","user_".mt_rand(1, 9999),$mywatchkey);         $mywatchlist = $redis->hGetAll("watchkeylist");         echo "抢购成功!<br/>";                echo "剩余数量:".($rob_total-$mywatchkey-1)."<br/>";         echo "用户列表:<pre>";         var_dump($mywatchlist);     }else{           $redis->hSet("watchkeylist","user_".mt_rand(1, 9999),'meiqiangdao');         echo "手气不好,再抢购!";exit;     } } ?>

php是什么语言

php,一个嵌套的缩写名称,是英文超级文本预处理语言(PHP:Hypertext Preprocessor)的缩写。PHP 是一种 HTML 内嵌式的语言,PHP与微软的ASP颇有几分相似,都是一种在服务器端执行的嵌入HTML文档的脚本语言,语言的风格有类似于C语言,现在被很多的网站编程人员广泛的运用。

感谢你能够认真阅读完这篇文章,希望小编分享的“PHP怎么解决高并发问题”这篇文章对大家有帮助,同时也希望大家多多支持编程网,关注编程网行业资讯频道,更多相关知识等着你来学习!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

PHP怎么解决高并发问题

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

PHP怎么解决高并发问题

这篇文章主要介绍了PHP怎么解决高并发问题,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。举个例子,高速路口,1秒钟来5部车,每秒通过5部车,高速路口运作正常。突然,这个路口1
2023-06-15

PHP高并发问题如何解决

PHP高并发问题如何解决?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。重启与过载保护如果系统发生“雪崩”,贸然重启服务,是无法解决问题的。最常见的现象是,启动起
2023-06-15

如何解决PHP高并发问题

这篇“如何解决PHP高并发问题”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“如何解决PHP高并发问题”文章吧。秒杀会产生一个
2023-06-29

golang高并发问题怎么解决

在Go语言中,高并发问题可以通过以下几种方式来解决:使用goroutine:Goroutine是Go语言的轻量级线程,可以并发执行函数。通过将任务分解为多个并发执行的goroutine,可以提高程序的并发处理能力。使用channel:Cha
golang高并发问题怎么解决
2024-02-29

JAVA高并发丢包问题怎么解决

在Java中解决高并发丢包问题,可以采取以下几种方式:1. 增加服务器端的资源:可以通过增加服务器的带宽、内存和处理能力来缓解高并发带来的丢包问题。使用更强大的服务器硬件可以提高服务器的处理能力,并减少丢包的可能性。2. 优化网络传输:可以
2023-08-19

tomcat高并发阻塞问题怎么解决

要解决Tomcat高并发阻塞问题,可以考虑以下几个方面:1. 调整Tomcat配置:增加Tomcat的线程池大小、调整连接超时时间等,以提高Tomcat的并发处理能力。2. 使用NIO或异步Servlet:Tomcat默认使用的是BIO方式
2023-10-12

java高并发下脏读问题怎么解决

在Java高并发下解决脏读问题可以通过使用锁机制或者使用线程安全的数据结构来实现。1. 使用锁机制:可以使用synchronized关键字或者Lock接口的实现类来对共享数据进行加锁,确保在一个线程读取数据时,其他线程无法修改该数据,从而避
2023-08-23

springboot多线程高并发问题怎么解决

要解决Spring Boot多线程高并发问题,你可以考虑以下几个方面:1. 线程池配置:合理配置线程池的大小、队列容量等参数,以满足高并发场景下的需求。可以使用Spring Boot提供的线程池配置方式,如通过在application.pr
2023-08-24

PHP高并发之怎么解决商品库存超卖问题

这篇文章主要介绍“PHP高并发之怎么解决商品库存超卖问题”,在日常操作中,相信很多人在PHP高并发之怎么解决商品库存超卖问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”PHP高并发之怎么解决商品库存超卖问题
2023-06-29

Java如何解决高并发问题

在Java中,可以采用以下几种方式来解决高并发问题:1. 使用线程池:线程池可以有效地管理线程的创建和销毁,避免频繁地创建和销毁线程,从而提高系统的并发能力。2. 使用并发集合类:Java提供了一系列的并发集合类,如ConcurrentHa
2023-10-20

如何解决PHP开发中的高并发任务调度问题

概述:在PHP开发过程中,高并发任务调度是一个常见的挑战。尤其是在大型的网站或应用中,任务调度可能会涉及到同时执行、竞争资源和性能等问题。本文将介绍一些解决高并发任务调度问题的方法,并提供具体的代码示例。使用消息队列:消息队列是一种高效的任
2023-10-21

三个方法解决php并发问题

福利:[网络安全重磅福利:入门&进阶全套282G学习资源包免费分享 !] 解决php并发问题的方法有很多,具体可以使用MySQL的行级锁、乐观锁和Redis的分布式锁等技术来解决。此外,还可以使用消息队列、多进程、多线程等技术来解决php并
2023-08-19

协程能否解决Linux高并发问题

协程是一种轻量级的线程,它可以实现在同一个线程中进行多个任务的切换执行,从而提高程序的并发处理能力。在Linux环境下,协程可以有效地解决高并发问题。通过使用协程,可以避免传统多线程模型中线程切换的开销,从而提高程序的性能和效率。协程可以
协程能否解决Linux高并发问题
2024-08-06

Java怎么解决接口并发问题

在Java中,可以通过以下几种方法来解决接口并发问题:1. 同步方法:可以在接口的实现类中使用synchronized关键字来修饰方法,确保同一时间只有一个线程能够访问该方法,从而避免并发问题。```javapublic synchroni
2023-09-12

MySQL 数据库如何解决高并发问题

前言我们都知道初创公司一开始都是以单体应用为首要架构,一般都是单体单库的形式。但是版本以及版本的迭代,数据库需要承受更多的高并发已经成了 架构设计 需要考虑的点。 那么解决问题,就得说到方案。但是方案有很多,我们该怎么选择呢? 优化与方案
2022-05-20

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录