美文网首页我爱编程
高并发下用户抢购问题简答

高并发下用户抢购问题简答

作者: guijianshi | 来源:发表于2018-03-22 20:51 被阅读0次

高并发下用户抢购问题简答

前言

面试题当中如何处理高并发用户抢购问题可以说是一个十分经典的问题,经常被提及,在这就这个问题写一个简要的解答;

思路

并发的最大瓶颈永远是数据库,MySQL的读写速度是制约并发的最大问题,而抢购之时真正需要写入的用户量实际上是很少的,等于抢购的商品总数.这就要求我们需要把无效的用户排除出.在前期放入有效用户量,一旦产品抢购结束,将活动页改为结束也的静态页面,最大程度的提升服务器相应速度.这里面放入限定数量的用户是最为关键的地方.
redis的高性能读写是现在最为主流的解决方案.下面就简单的介绍一下如何用redis来完成高并发抢购处理.

解决方案

将用户id写入redis列表当中,一旦列表长度达到商品总数,则拒掉后面的用户.

示例代码

Talk is cheap, show you my code.

<?php
/**
 * Created by PhpStorm.
 * User: mc
 * Date: 18/3/21
 * Time: 下午1:53
 */
$user_id = rand(100, 10000); // 模拟用户id
$key = 'user_list'; // 列表名
$redis = new Redis();
$redis->pconnect('localhost', 6379);
$len = $redis->lLen($key); // 获取列表长度
$count = 10; // 商品总数
if ($len >= $count) { // 达到商品总数则停止抢购
    echo '秒杀已结束';
    return '秒杀已结束';
}
$redis->lPush($key, $user_id);  // 将用户id推入列表
echo '恭喜你秒杀成功';
return '恭喜你秒杀成功';

ab测

ab -n 3000 -c 100 http://localhost:8001/     // 模拟3000个请求,100个并发

结果

列表当中的结果确实是10条,满足要求

 LRANGE user_list 0 -1
 1) "466"
 2) "5090"
 3) "8299"
 4) "6436"
 5) "4537"
 6) "9617"
 7) "9291"
 8) "2162"
 9) "1903"
10) "983"
Concurrency Level:      100
Time taken for tests:   4.558 seconds
Complete requests:      3000
Failed requests:        0
Total transferred:      540000 bytes
HTML transferred:       45000 bytes
Requests per second:    658.22 [#/sec] (mean)
Time per request:       151.924 [ms] (mean)
Time per request:       1.519 [ms] (mean, across all concurrent requests)
Transfer rate:          115.70 [Kbytes/sec] received

QPS能够达到658.

问题

上面的代码看似没问题,可是要是老司机一定不难发现代码当中存在一个极大的漏洞.当列表当中有9个值,两个用户同时取得$len,那么这两个用户就会被同时写入列表当中,这样就会出现超卖的问题.而且写列表的方式就需要取数据要在抢购完成之后,这显然不合理.
这需要我们将抢购判断和用户列表拆分开来,redis当中的string有一一自增的api具有原子性,哪怕并发情况下也一定能够保证自增.这能够很好的服务于我们的需求.

代码示例

$user_id = rand(100, 10000); // 模拟用户id
$key = 'user_list'; // 列表名
$redis = new Redis();
$redis->connect('localhost', 6379);
$len = $redis->incr('count');
$count = 10; // 商品总数
if ($len > $count) { // 达到商品总数则停止抢购
    echo '秒杀已结束';
    return '秒杀已结束';
}
$redis->lPush($key, $user_id);  // 将用户id推入列表
echo '恭喜你秒杀成功';
return '恭喜你秒杀成功';

这样就可以避免商品超售了,而且列表的生产和消费可以同步进行,提升业务体验.当然真正的业务当中复杂度远高于这里.

关于避免用户重复抢的简略方案

<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$user_id = rand(1, 15);
if (!$redis->hSetNx('seckill', 'test:' . $user_id, 1)) { // hSetNx函数当key存在时会返回false,不存在时才会被设置成功,返回true
    echo '您已经参加过秒杀请勿重复参加';
    return '您已经参加过秒杀请勿重复参加';
}

$len = $redis->incr('count');
$count = 10; // 商品总数
if ($len > $count) { // 达到商品总数则停止抢购
    echo '秒杀已结束';
    return '秒杀已结束';
}
$redis->lPush('user_id', $user_id);
echo '恭喜您,秒杀成功';
return '恭喜您,秒杀成功';

上面的QPS才600+而原生的PHP在我的电脑下应该能到达3000+,这里面new Redis()创建redis连接耗费了过多的资源

连接复用

<?php
$redis = new Redis();
$redis->pconnect('127.0.0.1', 6379); // redis自带连接复用函数
$user_id = rand(1, 15);
if (!$redis->hSetNx('seckill', 'test:' . $user_id, 1)) { // hSetNx函数当key存在时会返回false,不存在时才会被设置成功,返回true
    echo '您已经参加过秒杀请勿重复参加';
    return '您已经参加过秒杀请勿重复参加';
}

$len = $redis->incr('count');
$count = 10; // 商品总数
if ($len > $count) { // 达到商品总数则停止抢购
    echo '秒杀已结束';
    return '秒杀已结束';
}
$redis->lPush('user_id', $user_id);
echo '恭喜您,秒杀成功';
return '恭喜您,秒杀成功';
Concurrency Level:      100
Time taken for tests:   0.428 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      180000 bytes
HTML transferred:       15000 bytes
Requests per second:    2337.77 [#/sec] (mean)
Time per request:       42.776 [ms] (mean)
Time per request:       0.428 [ms] (mean, across all concurrent requests)
Transfer rate:          410.94 [Kbytes/sec] received

结束

QPS能够高达2300+完全能够适应一般业务的并发需求了.

相关文章

  • 高并发下用户抢购问题简答

    高并发下用户抢购问题简答 前言 面试题当中如何处理高并发用户抢购问题可以说是一个十分经典的问题,经常被提及,在这就...

  • 一个简单的处理抢购的一个方法

    抢购 抢购是一个开发中很容易遇到的问题,不管是抢购也好还是什么也好都会遇到高并发下数据可能出现超卖的这种现象。 解...

  • redis高并发下如何抢购防止超卖问题

    抢购是如今很常见的一个应用场景,主要需要解决的问题有两个: 1 高并发对数据库产生的压力 2 竞争状态下如何解决库...

  • 高并发下的抢购/秒杀功能

    抢购/秒杀是如今很常见的一个应用场景,那么高并发竞争下如何解决超抢(或超卖库存不足为负数的问题)呢? 常规写法: ...

  • redis实现高并发下的抢购/秒杀功能

    抢购/秒杀是如今很常见的一个应用场景,那么高并发竞争下如何解决超抢(或超卖库存不足为负数的问题)呢? 常规写法: ...

  • 秒杀抢购思路以及高并发下数据安全

    我们通常衡量一个Web系统的吞吐率的指标是QPS(Query Per Second,每秒处理请求数),解决每秒数万...

  • Redis实现高并发下的抢购、秒杀功能

    欢迎大家关注我的其他 Github博客 和 Csdn ,互相交流! 博主最近在项目中遇到了抢购问题!现在分享下。抢...

  • 高并发与缓存

    本文主要讲述高并发下缓存会出现的问题。 在高并发下,缓存会出现的问题有:缓存一致性、并发问题、穿透问题、缓存的雪崩...

  • 高并发下的mysql问题

    高并发下的mysql问题 mysql 重复插入问题 业务需要先根据where条件查询,如有数据命中对其进行修改否则...

  • php使用redis实现高并发下的抢购功能

    抢购、秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个: 高并发对数据库产生的压力 竞争状态下如何解决库存...

网友评论

    本文标题:高并发下用户抢购问题简答

    本文链接:https://www.haomeiwen.com/subject/qhezqftx.html