哈喽,小伙伴们大家好!当你们被咨询或者面试到这个问题的时候,大家是不是很困惑?甚至无从下手,感觉这不应该是面试(guan)架(wo)构(mao)师(shi)的问题吗?下面根据我多年来总结的经验,给大家一个示范应答,帮助小伙伴们轻松面对,仅供参考哈!
首先既然设计一个系统,我们就从软、硬件两方面来回答:
第一点:通常秒杀系统活动时间都是比较短,TB双十一买过的小伙伴们肯定深有体会,前一秒秒杀按钮还是可点击的,下一秒后就灰色了,无疑瞬间的操作除了快还是快。。。。。并且秒杀活动的并发量一定是巨大的,所以一定不要和你自身业务系统放置在一起,不然有可能会瞬间瘫痪的哦!可以分配独立的域名单独做个程序来放置。
第二点:通常在秒杀活动前,为了不错过活动,用户会频繁的刷新当前页面,这个操作其实会对后台造成一定的负载,所以在使用数据库集群、Redis集群,负载均衡之外,秒杀页面最好实现静态化,免得因为频繁刷新动态渲染的页面而消耗资源。
第三点:需要短时间内增加网络带宽,可以选择在云端增加或者临时租用带宽资源。也可以把秒杀系统放在CDN(动态分发网络)节点上,这样就可以节省秒杀服务器的带宽了。
第四点:为了防止用户提前获取秒杀下单页面,可以使用动态URL解决问题,使用Redis缓存保存一串随机字符串,秒杀活动时所有用户访问页面都必须要带上上述所说的字符串。
第五点:扣减库存也是一个很值得大家注意的地方,其实最容易发生的问题就是超卖引起的扣减库存不正确,可以使用乐观锁来解决,也就是所谓的更新使用版本号。或者使用Redis事务来解决。
第六点:做好限流,使用消息队列来控制请求
如何解决超售问题?
在秒杀活动之前,我会使用程序在Redis缓存里面创建商品的库存记录,秒杀活动的时候使用watch命令查看Redis里面的库存和秒杀成功的用户列表,开启Redis事务扣减库存并记录一下成功秒杀商品的用户Id,最后提交Redis事务。如果在提交事务和指令给Redis执行事务的同时没有被其他程序打断,则可以使用Redis单线程的特性成功扣减库存,不会引起超售问题。
下面附上操作代码:
这里使用Redis客户端Jedis进行操作,POM引用的依赖为jeds的3.0.1版本。使用线程成进行模拟。
使用Redis事务机制,因为Redis自带乐观锁,所以使用事务的时候Redis的watch命令会帮助我们用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。也就防止在运行期间被其他程序所打断,最后我们看下Redis的数据。
可以看到秒杀的商品数量和我们之前预期设置的商品数量是一致的,都为50个。
库存为0,所以使用Redis事务机制是可以有效的防止库存扣减以及商品超卖的问题。