php高并发解决方案

php高并发解决方案有哪些

php高并发解决方案有(不涉及mysql,以及前端):
1、使用文件锁;
2、使用消息队列;
3、如果是分布式集群服务器,需要一个或多个队列服务器;

例子
实际项目中,我们经常遇见抢购商品、抽奖活动等等短时间内访问过高造成高并发的问题。今天使用第一二中方法结合使用

1)文件锁

$file = fopen("list.lock","r");
//LOCK_EX锁定整个文件,LOCK_UN、LOCK_SH锁定文件的一部分,LOCK_NB非阻塞锁
if(!flock($file,LOCK_EX | LOCK_NB)){
    return "系统繁忙,请稍后再试";
}
//处理具体业务逻辑
    
//解除锁定
flock($file,LOCK_UN);
fclose($file );//关闭文件

2)消息队列

/**Redis消息队列**/
/**
     * @param $key
     * @param $goods_id
     * @param $num
     * @return void 后台开启抢购后启动这一步
     */
    function setNum($key='goods_',$goods_id,$num=100)
    {
        //实例化(实际开发中提出来)
        $redis = new Redis();
        //连接服务端
        $redis->connect('127.0.0.1', 6379);
        $res = $redis->set($key.$goods_id,$num);
    }

    /**
     * 秒杀抢购
     * @param Request $request
     * @return void
     */
    function cusBuy(Request $request)
    {
        //用户、商品信息
        $uid = $request->input('uid');
        $goods_id = $request->input('goods_id');
        //商品库存key
        $key = 'goods_'.$goods_id;
        //实例化(实际开发中提出来)
        $redis = new Redis();
        //连接服务端
        $redis->connect('127.0.0.1', 6379);
        //监听key 监听对应的key,事务提交之前,如果key被修改,则事务被打断
        $redis->watch($key);
        //检查key uid 是否存在对应已抢购用户ID
        if($redis->hGet('uid',$uid)){
            return '请误重复抢购';
        }
        //获取库存
        $goods_num = $this->setNum($key);
        //开启事务
        $redis->multi();
        //判断库存是否足够
        if($goods_num>0){
            $redis->decr($key);//库存减1
            //生成订单
            $time = time();
            $order_no = 'NO'.rand(1000,9999).$time.date('YmdHis',$time);//生成唯一订单
            $data = json_encode(['order_no'=>$order_no,'uid'=>$uid]);
            //订单信息入队
            $redis->rPush("order_no",$data);
            //入队成功后当前抢购人员信息放入redis,避免重复抢购
            $redis->set('uid',$uid);
            //入队后直接返回抢购成功,异步调用入库订单等等

            //关闭事务
            $redis->exec();
        }
    }

3)结合使用

/**
     * @param $key
     * @param $goods_id
     * @param $num
     * @return void 后台开启抢购后启动这一步
     */
    function setNum($key='goods_',$goods_id,$num=100)
    {
        //实例化(实际开发中提出来)
        $redis = new Redis();
        //连接服务端
        $redis->connect('127.0.0.1', 6379);
        $res = $redis->set($key.$goods_id,$num);
    }

    /**
     * 秒杀抢购
     * @param Request $request
     * @return void
     */
    function cusBuy(Request $request)
    {
        //$file = fopen("list.lock","r");
        //LOCK_EX锁定整个文件,LOCK_UN、LOCK_SH锁定文件的一部分,LOCK_NB非阻塞锁
        //if(!flock($file,LOCK_EX | LOCK_NB)){
            //return "系统繁忙,请稍后再试";
        //}
        //处理具体业务逻辑
        //用户、商品信息
        $uid = $request->input('uid');
        $goods_id = $request->input('goods_id');
        //商品库存key
        $key = 'goods_'.$goods_id;
        //实例化(实际开发中提出来)
        $redis = new Redis();
        //连接服务端
        $redis->connect('127.0.0.1', 6379);
        //监听key 监听对应的key,事务提交之前,如果key被修改,则事务被打断
        $redis->watch($key);
        //检查key uid 是否存在对应已抢购用户ID
        if($redis->hGet('uid',$uid)){
            return '请误重复抢购';
        }
        //获取库存
        $goods_num = $this->setNum($key);
        //开启事务
        $redis->multi();
        //判断库存是否足够
        if($goods_num>0){
            $redis->decr($key);//库存减1
            //生成订单
            $time = time();
            $order_no = 'NO'.rand(1000,9999).$time.date('YmdHis',$time);//生成唯一订单
            $data = json_encode(['order_no'=>$order_no,'uid'=>$uid]);
            //订单信息入队
            $redis->rPush("order_no",$data);
            //入队成功后当前抢购人员信息放入redis,避免重复抢购
            $redis->set('uid',$uid);
            //入队后直接返回抢购成功,异步调用入库订单等等

            //关闭事务
            $redis->exec();
        }
        //解除锁定(文件锁过慢,服务器压力大)
        //flock($file,LOCK_UN);
        //fclose($file );//关闭文件
        
    }

当然这只是很简单的运用,其中后面订单异步处理出队,订单信息入库,库存更改等等问题。库存字段可以设置为:UNSIGNED。前端涉及到一些异步,页面按钮禁止重复点击等等结合才能更有效处理并发问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值