秒杀是电子商务网站常见的一种营销手段:将少量商品(通常只有一件)以极低的价格,在特定的时间点开始出售。比如一元钱的手机,五元钱的电脑,十元钱的汽车等。因 为商品价格诱人,而且数量有限,所以很多人趋之若鹜,在秒杀活动开始前涌入网站,等到秒杀活动开始的一瞬间,点下购买按钮(在此之前购买按钮为灰色,不可以点击),抢 购商品。这些商品因为在活动开始的一秒内就被卖光了,所以被称作秒杀。
鉴于只有少部分用户能秒杀成功,所以要限制大部分流量,只允许少部分流量进入服务后端。
对于秒杀系统瞬时会有大量用户涌入,所以在抢购一开始会有很高的瞬间峰值。
高峰值是压垮系统很重要的原因,所以如何把瞬间的高流量编程一段时间平稳的流量也是设计秒杀系统很重要的思路。实现削峰的常用方法有利用缓存和消息中间件等技术。
秒杀系统是一个高并发系统,采用异步处理模式可以极大地提高系统并发量,其实异步处理就是削峰的一种实现方式。
秒杀系统最大的瓶颈一般是数据库读写,由于数据库读写属于磁盘 IO,性能很低,如果能够把部分数据或逻辑业务转到内存缓存,效率会有极大提高。
如果我们想支持更多用户,更大的并发,最好将系统设计成弹性可扩展的,如果流量来了,拓展机器就好了。
-
将请求拦截在系统上游,降低下游压力
秒杀系统特点是并发量极大,但实际秒杀成功的请求数量却很少,所以如果不在前端拦截很可能造成数据库读写锁冲突,甚至导致死锁,最终请求超时。
-
充分利用缓存
利用缓存可极大提高系统读写速度。
-
消息队列
消息队列可以削峰,将拦截大量并发请求,这也是一个异步处理过程,后台业务根据自己的处理能力,从消息队列中主动拉取请求消息进行业务处理。
-
页面静态化
将页面上的所有可静态的元素全部静态化,并尽量减少动态元素。通过 CDN 来抗峰值。
-
禁止重复提交
用户提交后按钮置灰,禁止重复提交。
-
用户限流
在某一时间段内只允许用户提交一次请求,比如可以采取 IP 限流。
前端方案只拦截了浏览器访问的请求,但针对某些恶意攻击或其他插件,在服务器控制层需要针对同一个访问 uid,限制访问频率。
-
采用消息队列缓存请求
先将请求都写到消息队列中都缓存一下,数据库层订阅消息减库存,减库存成功的请求返回秒杀成功,失败的返回秒杀失败。
-
采用缓存应对读请求
如果是多读写少业务,大部分请求时查询请求,所以可以充分利用缓存分担数据库压力。
-
采用缓存应对写请求
缓存也可以应对写请求的,比如我们可以把数据库中的库存数据转移到 Redis 缓存中,所有减库存操作都在 Redis 中进行,然后再通过后台进程把 Redis 中的用户秒杀请求同步到数据库中。
数据库是最脆弱的一层,一般在应用设计时在上游就需要把请求拦截掉,数据库层承担“能力范围内”的访问请求。所以通过服务层引入队列和缓存,让最底层的数据库高枕无忧。