抢购项目总结

最近在做一个抢礼券的小需求,需求功能点很简单,后台录入礼券,导入礼券码,前台用户抢礼券。但是还是要考虑一些问题的,例如用户抢礼券时如何保证多个用户并发操作时礼券的分配问题,是否会导致一个礼券码被多个用户抢到,还有考虑大并发情况下数据库的承受能力。考虑到公司流量不是特别大的情况下做了如下两点优化操作:

一、用redis生成限制锁

用redis做成限制锁,在多用户同时请求的情况下只处理一个用户的请求,其他用户等待锁,这样就把多线程变成单线程请求了,同样可以避免同一礼券分配给多用户。

/**
 * 限制锁
 *
 * @return bool
 */
public function getlock()
{
    $reTimes = 5;
    while($reTimes > 0){
        $this->expireTime = $this->microtime_float()+2;
        if($this->redis->setNx($this->key, $this->expireTime)){
            return true;
        }

        $setExpireTime = $this->redis->get($this->key);
        if($setExpireTime !== false && $setExpireTime < time()+1){
            //防止锁竞争,获取时间跟原定过期时间一致的获得锁
            $oldTime = $this->redis->getSet($this->key, $this->microtime_float()+2);
            if($oldTime == $setExpireTime){
                return true;
            }
        }
        $reTimes--;
        usleep(10000);
    }

    return false;
}

其实在使用事务时因为事务有行级锁,同样可以避免同一个礼券码分配给多用户。


二、使用redis实现队列防止高并发情况下“等锁”导致大批线程等不到锁“死掉”

把所有要发出去的礼券码使用lpush加入队列,然后每次去请求就lpop出队列,这样就大并发情况下不用频繁的去查询数据库。同样在后台关闭这个礼券的时候会清除掉对应队列


//判断该用户是否抢过该礼券
$code = $conn->fetchColumn('select * from table_name');
if(empty($code)){

    //判断队列里是否还含有礼券码
    if(false === ($codeInfo = $this->redis->lpop($ticketListKey))){
         $tickList = $conn->fetchAll('select t.id code_id, t.coupon_code from table_name');
        if(!empty($tickList)){
            //把礼券加入队列
            foreach($tickList as $key => $val){
                $this->redis->lpush($ticketListKey, json_encode(array('id' => $val['code_id'] , 'code' => $val['coupon_code'])));
            }
            $codeInfo = $this->redis->lpop($ticketListKey);
        }
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值