发布于2021-05-30 19:13 阅读(553) 评论(0) 点赞(27) 收藏(0)
秒杀系统-----秒杀服务
步骤实现
base.php
api.php
读商品信息页优化
读库存优化
有效压榨CPU,减少I/O操作,减少接口的调用,通过本地内存,减少cpu上下文的切换,多进程,多线程的切换。
<?php
class Base
{
static $redisObj;
static function conRedis($config = array())
{
if (self::$redisObj) return self::$redisObj;
self::$redisObj = new \Redis();
self::$redisObj->connect("127.0.0.1", 6379);
return self::$redisObj;
}
static function output($data = array(), $errNo = 0, $errMsg = 'ok')
{
$res['errno'] = $errNo;
$res['errmsg'] = $errMsg;
$res['data'] = $data;
echo json_encode($res);exit();
}
}
?>
<?php
include('base.php');
class Api extends Base
{
//共享信息,存储在redis中,以hash表的形式存储,%s变量代表的是商品id
static $userId;
static $productId;
static $REDIS_REMOTE_HT_KEY = "product_%s"; //共享信息key
static $REDIS_REMOTE_TOTAL_COUNT = "total_count"; //商品总库存
static $REDIS_REMOTE_USE_COUNT = "used_count"; //已售库存
static $REDIS_REMOTE_QUEUE = "c_order_queue"; //创建订单队列
static $APCU_LOCAL_STOCK = "apcu_stock_%s"; //总共剩余库存
static $APCU_LOCAL_USE = "apcu_stock_use_%s"; //本地已售多少
static $APCU_LOCAL_COUNT = "apcu_total_count_%s"; //本地分库存分摊总数
public function __construct($productId, $userId)
{
self::$REDIS_REMOTE_HT_KEY = sprintf(self::$REDIS_REMOTE_HT_KEY, $productId);
self::$APCU_LOCAL_STOCK = sprintf(self::$APCU_LOCAL_STOCK, $productId);
self::$APCU_LOCAL_USE = sprintf(self::$APCU_LOCAL_USE, $productId);
self::$APCU_LOCAL_COUNT = sprintf(self::$APCU_LOCAL_COUNT, $productId);
self::$APCU_LOCAL_COUNT = sprintf(self::$APCU_LOCAL_COUNT, $productId);
self::$userId = $userId;
self::$productId = $productId;
}
static function clear(){
apcu_delete(self::$APCU_LOCAL_STOCK);
apcu_delete(self::$APCU_LOCAL_USE);
apcu_delete(self::$APCU_LOCAL_COUNT);
}
/*查剩余库存*/
static function getStock()
{
$stockNum = apcu_fetch(self::$APCU_LOCAL_STOCK);
if ($stockNum === false) {
$stockNum = self::initStock();
}
self::output(['stock_num' => $stockNum]);
}
/*抢购-减库存*/
static function buy()
{
$localStockNum = apcu_fetch(self::$APCU_LOCAL_COUNT);
if ($localStockNum === false) {
$localStockNum = self::init();
}
$localUse = apcu_inc(self::$APCU_LOCAL_USE);//本已卖 + 1
if ($localUse > $localStockNum) {//抢购失败 大部分流量在此被拦截
echo 1;
self::output([], -1, '该商品已售完');
}
//同步已售库存 + 1;
if (!self::incUseCount()) {//改失败,返回商品已售完
self::output([], -1, '该商品已售完');
}
//写入创建订单队列
self::conRedis()->lPush(self::$REDIS_REMOTE_QUEUE, json_encode(['user_id' => self::$userId, 'product_id' => self::$productId]));
//返回抢购成功
self::output([], 0, '抢购成功,请从订单中心查看订单');
}
/*创建订单*/
/*查询订单*/
/*总剩余库存同步本地,定时执行就可以*/
static function sync()
{
$data = self::conRedis()->hMGet(self::$REDIS_REMOTE_HT_KEY, [self::$REDIS_REMOTE_TOTAL_COUNT, self::$REDIS_REMOTE_USE_COUNT]);
$num = $data['total_count'] - $data["used_count"];
apcu_add(self::$APCU_LOCAL_STOCK, $num);
self::output([], 0, '同步库存成功');
}
/*私有方法*/
//库存同步
private static function incUseCount()
{
//同步远端库存时,需要经过lua脚本,保证不会出现超卖现象
$script = <<<eof
local key = KEYS[1]
local field1 = KEYS[2]
local field2 = KEYS[3]
local field1_val = redis.call('hget', key, field1)
local field2_val = redis.call('hget', key, field2)
if(field1_val>field2_val) then
return redis.call('HINCRBY', key, field2,1)
end
return 0
eof;
return self::conRedis()->eval($script,[self::$REDIS_REMOTE_HT_KEY, self::$REDIS_REMOTE_TOTAL_COUNT, self::$REDIS_REMOTE_USE_COUNT] , 3);
}
/*初始化本地数据*/
private static function init()
{
apcu_add(self::$APCU_LOCAL_COUNT, 150);
apcu_add(self::$APCU_LOCAL_USE, 0);
}
static function initStock(){
$data = self::conRedis()->hMGet(self::$REDIS_REMOTE_HT_KEY, [self::$REDIS_REMOTE_TOTAL_COUNT, self::$REDIS_REMOTE_USE_COUNT]);
$num = $data['total_count']- $data["used_count"];
apcu_add(self::$APCU_LOCAL_STOCK, $num);
return $num;
}
}
try{
$act = $_GET['act'];
$product_id = $_GET['product_id'];
$user_id = $_GET['user_id'];
$obj = new Api($product_id, $user_id);
if (method_exists($obj, $act)) {
$obj::$act();
die;
}
echo 'method_error!';
} catch (\Exception $e) {
echo 'exception_error!';
var_dump($e);
}
作者:再拍我就焖面
链接:http://www.phpheidong.com/blog/article/86738/b59f33e79f2a7a6e6942/
来源:php黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 php黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-4
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!