PHP秒杀系统学习笔记 2/2

PHP秒杀系统学习

    • 一、基本需求分析
      • 秒杀服务核心实现
    • 二、扣库存分布式实现方案
    • 三、扣库存代码演示
    • 四、商品信息页及抢购进度查询实现
      • 1、基本需求,创建,支付订单
      • 2、读商品信息
      • 3、排队进度查看
    • 五、高性能的查库存服务实现
      • 1、高性能可读写库存
      • 2、基本需求实现
    • 六、链路如何实现漏斗型流量
    • 七、附·代码
      • 1、base.php
      • 2、api.php

一、基本需求分析

秒杀系统-----秒杀服务

秒杀服务核心实现

  • 满足基本需求,做到单服务极致性能
    基本需求:
    1、扣库存
    2、查库存,排队进度
    3、查订单详情,创建订单,支付订单
  • 请求链路流量优化,从客户端到服务端每层优化
  • 稳定性建设
    PHP秒杀系统学习笔记 2/2_第1张图片
    PHP秒杀系统学习笔记 2/2_第2张图片
    PHP秒杀系统学习笔记 2/2_第3张图片
    PHP秒杀系统学习笔记 2/2_第4张图片
    多进程阻塞式服务
    PHP秒杀系统学习笔记 2/2_第5张图片
    PHP秒杀系统学习笔记 2/2_第6张图片
    PHP秒杀系统学习笔记 2/2_第7张图片
    PHP秒杀系统学习笔记 2/2_第8张图片

二、扣库存分布式实现方案

PHP秒杀系统学习笔记 2/2_第9张图片
步骤实现
PHP秒杀系统学习笔记 2/2_第10张图片

三、扣库存代码演示

base.php
PHP秒杀系统学习笔记 2/2_第11张图片
api.php
PHP秒杀系统学习笔记 2/2_第12张图片
PHP秒杀系统学习笔记 2/2_第13张图片
PHP秒杀系统学习笔记 2/2_第14张图片
PHP秒杀系统学习笔记 2/2_第15张图片

四、商品信息页及抢购进度查询实现

1、基本需求,创建,支付订单

PHP秒杀系统学习笔记 2/2_第16张图片

2、读商品信息

PHP秒杀系统学习笔记 2/2_第17张图片

3、排队进度查看

PHP秒杀系统学习笔记 2/2_第18张图片

五、高性能的查库存服务实现

1、高性能可读写库存

PHP秒杀系统学习笔记 2/2_第19张图片
PHP秒杀系统学习笔记 2/2_第20张图片
PHP秒杀系统学习笔记 2/2_第21张图片

2、基本需求实现

PHP秒杀系统学习笔记 2/2_第22张图片

六、链路如何实现漏斗型流量

PHP秒杀系统学习笔记 2/2_第23张图片
读商品信息页优化
PHP秒杀系统学习笔记 2/2_第24张图片
读库存优化
PHP秒杀系统学习笔记 2/2_第25张图片
PHP秒杀系统学习笔记 2/2_第26张图片
PHP秒杀系统学习笔记 2/2_第27张图片
PHP秒杀系统学习笔记 2/2_第28张图片
有效压榨CPU,减少I/O操作,减少接口的调用,通过本地内存,减少cpu上下文的切换,多进程,多线程的切换。
PHP秒杀系统学习笔记 2/2_第29张图片

七、附·代码

1、base.php

<?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();
    }
}

?>

2、api.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);
}

你可能感兴趣的:(高并发,PHP代码片段,php,队列)