12-场景

1、秒杀场景

应对策略:

1)秒杀系统独立部署

2)秒杀商品页面静态化

3)租借秒杀活动带宽(将秒杀页面缓存到CDN)

4)动态生成下单URL,防止用户直接访问下单页面URL

5)按钮置灰,5秒内不可重复点击

6)集群中的每台服务器都只接受固定数量请求,其他直接响应秒杀活动结束

7)友好设计:所有异常都应捕获,即使服务器瘫痪,应返回“秒杀活动结束”

Mysql层面优化,丁奇:

测试显示,在6线程时,TPS达到顶峰1.9W,随着线程数增加TPS急剧下降

问题:当线程并发时,Innodb内部存在太多线程

1)关掉死锁检测,正常的业务死锁会变成超时,治标不治本,效果微弱

2)修改源码:将排队队列提到进入引擎层之前(放到server层),随着线程数增加TPS稳定在1.5W

3)优化排队,组提交策略,TPS提升稳定至8.5W

如何防止超卖

以下3种办法:

1、将提交操作变成两段式,先申请后确认。

1.1利用Redis的原子自增操作(相比较MySQL的自增来说没有空洞),同时利用Redis的事务特性来发号,

  保证拿到小于等于库存阀值的号的人都可以成功提交订单。

1.2数据异步更新到DB中。

优点:解决超卖问题,库存读写都在内存中,故同时解决性能问题。

缺点:由于异步写入DB,可能存在数据不一致。另可能存在少买,也就是如果拿到号的人不真正下订单,可能库存减为0,但是订单数并没有达到库存阀值。

2、数据库层面

2.1设计2张表:

第一张:判重表(buy_record),该用户有没秒杀过该商品

字段: id, uid, goods_id, addtime

第二张表:商品表 goods

字段: goods_id  goods_num

2.2对(uid,goods_id)加唯一索引!

start transaction;

insert into buy_record。。。

if(唯一索引报错?)

    抛异常,已经秒过了,回滚。。。

update goods set goods_num=goods_num-1  where goods_id=$goods_id and goods_num>0 ;

if(受影响行数<=0)

    抛异常,商品秒完了,回滚。。。

该方法完美的解决了超卖与select排它锁导致的并发低的问题。极大提升性能

3、Mysql优化,改源码

丁奇在DTCC2013上分享的《秒杀场景下MySQL的低效》

1)关掉死锁检测,正常的业务死锁会变成超时,治标不治本,效果微弱

2)修改源码:将排队队列提到进入引擎层之前(放到server层),随着线程数增加TPS稳定在1.5W

3)优化排队,组提交策略,TPS提升稳定至8.5W

你可能感兴趣的:(12-场景)