作者 | 悟空哥
来源 | 悟空聊架构(ID:PassJava666)
星球简介
地点:β-410 星系,A-731电商星球。
时间:新纪元 2036 年。
星球简介:
- 中文名:A-731电商星球
- 外文名:A-731 Mall
- 分类:行星
- 公转周期:一年
- 常驻用户:中间件工作者、各种请求。
- 星球总历史:二十万年。
星球危机
我是一个秒杀请求,每天的工作就是将秒杀请求的数据运送给后端工作者。
这天我在 Nginx 转发服务器上遇见了请求「小空」 ,我跟小空说有重要消息不方便现在告诉他,下班再约,然后就都匆匆赶路了。
我和小空晚上十点下班后来到一家酒吧,点了两杯 mojito,找了一个角落坐下。
小空:你最近看起来心事重重。
我:你有没有发现最近我们星球的订单数急剧增加,每天有一千万订单数据产生,也不是一天、两天的事了。
小空:难怪我每天加班到晚上十点来运送请求数据。
我:我有个舅舅在航天局上班,告诉我说我们星球承载不了那么多请求和订单数据,不久就会出现「行星大爆炸」 。你可不要透露给别人。
小空:那怎么办?
我:我们可以去 100 光年外的 T-714 星球,但是只能通过秒杀通道坐时空穿梭机去那颗星球。而且名额有限制,不知道我有没有机会登上穿梭机。
我:明天通道会开启两次,上午十点和下午两点。你明天和我一起去吧!
小空:好的。
星球大爆炸
「涉及的知识点:」
- 这里的行星大爆炸指的是什么?
- 因订单数据量很大,数据库撑不住了。数据库可能宕机。
- 因每天有大量请求发送到服务器,服务器也扛不住了。服务器可能宕机。
- 秒杀通道每天开启两次代表了什么?
- 「流量错峰」 ,将流量分摊到两个秒杀场次。
- 当然「流量错峰」 的手段还有输入验证、加入购物车等分摊流量的做法。
秒杀通道
地点:A-731 星球机场
时间:09 : 45
通道
“请前往 T-714 星球的请求旅客到 Y1 站台排队等待进入特殊通道, 15 分钟后开始进入穿梭机大厅”。大厅的广播连续播放了三遍。
我走向了特殊通道,看到通道旁立着一个牌子:秒杀通道,只给秒杀请求使用。
「涉及知识点:」
- 秒杀场景为什么单独弄了条通道?
- 秒杀业务为了不影响系统的其他业务单独部署了一套秒杀系统。
- 总结为「服务单一职责 + 独立部署」
实时大屏
一抬头看到通道上方有一个大屏,在不断播放 T-714 星球的照片,以及机票的订单信息。
T-714 星球
有两个穿制服的工作者正在大屏旁巡逻。一个制服上印着 Nginx,一个制服上印着 CDN。
Nginx+CDN
「涉及知识点:」
- Nginx 制服:
- 穿 Nginx 制服的工作者在维护 Nginx 的静态和动态资源。
- 商品详情页是一个静态页面,将这些静态页面存储到 Nginx 服务器上,访问静态资源时,请求先到 Nginx,然后 Nginx 服务器通过请求的 URL 链接来匹配是否是访问的静态资源。
- 大屏的商品详情页并不是通过发送请求从后台服务器拿到的。其实实现了「动静分离」 。
- 一张图解释 Nginx 动静分离
Nginx 流程图
- 静态资源比如 HTML 文件极少变化,就可以专门放到一台服务器上,直接访问,不需要与后台服务器交互(比如 Tomcat)。
- 动态资源比如需要从后台拿到有多少人购买了商品,发送下单请求来存储数据,这些都称作动态资源,不能狭隘的理解为看得见的资源,广义上可以包括获取逻辑处理的结果,执行存储数据等操作。
- CDN 制服
- 什么是 CDN:CDN 大白话解释就是用户就近获取资源,减少网络传输时间,提高访问速度。
- Nginx 上放 HTML文件,而 CDN 上则放 HTML 引入的图片文件、脚本文件。
- 穿 CDN 制服的工作者在维护 CDN 的资源。
- 一张流程图解释 CDN 工作原理
CDN 流程图
验证通道
时间:10:00
“验证通道已开启,请携带密码进入!” 又是播放了三遍广播。
输入密码
「涉及的知识点:」
- 为什么需要密码?
- 为了防止大量模拟的秒杀请求进入业务处理流程,所以先加一道验证,丢弃这些假请求。
- 怎么做到的?前端网页先发送请求拿到密码,点击抢购时,请求体中携带加密密码,后端校验密码是否匹配。可以通过 MD5 加密。
- 总结为「秒杀请求加密」 。
穿梭机大厅
穿梭机大厅
经过验证通道的筛选后,有一半的假请求被挡在门外,像我这种拿到了正确密码的顺利进入了穿梭机大厅。
来到大厅,发现大厅的正中央摆放着一个显示器,上面显示的红色数字 100 赫然映入眼中。
显示屏的左手边站着一位穿着 Redis 统一制服的靓女。在一旁的我偷听到原来她是控制显示器显示穿梭机剩余数量的。如果数字变为 0 ,则表示穿梭机已经全部被占用,后来的人就得无功而返了。
「涉及的知识点:」
- 秒杀场景中,查询剩余库存并不是直接查数据库,而是查 Redis 缓存的。
- 为什么是查缓存?因为查缓存的速度要远远快于查数据库,减少了响应时间,而且对数据库的压力减小了很多。如果很多查库存的请求都到数据库了,那数据库就要崩了,而且数据库干不了其他的活了。
抢票
显示屏的右手边站着一位西装笔挺的年轻帅哥,看到他的袖口上挂着一个红袖章,印着 Redisson 字样。他一脸严肃的模样,对大厅内黑压压一片的请求熟视无睹。可能是见惯了这种场景吧。
正在打量这位帅哥时,发现他的左手拿着一叠机票,没错,有了一张机票就可以登入穿梭机了。我以百米冲速的速度到达了他面前,到达他面前时,已经有十几个请求也到了他身边,他按照先来后到的顺序依次发放机票,到我的时候,机票已经只剩几张了,庆幸的是我的百米冲速帮我抢到了一张机票。我问帅哥是否可以再发一张票给我,他拒绝了。
每一次发放票,穿 Redis 制服的靓女都会操作显示屏,让其数量减一。
十秒钟后,票已经发完,显示屏显示数字 0 。
「涉及的知识点:」
- Redisson 是啥呢?Redis 客户端,解决了分布式的一些常见问题。
- 这里其实用到了 Redisson 的信号量功能,总共有 100 张票,也就是 100 个信号量,而且票的数量不会因为多线程并发或分布式系统的原因而导致票的数量被超卖。比如卖出了 101 张票。
- 每个人只能获得一张票,这就是秒杀系统中涉及到的幂等性校验,不能重复抢票。
售票窗口
登机牌
登机牌
发放机票的帅哥告诉我,拿到票后,到 A 窗口排队付款,才能拿到登记牌。于是我和另外 99 个请求一起在 A 窗口排队了。
看到一个请求想要放弃付款了,说是机票太贵了,然后准备离开大厅时,被发放机票的帅哥拦住了,他问请求是否要考虑下,有 15 分钟的考虑时间,如果请求还是觉得不行,可以将机票还给他,他可以再发放给其他人。
队列削峰
「涉及的知识点:」
- 秒杀系统中常用的「队列削峰」 。秒杀成功的请求,进入队列,慢慢创建订单、扣减库存。
- 秒杀成功后,快速告诉用户已经秒杀成功,而不是等待订单完再告诉用户,那用户就要多等一会了,影响体验。
- 为什么要做队列削峰?成功的请求不必一下子都去数据库创建订单,这样对数据库的压力也会小一些。
- 在秒杀场景中,很有可能有用户抢到了但是不付款的场景,这个时候库存是要加回去的,可以提供给其他用户。
启航
订单创建成功后,我顺利拿到了登机牌,通过了登机牌的校验后,成功登上了穿梭机。
出发,去往 T-714 星球。听说那个星球的数据库进行了分库分表、服务也拆分成了微服务。
总结
上面通过科幻小说的方式来讲解了秒杀系统中关注的点,下面是对秒杀系统关注的八大点的一个总结:
秒杀场景关注点
- 服务单一职责、独立部署
- 库存预热、快速扣减
- 秒杀链接加密
- 动静分离
- 恶意请求拦截
- 流量错峰
- 限流&熔断&降级
- 队列削峰
本文转载自微信公众号「悟空聊架构」,可以通过以下二维码关注。转载本文请联系悟空聊架构公众号。