Redis+PHP秒杀设计

讲师介绍:

  1. 稳定性建设: 如何做到服务9999的稳定性即每年不可用时间不到1min
  2. 高性能系统: 滴滴运营广告系统即并发量很大
  3. 社招面试: 秒杀系统的设计与实现,其本质高并发高可用,这两方面的技术可直接决定公司技术水平,提现个人技术实力

概要:

  1. 基本知识和原理
    1. 减而治之
      1. cdn原理: 减少读的压力,如订单详情页下发到不同地方的cdn节点,访问加速,回源减少
      2. Nginx限流: 请求到达服务端(即接入层)如何做过载保护
      3. 异步队列概念: 如通过异步方式创建订单
    2. 分而治之
      1. Nginx负载均衡: 流量到达接入层,接入层分摊到每个server层
  2. 难点分析架构思路: 结合具体应用场景分析难点及如何架构
    1. 特征
      1. 写的强一致性: 抢购时不能发生超卖现象
      2. 读的弱一致性: 显示有库存,但下单不成功即减不了库存(如:12306,总库存和实际抢票的库存可以不一致)
    2. 难点
      1. 极致性能的实现: 可用上万台机器分摊流量达到负载均衡,但成本高; 应该提高单个服务的极致性能
      2. 高可用的保证
  3. 核心实现思路
    1. 极致性能的读服务实现: 需要实时读的库存数
    2. 极致性能的写服务实现: 扣库存,同时创建订单
    3. 极致性能的排队进度查询实现: 频繁查询排队进展
    4. 链路流量优化如何做: 流量第一次到达lvs层(Linux Virtual Server)->接入层->server层->客户端,如何减少每层流量,实现漏斗型流量过滤
  4. 兜底方案-高可用
    1. 高可用的 标准: 999和9999对应的标准
    2. 请求链路中每层高可用的实现原理: 每层出故障后该如何做
    3. 限流,一键降级和自动降级实现: 过载保护

目标:

  1. 掌握秒杀系统的核心实现
  2. 系统高可用的方法论学习
  3. 高并发场景的通用解决思路学习

工具使用与基础知识点介绍:

  1. 压测工具安装
    1. 原理: 通过多线程的模式,并发的访问某个接口,将对应的结果汇总统计展示出来
    2. yum -y install httpd-tools //通过yum命令安装ab压测工具
    3. ab -v //检查是否安装成功
  2. 检测接口最大qps(Queries-per-second)
    1. ab -n100 -c10 http://xxx
    2. 查看接口是否有优化空间,以达到单服务的性能极致
    3. 若接口性能无需优化,需要对接口进行限流,确保服务不会因为流量暴增挂掉
  3. Nginx限流配置
    1. 按连接数限速,即并发数(ngx_http_limit_conn_module)---限制客户端连接
    2. 按请求速率限速,按照ip限制单位时间内的请求书(ngx_http_limit_req_module)
    3. limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s; //创建规则; 以用户ip地址$binary_remote_addr为key;规则名是mylimit,申请了10M的空间;限制每秒1个请求
    4. limit_req zone=mylimit burst=1 nodelay; //应用规则; burst定义保留的缓存空间,nodelay如果burst设置的非常大时实现瞬间处理减少排队的等待时间
    5. ps aux | grep nginx //查看Nginx是否启动
    6. tail -f /var/log/nginx/error.log //nginx错误日志
  4. 限流算法介绍
    1. 令牌桶算法(例上述规则
      1. 匀速生产令牌: 每500ms生产一个令牌并将令牌放入令牌桶,1s产生两个令牌
      2. 令牌桶: 请求过来从令牌桶中扣除令牌,桶中无令牌则返回503
      3. 好处: 限制请求的速度; 应对突发流量
    2. 漏桶算法
      1. 漏桶: 请求排队, 桶存在大小, 队列均匀流出,桶满则溢出,返回503
      2. 和令牌桶区别: 不能处理突发流量
    3. 计数器: 单位时间计数器计数即可,一般在 应用程序中写的较多
  5. cdn介绍(Content Delivery Network): qps固定的情况下,提示单服务性能(流量拦截)
    1. 作用:缩短访问路径,减少源站压力,提高内容响应速度,为源站提供安全保护
    2. 原理
      1. 传统c/s架构: 客户端直接请求server,导致访问量极大
      2. cdn架构: 根据客户端所在位置返回一个最近的cdn IP给客户端; 无缓存回源(源server)
      3. 同一个域名访问的是不同的cdn服务器,涉及dns解析,通过域名解析ip和端口
    3. 普通域名解析(即未经过cdn加速的域名解析)客户端(浏览器,app)
      1. gethostbyname("www.test.com")//获取域名的ip和端口
      2. gethostbyname{

生成查询DNS服务器的消息(域名,class,记录类型)

通过UDP协议向(最近的)DNS服务器发送消息

(DNS服务器查看本地缓存有没有该域名,没有向根域名请求该域名对应的ip和端口)

接受DNS服务器返回的消息并读取出ip地址返回

}

      1. 拿到ip地址直接访问对应服务器
    • DNS解析原理
      1. 任何一台DNS服务器都保留根域信息
      2. 上级DNS服务器保管着所有下级DNS服务器的信息
      3. 客户端访问最近的DNS服务器,DNS服务器无缓存则请求root,root告诉DNS该域名需要访问某个子服务器,请求该子服务器后也会返回DNS应该访问的下级服务器
      4. 图解

      1. DNS服务器数据存储格式

域名

class

类型

数据

a.com

IN

A

10.xx.xx(直接解析出IP)

mail.a.com

IN

MX

10.xx.xx(直接解析出ip,并指出ip类型)

cdn.a.com

IN

CNAME

cdn.cdntip.com(另一个服务器的ip)

CNAME记录: 类似查询转发,该记录不能直接使用IP,只能是另一个主机的别名.CDN是利用该记录来指定CDN服务器,如果有A记录与CNAME记录同时存在,则只使用A记录

    1. CDN原理: 通过CNAME方式把某个已加速过的域名解析到另一个CDN服务商提供的dns解析的服务器

  1. 大型网站架构
    1. 主要结构(每层间有心跳检测,可及时将问题机器摘除,通过集群的方式确保服务高可用)
      1. 客户端: 请求某个地址时,通过dns/cdn加速到达,可能会回源至网站最外层router
      2. router(路由器/交换机): 使用Ospf负载均衡将流量负载至多个lvs机器上
      3. lvs层(lvs1,lvs2..): 四层负载均衡,流量到达后,不解析包内容,修改tcp头后转发给接入层
      4. 接入层(nginx1,nginx2..): 七层负载均衡,解析包内容,根据域名进行跳转至对应server层,同一个域名可以做到负载均衡的效果如ip做哈希来达到分流的效果
      5. server层(nginx+fpm,nginx+fpm..)
    2. nginx负载均衡算法介绍
      1. Round-robin(轮询)
      2. Weight-round-robin(带权轮询)

      1. Ip-hash(Ip哈希)
    • 消息队列
      1. 消息队列实为链表,头插尾出,高并发下容易发生堵塞,为避免消息丢失,可通过写入实时消息队列进行延时处理
      2. 实时队列: 如海底捞排队
      3. 延时队列: 基于触发的时间进行排队,如订单
      4. 作用
        1. 提高请求响应速度,如创建订单后的流程,发push,短信提醒等
        2. 瞬间高并发下,可起到削锋,如双十一0点并发创建订单
        3. 延时队列,时间维度任务触发,如发货提醒

秒杀系统的难点分析与架构原则:

  1. 使用场景及预估并发量
    1. 商城活动抢购,优惠券,定时抢购 有效写100+ 并发抢1w+
    2. 小米商城手机抢购 有效写1w+ 并发抢100w+
    3. 12306抢票 有效写1w+ 并发抢100w+
    4. 天猫双十一凌晨促销秒杀 有效写10w+ 并发抢1000w+
  2. 特点
    1. 抢购人数远多于库存,读写并发巨大
    2. 库存少,有效写少
    3. 写需要强一致性,商品不能卖超
    4. 读强一致性要求不高(与库存存储方案有关)
  3. 难点
    1. 稳定性难
      1. 高并发下,某个小依赖可能直接造成雪崩
      2. 流量预期难精确,过高也造成雪崩
      3. 分布式集群,机器多,出故障的概率高
    2. 准确性难
      1. 库存,抢购成功数,创建订单数之间的一致性
    3. 高性能难
      1. 有限成本下需要做到极致的性能
  4. 架构原则
    1. 稳定性
      1. 减少第三方依赖,同事自身服务部署也需要做到隔离
      2. (接口进行)压测,(针对接口最大容量进行)限流,(用户被限流后展示503页面无法抢购)降级确保核心服务可用
      3. 需要健康度检查机制,整个链路避免单点
    2. 高性能
      1. 缩短单请求访问路径,减少IO
      2. 减少接口数,降低吞吐数据量,请求次数减少
    3. 目标: 满足高并发且高可用的秒杀系统

秒杀系统的核心实现:

  1. 秒杀服务核心实现
    1. 满足基本需求,做到单服务极致性能
      1. 扣库存
      2. 查库存(实时查询)和排队进度(创建订单量大时,扣库存操作跟不上)
      3. 查订单详情,创建订单,支付订单(该条属于订单中心; 以上两个为秒杀服务,挑战大)
    2. 请求链路流量优化,从客户端到服务端每层优化: 实现流量漏斗
    3. 稳定性建设
  2. 场景示例:某件商品1000库存,100w并发读,100w并发抢购
  3. 扣库存方案
    1. 下单减库存×
      1. 流程: 并发请求->创建订单->扣库存->支付 (创建订单与扣库存通过事务方式绑定)
      2. 问题: 创建订单扣完库存后并不去支付,存在恶意下单但不会出现超卖
    2. 支付减库存×
      1. 流程: 并发请求->创建订单->支付->扣库存 (支付与扣库存通过事务方式绑定,保持强一致性)
      2. 问题: 订单超卖,导致订单支付不了
    3. 预扣库存√
      1. 流程: 并发请求->扣库存->创建订单->支付(扣库存与创建订单通过事务方式绑定)
      2. 问题: 不支付库存卖不出
      3. 解决: 订单创建后,设置订单时效,订单失效后库存恢复避免不支付库存卖不出的问题
      4. 原因: 秒杀系统并发量大,创建订单及支付都涉及IO
    4. 该部分问题
      1. 问题: 下单减库存的第一个方案 ,创建订单同时库存减,但是不是支付,同样也是可以设置支付时效啊,与第三个方案感觉差不多呢? 不理解老师说的
      2. 解答: 方案一(下单减库存)和方案三(预扣库存)模式其实差不多,就像 do..while... 和 while 的区别,都可以用支付时效控制回收库存,但是方案一相对方案三 I/O 开销更高
      3. 问题: 预扣库存的方案中也存在恶意下单的问题啊,恶意用户减完库存后但是不支付,这样其他人只能等这批订单超时了,如果此时我再批量下单减完库存是不是可以一直让目标玩家抢不到商品
      4. 解决:确实是这样的。但是,对于这样的用户你可以记录下来,让他在第二次秒杀的时候丧失资格。
  4. 极致性能的扣库存服务如何实现
    1. 本质: 程序有没有对CPU进行有效的压榨
      1. 减少上下文切换(如go语言中的携程概念,基于线程实现,将线程分为多个时间段,线程不进行切换;通过单线程方式保证不做切换,但会造成阻塞I/O; 单线程不会充分使用多核cpu优势,可实行单机部署多实例方式提高cpu使用率)
      2. 减少阻塞式I/O: I/O主要包含rpv调用(远程通信:接口/redis查询/mysql查询等)/磁盘读写(文件读写)
    2. 无IO怎么做
      1. 拆解: 扣库存与写订单分开,秒杀系统仅提供扣库存服务
      2. 用内存: 调用远程redis,可实现单机单服务10w的qps
      3. 用本地内存
    3. 步骤
      1. 初始化库存到本地库存
      2. 本地减库存,成功则进行统一减库存,失败则返回
      3. 统一减库存成功则写入MQ(可用redis),异步创建订单
      4. 告知用户抢购成功
    4. 好处:
      1. 统一减库存,可以防止因为机器的增减导致超买超卖现象
      2. 本地减库存: php可以通过apcu扩展实现, go使用单线程不存在强锁过程

  1. 扣库存实现
    1. 因为php的fpm是一个多进程模型
      1. 多进程间修改某块共享内存时存在抢锁,频率高的话影响性能
      2. cpu单核的话,多进程进行切换,开销巨大
    2. 基类base.php
 1 <?php
 2 class Base{
 3     static $redisObj;
 4     /*通过单例方式初始化一个redis连接*/
 5     static function conRedis($config = array()){
 6         if(self::$redisObj) return self::$redisObj;
 7         self::$redisObj = new \Redis();
 8         self::$redisObj->connect(‘127.0.0.1‘, 6379);
 9         return self::$redisObj;
10     }
11     /*接口输出格式化*/
12     static function output($data = array(), $errNo = 0, $errMsg = ‘ok‘){
13         $res[‘errno‘] = $errNo;
14         $res[‘errmsg‘] = $errMsg;
15         $res[‘data‘] = $data;
16         echo json_encode($res);
17         exit();
18     }
19 }
    1. api.php
  1 <?php
  2 include(‘base.php‘);
  3 class Api extends Base
  4 {
  5     //共享信息,存储在redis中,以hash表的形式存储,%s变量代表的是商品id
  6     static $userId;
  7     static $productId;
  8     static $REDIS_REMOTE_HT_KEY         = "product_%s";     //共享信息key
  9     static $REDIS_REMOTE_TOTAL_COUNT    = "total_count";    //商品总库存
 10     static $REDIS_REMOTE_USE_COUNT      = "used_count";     //已售库存
 11     static $REDIS_REMOTE_QUEUE          = "c_order_queue";  //创建订单队列
 12     static $APCU_LOCAL_STOCK    = "apcu_stock_%s";       //总共剩余库存
 13     static $APCU_LOCAL_USE      = "apcu_stock_use_%s";   //本地已售多少
 14     static $APCU_LOCAL_COUNT    = "apcu_total_count_%s"; //本地分库存分摊总数
 15     public function __construct($productId, $userId)
 16     {
 17         self::$REDIS_REMOTE_HT_KEY  = sprintf(self::$REDIS_REMOTE_HT_KEY, $productId);
 18         self::$APCU_LOCAL_STOCK     = sprintf(self::$APCU_LOCAL_STOCK, $productId);
 19         self::$APCU_LOCAL_USE       = sprintf(self::$APCU_LOCAL_USE, $productId);
 20         self::$APCU_LOCAL_COUNT     = sprintf(self::$APCU_LOCAL_COUNT, $productId);
 21         self::$APCU_LOCAL_COUNT     = sprintf(self::$APCU_LOCAL_COUNT, $productId);
 22         self::$userId               = $userId;
 23         self::$productId            = $productId;
 24     }
 25     static  function clear(){
 26     apcu_delete(self::$APCU_LOCAL_STOCK);
 27     apcu_delete(self::$APCU_LOCAL_USE);
 28     apcu_delete(self::$APCU_LOCAL_COUNT);
 29
 30     }
 31     /*查剩余库存*/
 32     static function getStock()
 33     {
 34     $stockNum = apcu_fetch(self::$APCU_LOCAL_STOCK);
 35         if ($stockNum === false) {
 36             $stockNum = self::initStock();
 37         }
 38         self::output([‘stock_num‘ => $stockNum]);
 39     }
 40     /*抢购-减库存*/
 41     static function buy()
 42     {
 43         $localStockNum = apcu_fetch(self::$APCU_LOCAL_COUNT);
 44         if ($localStockNum === false) {
 45             $localStockNum = self::init();
 46         }
 47         $localUse = apcu_inc(self::$APCU_LOCAL_USE);//本已卖 + 1
 48         if ($localUse > $localStockNum) {//抢购失败 大部分流量在此被拦截
 49         echo 1;
 50             self::output([], -1, ‘该商品已售完‘);
 51         }
 52         //同步已售库存 + 1;
 53         if (!self::incUseCount()) {//改失败,返回商品已售完
 54             self::output([], -1, ‘该商品已售完‘);
 55         }
 56         //写入创建订单队列
 57         self::conRedis()->lPush(self::$REDIS_REMOTE_QUEUE, json_encode([‘user_id‘ => self::$userId, ‘product_id‘ => self::$productId]));
 58         //返回抢购成功
 59         self::output([], 0, ‘抢购成功,请从订单中心查看订单‘);
 60     }
 61     /*创建订单*/
 62     /*查询订单*/
 63     /*总剩余库存同步本地,定时执行就可以*/
 64     static function sync()
 65     {
 66         $data = self::conRedis()->hMGet(self::$REDIS_REMOTE_HT_KEY, [self::$REDIS_REMOTE_TOTAL_COUNT, self::$REDIS_REMOTE_USE_COUNT]);
 67         $num = $data[‘total_count‘] - $data["used_count"];
 68         apcu_add(self::$APCU_LOCAL_STOCK, $num);
 69         self::output([], 0, ‘同步库存成功‘);
 70     }
 71     /*私有方法*/
 72     //库存同步
 73     private static function incUseCount()
 74     {
 75         //需要查远端的总库存和已经售卖的计数
 76         //同步远端库存时,需要经过lua脚本,保证不会出现超卖现象
 77         //因为redis是单进程模型,可有效的避免两个用户同时进行查库存和扣库存
 78         $script = <<<eof
 79             local key = KEYS[1]
 80             local field1 = KEYS[2]
 81             local field2 = KEYS[3]
 82             local field1_val = redis.call(‘hget‘, key, field1)//总库存
 83             local field2_val = redis.call(‘hget‘, key, field2)//已经售卖的计数
 84             if(field1_val>field2_val) then
 85                 return redis.call(‘HINCRBY‘, key, field2,1)
 86             end
 87             return 0
 88 eof;
 89         //eval()执行lua脚本的方法
 90         return self::conRedis()->eval($script,[self::$REDIS_REMOTE_HT_KEY,  self::$REDIS_REMOTE_TOTAL_COUNT, self::$REDIS_REMOTE_USE_COUNT] , 3);
 91     }
 92     /*初始化本地数据*/
 93     private static function init()
 94     {
 95         apcu_add(self::$APCU_LOCAL_COUNT, 150);
 96         apcu_add(self::$APCU_LOCAL_USE, 0);
 97     }
 98     static  function initStock(){
 99         $data = self::conRedis()->hMGet(self::$REDIS_REMOTE_HT_KEY, [self::$REDIS_REMOTE_TOTAL_COUNT, self::$REDIS_REMOTE_USE_COUNT]);
100         $num = $data[‘total_count‘]- $data["used_count"];
101         apcu_add(self::$APCU_LOCAL_STOCK, $num);
102         return $num;
103     }
104 }
105 try{
106 $act = $_GET[‘act‘];
107 $product_id = $_GET[‘product_id‘];
108 $user_id = $_GET[‘user_id‘];
109 $obj = new Api($product_id, $user_id);
110 if (method_exists($obj, $act)) {
111     $obj::$act();
112     die;
113 }
114 echo ‘method_error!‘;
115 } catch (\Exception $e) {
116     echo ‘exception_error!‘;
117     var_dump($e);
118 }
  1. 创建,支付订单
    1. 与扣库存服务隔离
    2. 用户收到抢购成功,页面跳转到订单中心去支付订单
    3. 图解: MQ异步创建订单

  1. 读商品信息页
    1. 与库存服务隔离
    2. 商品库一主多从提高读能力
    3. 页面静态化+缓存+db实现即可
  2. 排队进度查看(创建订单海量,怎么解决高性能查排队进展的问题)
    1. 结构
      1. 数组A: 例大小1000
      2. Hash表B: 通过key查找value,通过hash函数计算得到索引位置
    2. 思路
      1. 数组A存储排队中,待创建订单的用户;数组B用作索引,存储uid对应在数组A中的索引位置
      2. 每次从数组A中依次消费数据,并记录最近消费的索引值X
      3. 用户来查排队进展时,从hash表B中取出该uid对应存储的索引值Y
      4. 索引值Y - 索引值X = 排队进度值
  3. 高性能读库存(强一致性要求低)
    1. 读取本地库存,无则主动拉取一次,有则返回
    2. 异步脚本定时同步库存至本地
    3. 对接口进行压测

qps1800 启动了一个fpm,单进程

  1. 总结
    1. 读场景
      1. 读商品详情
      2. 读库存
      3. 读排队进度
    2. 写场景
      1. 扣库存
      2. 写订单
    3. 高性能服务: 单性能多携程及异步I/O方式实现的
  2. 链路如何实现漏斗形流量


链路流量优化-总结


1.页面静态化cdn缓存(降低商品详情页回源)

2.限流(访问库存数的限流,限制高频读,但是保证限流时间短)


客户端:app,浏览器

1.防重入(抢购后,让抢购按钮置灰)

2.分片削锋(通过验证码方式将原本并行的流量分散)

3.限流(通过本地cache限制用户抢购频次)


1.负载均衡(接口流量分摊给每个server)

2.限流(针对单个用户或接口)


接入层:nginx

1.负载均衡(降低到达单机server的流量)

2.限流(针对某个用户限制其访问频次或总连接数)


1.集群化部署(降低单服务流量)

2.cache+本地总库存


server:php

1.集群化部署(通过加机器方式提高整个servers访问能力,降低到达单机的流量)

2.本地库存(通过每个server本地减库存方式降低真正扣库存的流量)

3.写订单-排队(降低创建订单的并发量)


1.读写分离(基于数据库层面,通过一主多从提高读的访问能力)

数据:读写
 

原文地址:https://www.cnblogs.com/qiusanqi/p/11988445.html

时间: 2024-11-10 14:25:40

Redis+PHP秒杀设计的相关文章

Redis的Client设计

本文原创为freas_1990,转载请标明出处:http://blog.csdn.net/freas_1990/article/details/25432823 Redis的client设计如下: /* With multiplexing we need to take per-clinet state. * Clients are taken in a liked list. */ typedef struct redisClient { int fd; redisDb *db; int di

为什么C/C++程序员都要阅读Redis源码之:Redis学习事件驱动设计

为什么我说C/C++程序员都要阅读Redis源码 主要原因就是『简洁』.如果你用源码编译过Redis,你会发现十分轻快,一步到位.其他语言的开发者可能不会了解这种痛,作为C/C++程序员,如果你源码编译安装过Nginx/Grpc/Thrift/Boost等开源产品,你会发现有很多依赖,而依赖本身又有依赖,十分痛苦.通常半天一天就耗进去了.由衷地羡慕 npm/maven/pip/composer/...这些包管理器.而Redis则给人惊喜,一行make了此残生. 除了安装过程简洁,代码也十分简洁.

基于Redis/Memcached的高并发秒杀设计

如何设计高并发时的秒杀,是面试电商技术职位时必考的题目.今天在这里分享一下基于Redis或Memcached的技术方案,能解决重复提交.超发.高并发的问题. <?php //预定义总库存define("TOTAL_STOCK", 5);//预定义商品编号define("ITEM_ID", "ITEM_001"); $userId = $_GET['userId'];$userIdKey = ITEM_ID . '_' . $userId;

.NetCore+Jexus代理+Redis模拟秒杀商品活动

开篇叙 本篇将和大家分享一下秒杀商品活动架构,采用的架构方案正如标题名称.NetCore+Jexus代理+Redis,由于精力有限所以这里只设计到商品添加,抢购,订单查询,处理队列抢购订单的功能:有不足或者不够详细的还请见谅,顺手点个推荐也不错: a. 秒杀流程 b. 封装StackExchange.Redis的使用类 c. Ubuntu16.04上使用Jexus搭建代理完成分布式部署 d. NetCore写实时监控队列服务 秒杀架构设计图︿( ̄︶ ̄)︿三幅 1. 一般业务性架构 2. 后端分布

Redis初识、设计思想与一些学习资源推荐

一.Redis简介 1.什么是Redis Redis 是一个开源的使用ANSI C 语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value 数据库,并提供多种语言的API.从2010 年3 月15 日起,Redis 的开发工作由VMware 主持. Redis 是一个Key-Value 存储系统.和Memcached 类似,它支持存储的value 类型相对更多, 包括string(字符串).hash(散列).list(链表).set(集合)和zset(有序集合).这些数据类型支持p

互联网秒杀设计

分享内容抢先看 本次分享介绍了A对抢购业务的设计实践.主要包括例如以下主题: 1. 抢购业务介绍 2. 详细抢购项目中的设计 2.1. 怎样解耦前后端压力 2.2. 怎样保证商品库存可靠 2.3. 怎样在业务中多放对账 3. 项目总结 4. Q & A 抢购.闪购,从国外风靡后,国内各类站点都開始做相似的业务,我们耳熟能详的唯品会.淘宝.京东都有这类业务.抢购,很多其它出如今电商站点.那么.今天和大家一起学习下抢购业务形态的业务架构设计. 1.抢购业务介绍 我们常见的抢购业务分两种: 限时抢购.

thinkphp+redis实现秒杀功能

1,安装redis,根据自己的php版本安装对应的redis扩展(此步骤简单的描述一下) 1.1,安装 php_igbinary.dll,php_redis.dll扩展此处需要注意你的php版本如图: 1.2,php.ini文件新增 extension=php_igbinary.dll;extension=php_redis.dll两处扩展 ok此处已经完成第一步redis环境搭建完成看看phpinfo 2,项目中实际使用redis 2.1,第一步配置redis参数如下,redis安装的默认端口

redis优化秒杀系统

用redis提高基于mss的秒杀系统 使用背景: 普通的基于mss框架的系统在并发量不是很高的情况下,对redis的需求不是很高.redis在系统中的角色相当于一个对象缓存器,在高并发的系统中(比如秒杀系统),在某一刻对数据库中的一条数据可能是成千上万的用户同时去访问,系统的用户体验度直接受到数据库的性能的影响.为了保证数据的完整性,用户只能串行访问数据库中的某一条记录.redis则是把记录对应的对象序列化存储在自身的容器中,减少数据库的压力.废话不多说,接下来简单介绍redis的使用. red

借助Redis做秒杀和限流的思考

最近群里聊起秒杀和限流,我自己没有做过类似应用,但是工作中遇到过更大的数据和并发. 于是提出了一个简单的模型: var count = rds.inc(key); if(count > 1000) throw "已抢光!" 借助Redis单线程模型,它的inc是安全的,确保每次加一,然后返回加一后的结果.如果原来是234,加一了就是235,返回的一定是235,在此中间,不会有别的请求来打断从而导致返回236或者其它. 其实我们可以理解为inc的业务就是占坑排队,每人占一个坑,拿到