range

If there were you, the world would be just right

应用场景1:在很多时候,我们会把数据库中查出来的数据存入缓存,当缓存失效时,再从数据库中取出数据并重新添加到缓存中。但是如果这时并发量很大时,会有很多进程同时去数据库取数据,很多请求穿透到数据库,最终导致数据库崩溃

<?php
    $data = $cache->get('key');
    if(!$data){
        $fp = fopen('lock.txt',"w+");
        if(flock($fp, LOCK_EX)){
            $data = $cache->get('key');//拿到锁后再次检查缓存,这时可能已经有了
            if(!$data){
                $data = mysql->query();
                $cache->set('key', $data);
            }
            flock($fp, LOCK_UN);
        }
        fclose($fp);
    }

应用场景2:准点抢游戏皮肤,我们的代码是以下这种情况:

<?php
    $count = 检查数据库中的库存量
    if($count > 0){
        生成订单,皮肤库存减一
    }

在正常情况下,上面的这个demo是没有任何问题的,但是当大并发产生时,在执行数据库减一之前,库存只剩下1个时,用户1查到库存>0,用户2这个时候也查到库存>0...,后面的代码继续执行时,库存就会出现负数。

解决方案:

  1. 用额外的单进程处理一个队列,下单请求放到队列里,一个个处理,就不会有并发的问题了,但是要额外的后台进程以及延迟问题,不予考虑。
  2. 借助文件锁,如果锁定失败说明有其他订单正在处理,此时要么等待要么直接提示用户"服务器繁忙"

文件锁: (非阻塞【不等待】模式)

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

    fclose($fp);

文件锁: (阻塞【等待】模式)

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

处理高并发:https://blog.csdn.net/gaisidewangzhan1/article/details/80186584