如何设计一个秒杀系统?
设计秒杀系统之前,我们首先需要对秒杀系统有一个清晰的认识。
秒杀系统主要为商品(往往是爆款商品)秒杀活动提供支持,这个秒杀活动会限制商品的个数以及秒杀持续时间。
为什么秒杀系统的设计是一个难点呢? 是因为它的业务复杂么? 当然不是!
秒杀系统的业务逻辑非常简单,一般就是下订单减库存,难点在于我们如何保障秒杀能够顺利进行。
秒杀开始的时候,会有大量用户同时参与进来,因此秒杀系统一定要满足 高并发 和 高性能 。
为了保证秒杀整个流程的顺利进行,整个秒杀系统必须要满足 高可用 。
除此之外,由于商品的库存有限,在面对大量订单的情况下,一定不能超卖,我们还需要保证 一致性 。
很多小伙伴可能不太了解当代三高互联网架构:高并发、高性能、高可用。
我这里简单解释一下:高并发简单来说就是能够同时处理很多用户请求。高性能简单来说就是处理用户的请求速度要快。高可用简单来说就是我们的系统要在趋近 100% 的时间内都能正确提供服务。
知道了秒杀系统的特点之后,我们站在技术层面来思考一下:“设计秒杀系统的过程中需要重点关注哪些问题”。
参与秒杀的商品属于热点数据,我们该如何处理热点数据?
商品的库存有限,在面对大量订单的情况下,如何解决超卖的问题?
如果系统用了消息队列,如何保证消息队列不丢失消息?
如何保证秒杀系统的高可用?
如何对项目进行压测?有哪些工具?
......
好的,废话不多说!正式开始!
高性能
热点数据处理
何为热点数据? 热点数据指的就是某一时间段内被大量访问的数据,比如爆款商品的数据、新闻热点。
为什么要关注热点数据? 热点数据可能仅仅占据系统所有数据的 0.1% ,但是其访问量可能是比其他所有数据之和还要多。不重点处理热点数据,势必会给系统资源消耗带来严峻的挑战。
热点数据的分类? 根据热点数据的特点,我们通常将其分为两类:
静态热点数据 :可以提前预测到的热点数据比如要秒杀的商品。
动态热点数据 : 不能够提前预测到的热点数据,需要通过一些手段动态检测系统运行情况产生。
另外,处理热点数据的问题的关键就在于 我们如何找到这些热点数据(或者说热 key),然后将它们存在 jvm 内存里。 对于并发量非常一般的系统直接将热点数据存放进缓存比如 Redis 中就可以了,不过像淘宝、京东这种级别的并发量,如果把某些热点数据放在 Redis 中,直接可能就将整个 Redis 集群给干掉了。
如何检测热点数据?
我了解到的是市面上也有一些类似的中间件,比如京东零售的 hotkey 就是一款专门用于检测热点数据的中间件,它可以毫秒级探测热点数据,毫秒级推送至服务器集群内存。相关阅读:京东毫秒级热 key 探测框架设计与实践,已完美支撑 618 大促 。
另外,我们平时使用 Redis 做缓存比较多,关于如何快速定位 Redis 热点数据,可以看下如何快速定位 Redis 热 key这篇文章。
如何处理热点数据? 热点数据一定要放在缓存中,并且最好可以写入到 jvm 内存一份(多级缓存),并设置个过期时间。需要注意写入到 jvm 的热点数据不宜过多,避免内存占用过大,一定要设置到淘汰策略。
为什么还要放在 jvm 内存一份? 因为放在 jvm 内存中的数据访问速度是最快的,不存在什么网络开销。
静态资源处理
秒杀页面可能涉及到很多静态资源比如商品图片、CSS、JS。秒杀开始之前以及进行中的时候,会有大量的用户点开页面,有的用户还会不断的刷新秒杀界面。如果这些界面中的静态资源全部通过服务器获取,会造成大量的带宽消耗,甚至造成秒杀还没开始服务器就崩了。
对于这些静态资源,我们可以使用 CDN 进行处理,这是业内目前比较成熟的解决方案。
CDN 全称是 Content Delivery Network/Content Distribution Network,翻译过的意思是内容分发网络 。CDN 的作用是将静态资源分发到多个不同的地方以实现就近访问,进而加快静态资源的访问速度,减轻服务器以及带宽的负担。
你可以将 CDN 看作是服务上一层的特殊缓存服务,分布在全国各地,主要用来处理静态资源的请求。
基于成本、稳定性和易用性考虑,建议直接选择专业的云厂商(比如阿里云、腾讯云、华为云、青云)或者 CDN 厂商(比如网宿、蓝汛)提供的开箱即用的 CDN 服务。
高可用
集群化
如果我们想要保证系统中某一个组件的高可用,往往需要搭建集群来避免单点风险,比如说 Nginx 集群、Kafka 集群、Redis 集群。
我们拿 Redis 来举例说明。如果我们需要保证 Redis 高可用的话,该怎么做呢?
你直接通过 Redis replication(异步复制) 搞个一主(master)多从(slave)来提高可用性和读吞吐量,slave 的多少取决于你的读吞吐量。
这样的方式有一个问题:一旦 master 宕机,slave 晋升成 master,同时需要修改应用方的主节点地址,还需要命令所有从节点去复制新的主节点,整个过程需要人工干预。
不过,这个问题我们可以通过 Sentinel(哨兵) 来解决。Redis Sentinel 是 Redis 官方推荐的高可用性(HA)解决方案。
Sentinel 是 Redis 的一种运行模式 ,它主要的作用就是对 Redis 运行节点进行监控。当 master 节点出现故障的时候, Sentinel 会帮助我们实现故障转移,确保整个 Redis 系统的可用性。整个过程完全自动,不需要人工介入!
Sentinel 也是一个 Redis 进程,只是不对外提供读写服务,通常哨兵要配置成单数。
限流
限流是秒杀业务最常用的一个手段,所以经常你一参加秒杀就会提示“当前人数过多,请稍后再试”。
接口限流
限流是从用户访问压力的角度来考虑如何应对系统故障。接口限流是为了对服务端的接口接受请求的频率进行限制,防止服务挂掉。