redis模拟抢购

  • 内容
  • 评论
  • 相关

由于最近博主离职然后又找工作了,想起了以前做商城的时候有抢购活动,就简单写了个抢购活动类当是回忆开发过程了。话不多说,直接上代码。

<?php 
include "../functions.php";

interface Seckill{
	// 添加商品到库存
	public function sddGoods($warehouse_name, $goods_num);
	// 模拟用户参与秒杀
	public function seckill($warehouse_name, $uid, $user_queue_k, $user_k);
}

class BaseSeckill implements Seckill{

	private $act; //add:添加商品,seckill:秒杀

	function __construct($act = 'add', $host = '127.0.0.1', $port = 6379){
		$redis = new Redis();
		$redis->connect($host, $port);
		$this->redis = $redis;
		$this->act = $act;
	}

	/**
	 * [sddGoods 添加商品]
	 * @author ken
	 * @since  2019-03-26
	 * @param  string     $warehouse_name [库存名称]
	 * @param  integer    $goods_num      [商品入库数量]
	 * @return [type]                     [description]
	 */
	public function sddGoods($warehouse_name = 'goods', $goods_num = 10){
		if ($this->act == 'add') {
			$goods_num ?: p('存入商品数为空');
			$warehouse_name ?: p('库存名称不能为空');

			for ($i = 1; $i <= $goods_num; $i++) {
				$this->redis->lpush($warehouse_name, 1);
			}
			p('入仓商品数为:'.$this->redis->llen($warehouse_name));
		}
	}

	/**
	 * [seckill 秒杀]
	 * @author ken
	 * @since  2019-03-26
	 * @param  string     $warehouse_name [库存名称]
	 * @param  string     $user_queue_k   [参与抢购活动的用户队列]
	 * @param  string     $user_k         [成功抢购的用户队列]
	 * @param  integer    $uid            [description]
	 * @return [type]                     [description]
	 */
	public function seckill($warehouse_name = 'goods', $user_queue_k = 'user_queue_list', $user_k = 'user_list', $uid = 0){
		if ($this->act == 'seckill') {
			// 模拟用户id
			$uid = $uid ?: mt_rand(1, 100);
			// 统计所有参与用户
			$result = $this->redis->hset($user_queue_k, $uid, $uid);
			// 判断是否还有库存
			$inventory_num = $this->redis->llen($warehouse_name);
			$inventory_num ?: p('抢购已结束');

			// 判断用户是否已经参与,hash表储存,字段存在且旧值被新值覆盖时,返回0,否则返回1
			if ($result) {
				// 用户首次参加抢购,存储在成功抢购列表
				$this->redis->hset($user_k, $uid, $uid);
				// 商品库存-1
				$this->redis->lpop($warehouse_name);
				p('抢购成功'.$uid);
			}else{
				// 用户已经参加过抢购
				p($uid.'用户,您已参加过抢购活动');
			}
		}
	}
}

$act = $_REQUEST['act'] ?? 'add'; //add:添加商品,seckill:秒杀
$seckill = new BaseSeckill($act);
$seckill->sddGoods();
$seckill->seckill();

通过wrk压测实现抢购测试。

看看参与抢购的用户id列表:

用户id是从1-100随机生成的,每次并发的时候同时记录参与抢购的用户id。多次并发之下,值的范围能够完全覆盖定义域[1,100]。图片太长,只截部分。能够看到,100个用户id都被记录了。

再看看成功抢购的用户id列表是否正确:

我这里的商品库存设置了10,如果正确参与抢购的话,这里应该有10个用户id,并且不能够重复。结果符合预期,因此算是实现了模拟抢购。

友情赞助:

支付宝(alipay)
微信(wechat pay)

评论

1条评论