架构实战营 毕业设计项目
1. 业务背景
我们公司运营着一个日活大约 100 万人的小有名气的电商应用。
618 快到了,为了提升人气,公司决定开展秒杀活动。
我们挑选选品各大电商平台上畅销和好评的商品进行销售,每个品类不超过 20 个商品,目前做了 10 个品类;而我们的本次 618 的秒杀活动包含了两种商品:1000 个充电宝,以及 10 台 iphone12。
用户要参与秒杀活动必须要下载我们的 APP
此次秒杀活动关系到公司是否能借此提升知名度,所以要万无一失。
2. 约束和限制
团队技术以 java 为主,已经落地了微服务架构
只有一个机房
用户必须要下载 APP 才能参与秒杀
秒杀过程中不允许出现崩溃的情况,秒杀过程必须顺利完成
当前的消息队列已经在使用 kafka 作为消息队列的工具
3. 总体架构
负载均衡架构
存储架构
缓存架构
3.1 架构分析
数据分析:
日活 100 万的应用,参与秒杀的用户应该只有一部分,我们假设真正参与秒杀的用户占日活用户的 40%,那么就会有 40 万用户参加秒杀。秒杀活动的商品有 2 种:充电宝和 iphone,我们假设所有的 40%的用户都参加了两项秒杀,那么我们可以针对任意一种商品的秒杀进行设计。
因为要下载 APP 后才能进行秒杀活动,所以我们可以在 APP 端做 app 端的缓存,但是 app 端第一次加载活动也需要去真正获取秒杀活动数据,我们假设用户在秒杀开始前 10 分钟内开始请求秒杀活动信息,那么 qps 为:
40 万/(3600/6) = 666.6
而这个请求会打到 redis 上,这点压力对于 redis 丝毫无法构成问题。
而真正开始秒杀的时候,并不会将这 40 万的请求全部发到服务端,在 app 端限流,接入端限流,微服务端也限流,并且最后用漏桶来接受请求,这样一来服务器端的压力就会减轻很多。
3.1.1 高可用
负载均衡架构方面,使用了 3 个 nginx 组成的集群,避免了单点故障,而服务网关服务器也是多个(已经落地的微服务架构),最后的秒杀服务器也是多台,其实针对秒杀,3 台服务器也许已经够了,但是为了活动万无一失,特意冗余了 2 台服务器,避免出现意外的情况。5 台服务器其实是 5 个容器,用 k8s 集群管理,其中一个出现故障之后,马上有新的容器会启动替代故障的容器
存储架构方面使用了 Redis sentinel 对于整个 redis 的集群进行了高可用的保障,任何一个 redis 的实例出现写入或者读取问题的时候,sentinel 就会重新确定 master,并且尝试恢复不可服务的实体,在重启后将它改为 slave。
3.1.2 高性能
在缓存架构方面,使用了多级缓存的架构。首先是 app 的缓存,这个缓存在用户手机上,不消耗服务器的资源,数据从 redis 中读取之后,就会一直在用户 app 端,直到活动结束。而 redis 面对这个体量的(qps 约为 666.6)请求并不会有什么太大的压力。
而 redis 也是采用了主从架构,进一步分流了请求。可以在秒杀活动开始前,将活动数据预加载到 redis 里,实现缓存预热,避免出现缓存穿透问题。redis 除了会从数据库读取信息外,也会用 url 去请求 oss,因为秒杀肯定要有商品的图片信息。
3.1.3 可扩展
缓存架构中的 redis 其实是可以被替换成为其他的缓存工具的,而微服务架构中的一些组件也可以被方便的替换成相同角色的组件。如果未来要支持更大的流量,可以在负载均衡架构上把机房级别的 F5 加上,在缓存架构上也可以加上 CDN。
3.2 总体架构
采用 redis 存储所有的秒杀活动数据,这样可以高性能应对秒杀活动的请求
redis 采用三节点混合部署的方式,节省服务器资源,也可以用 sentinel 保证高可用。
缓存架构采用 4 层缓存架构,去掉了最昂贵的 CDN,因为这个体量还不需要 CDN 出场
负载均衡架构使用 4 层负载均衡架构,去掉了 F5 这最昂贵的一层
在秒杀活动开始前,会将秒杀活动加载到 redis 内进行预热
app 在秒杀进行的时候,会进行 app 端限流,而相应的 nginx 和服务网关层也会进行限流,过滤掉一些流量,最后只剩下大约 1 千左右的请求到秒杀服务器。
4. 详细设计
核心的功能主要有:
用户查看秒杀信息
用户参与秒杀
4.1 核心功能
用户查看秒杀消息
用户参与秒杀
4.2 关键设计
客户端限流
因为秒杀必须要通过 app,所以可以在 app 做限流:秒杀的时候,用户在点击秒杀按钮的时候,app 会生成一个随机数,在一定范围内才会向服务端发送请求,否则根本不会发送请求,在这一步大约会有 10%(4 万)的请求通过 app 向服务端发起请求。如果是 90%的那部分用户,会在这一步就收到秒杀失败的通知。
接入端限流
4 万个左右的请求向 nginx 发起请求。nginx 端接到请求的时候,随机抛弃一部分的请求,这一步大概会有 10%(4000 个)左右的请求真正发向服务网关,剩余的 90%用户会收到秒杀失败的通知,10%的那部分用户会收到“系统处理中,请稍后等待秒杀结果通知”
微服务端限流
在微服务端,使用消息队列接受秒杀的请求。利用漏桶算法,接受最先到达的 X(奖品数量)个请求,最先达到的请求计数使用 redis 里的原子操作来实现。剩余的请求全部丢弃,丢弃的这部分消息会被发送到另一个消息队列,以站内信的形式告知“很遗憾,秒杀失败”,而留下的那部分用户会收到“恭喜您,秒杀成功,订单处理中”的站内通知
4.3 设计规范
秒杀服务使用 Spring Boot + Netty 开发
消息队列使用 Kafka 作为消息队列中间件,因为当前已经在使用 kafka 了
5. 质量设计
秒杀活动管理后台:负责新增和编辑秒杀活动,在目前的管理后台的基础上新增功能。管理后台新增秒杀活动之后,直接写入 redis。redis 有持久化功能,所以不用担心秒杀活动丢失,除非新增完之后立马出现机房断电等极端情况,否则数据不会丢失。
6. 演进规划
6.1 秒杀活动第一期:仅支持程序写入秒杀活动
6.2 秒杀活动第二期:开发管理后台,支持运营人员录入和编辑秒杀活动
注:关于秒杀后的库存处理这块,本设计中不涉及,因为那块是属于之后的物流管理相关的内容。
版权声明: 本文为 InfoQ 作者【红莲疾风】的原创文章。
原文链接:【http://xie.infoq.cn/article/8129215ed0c402a87b46fe0a8】。未经作者许可,禁止转载。
评论