php+redis实现处理高并发秒杀(令牌桶限流)

2 篇文章 0 订阅
1 篇文章 0 订阅
<?php
class redis_miaoshaControl extends mobileControl
{
    public function __construct()
    {
        parent::__construct();
    }


    /**
     * 接口参数
     * @return array
     */
    public function getRules()
    {
        return [
            'user_buyOp' => [
                'user_id'        => ['name' => 'user_id', 'type' => 'int', 'form' => 'get', 'require' => true, 'default' => '', 'desc' => '用户id'],
               ],
        ];
    }


    /**
     * 初始化秒杀库存
     * @desc 初始化秒杀库存
     */
    public function set_storageOp()
    {
        //redis 初始秒杀库存设置
        $ins     = \Cache::getInstance('cacheredis');

        $goods_storage_data['goods_storage'] = 30;
        $ins->hset('goods_storage','nc_', $goods_storage_data);

        return_api('初始化秒杀库存');
    }

    /**
     * 初始化令牌桶
     * @desc 初始化秒杀库存
     */
    public function set_token_bucketOp()
    {
        //redis 初始秒杀库存设置
        $ins = \Cache::getInstance('cacheredis');
        $data['num'] = 20;
        $ins->hset('token_bucket','nc_', $data);

        return_api('初始化令牌桶成功');
    }

    /**
     * 用户购买
     * @desc 用户购买
     */
    public function user_buyOp()
    {
        $user_id = $_GET['user_id'];
        //用户限流,规定时间内只能请求一次
        $ins             = \Cache::getInstance('cacheredis');
        $user_limit_info = $ins->hget('user_limit' . $user_id,'nc_');

        if (!empty($user_limit_info)) {
            //上次请求时间
            $user_last_time = $user_limit_info['user_last_time'] + 30;
            //这里还能优化单位时间内请求次数,只要不超过这个次数,就不更新上次请求时间
            $now = time();

            //当初操作时间加三十秒,依然大于当前时间,那么就是太频繁
            if ($now < $user_last_time) {
                error_api('1000021', '请求失败,操作频繁,30秒内无法请求');
            }else{
                $ins->hset('user_limit' . $user_id,'nc_',['user_last_time' => time()]);
            }
        } else {
            $ins->hset('user_limit' . $user_id,'nc_',['user_last_time' => time()]);
        }


        //请求消费令牌桶
        $token_total = $ins->hget('token_bucket','nc_','num');

        if ($token_total <= 0) {
            error_api('1000022', '请求失败,当前请求人数太多',[$token_total]);
        }

        //消费令牌
        $token_total -= 1;
        $token_bucket['num'] = $token_total;
        $ins->hset('token_bucket', 'nc_',$token_bucket);

        //判断库存
        $storage = $ins->hget('goods_storage','nc_','goods_storage');
        if ($storage <= 0) {
            error_api('1000023', '请求失败,库存不足',[$storage]);
        }

        //减少库存
        $storage -= 1;
        $goods_storage_data['goods_storage'] = $storage;
        $ins->hset('goods_storage','nc_', $goods_storage_data);


        //加入rabitmq队列,定时脚本消费队列生成订单,发送短信通知用户秒杀成功
        $arr['goods_storage'] = $storage;
        $arr['token_total'] = $token_total;
        return_api('请求成功,订单创建成功会以短信通知',$arr);
    }

}

定时脚本生成令牌,根据实际需要控制令牌生成节奏

/**
 * 增加秒杀令牌
 */
private function _cron_create_token_bucket() {
    $ins = \Cache::getInstance('cacheredis');

    //当前令牌数
    $token_total = $ins->hget('token_bucket', 'nc_', 'num');

    $token_total += 8;

    //限制峰值
    $max = 20;

    $token_bucket['num'] = $token_total > $max ? $max : $token_total;

    $ins->hset('token_bucket', 'nc_',$token_bucket);
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值