来自个人博客 秒杀活动的设计
业务的基本说明
- 运营评估最高的并发会达到 10W(根据推广的力度,以及以往的经验)
- 业务现有的服务器架构 反向代理 4台,前端机 8台, db 2台(主从),redis 2台(主从)以下是服务器架构图
动静分离
html 等静态文件上CDN ,这方面压力不大
后台程序动态接口,必须支持高并发,用户体验必须做好
后端程序优化点(欢迎大家补充)
- 程序尽可能的减少加载的文件
- 程序减少不必要的网络请求
- redis 队列来作 异步方式实现
// 后台进程消费队列 个人使用brpoplpush方法 取出数据并用存入另外队列作数据备份
$block_expire_time = 0; # 设置阻塞等待时间为永久
$redis->brpoplpush($key, $backup_key, $block_expire_time);
- redis 缓存
- 前端点击按钮请求后变灰,防止用户重复点击
- 静态文件上CDN
- nginx的最大连接数设置为550,防止连接数过大时全部到php,导致php服务挂了
- 针对每个用户加并发锁(redis),防止高并发情况判断条件被绕过,程序执行完后解锁。
$lock_status = $redis->set($lock_key, 1, array("NX", "EX"=>$expire_time));
高并发下奖品超发问题
个人设计的方案:提前把每个奖品放入 redis队列,每个key一个奖品,队列的长度是奖品的数量,可以保证奖品不会超发放
另外,假设使用
悲观锁,在更新数据的时候加锁,其它的都为等待状态,不合适秒杀场景
乐观锁 基本是采用带版本号更新,版本号匹配才能更新,其它的回滚,虽然保证的数据的安全不超发放,但是在高并发场景下,DB只有两台的时候,超过mysql 进程堆积肯定会的, 超过最大连接数是怎么办,一系列的问题需要解决,所以该方案不合适
程序压测结果分析服务器能抗的并发
在平均响应时间300ms内,单台qps 750 左右(保持300ms是公司压测试的规范指标)
10台机器(后面新增2台到 8+2)一秒钟能处理: 10 * 750 = 7500
保守的并发只有7500,与10w 差距大,需要在执行方案上解决,公司不可无限的申请web机器。
解决10W并发问题(资源有限的情况)方案
在代理层做处理,根据权重挡掉93%的量,返回800(自定义),前端判断是否为800,是则提示火爆用户重试(对应的方案设置友好一些)
活动的序列图及说明
- 接口程序不连接查询mysql数据库
- 奖品的数据存放redis队列,每个奖品一个key,队列长度是奖品的数量
- 用户成功领取红包(或抢购)时的代码流程(不包括业务限制与防刷),从队列获取奖品成功,再入队列(此队列后台消费入库),返回给用户领取成功。在用户体验上有所提升,但如果后台队列堆积太多,未能消费完成,用户查看的红包时是没有对应记录的,所以针对自己的需求作对应的优化。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。