【沉淀笔记】秒杀系统设计

news/2024/11/14 14:35:03/文章来源:https://www.cnblogs.com/rthete/p/18543800

[!NOTE]

在今年的秋招面试中,“秒杀系统”也是本人遇到的一个相对高频考点,所以在秋招结束后,我学习了极客时间的《如何设计一个秒杀系统》课程,并总结了一些要点,面试可从这几点来阐述。

目标 原则
1. 高性能。数据动静分离、热点发现和隔离、请求的削峰和分层过滤、服务端的性能优化。
2. 一致性。减库存方案。
2. 高可用。兜底方案。
1. 数据尽量少
2. 请求数量尽量少(热点发现和处理)
3. 路径尽量短
4. 依赖尽量少
5. 不要有单点

动静分离

热点发现和处理

  • 热点操作:双十一零点下单、添加购物车等。分读请求和写请求处理。
  • 静态热点数据:能够通过卖家报名、数据分析等方式提前预测热点数据。
  • 动态热点数据:系统运行时临时产生的热点数据。

热点数据发现

静态热点数据发现

  1. 卖家报名,通过运营系统提前做缓存。
  2. 数据分析,提前统计TOP N商品。
  3. 缺点:增加卖家使用成本,实时性差不灵活。

动态热点数据发现

构建热点发现系统,收集交易链路上的热点key,将上游发现的热点透传给下游系统,下游系统做热点保护处理。

比如以来上游的导购决策页面,如首页/搜索/商品详情,提前识别热点商品,通过上游系统的中间件收集热点数据,记录到日志中。对日志进行聚合和分析,把符合规则的热点数据通过订阅分发系统推送到相应的下游系统中,进行热点保护(填充到缓存中或应用服务器的内存等等)。

热点发现系统注意点

  1. 热点服务异步抓取热点数据。异步保证通用性,且不影响主流程。
  2. 热点服务发现系统与中间件自身的热点保护模块并存。
  3. 热点发现要接近实时,才能对下游系统做动态的保护。

热点数据处理

三种思路:优化,限制,隔离。

  1. 优化:使用队列,临时缓存热点数据。
  2. 限制:对商品ID做一致性hash分桶,每个分桶设置一个处理队列,可以将热点商品限制在一个请求队列里,防止热点数据影响到其他请求。
  3. 隔离:
    1. 业务隔离:热点请求单独做秒杀业务,卖家报名,提前做预热。
    2. 系统隔离:集群做分组部署,秒杀业务通过单独的域名进行分组隔离。
    3. 数据隔离:启用单独的cache集群或mysql数据库存放热点数据。
    4. 其他:接入层针对URL中的不同path设置限流策略;服务层调用不同的服务接口进行区分;数据层给数据打标进行区分。目的是识别出热点请求。

削峰

三种方式:排队,答题,分层过滤

排队

  • 使用消息队列来缓冲瞬时流量
  • 线程池加锁等待
  • 将请求序列化到文件中顺序读文件

答题

防止秒杀器,延长请求峰值时间。

分层过滤

通过CDN、前台读系统、后台写系统、数据库四层,进行无效请求过滤。需要做数据的分层校验:

  1. 读数据不做强一致性校验,减少瓶颈。
  2. 对写数据进行基于时间的分片,过滤掉过期请求。
  3. 对写请求做限流,将超出系统承载能力的请求过滤。
  4. 对写数据做强一致性校验,只保留有效数据。

在读系统中,尽量减少由于一致性校验带来的系统瓶颈,但是尽量将不影响性能的检查条件提前,如用户是否具有秒杀资格、商品状态是否正常、用户答题是否正确、秒杀是否已经结束、是否非法请求、营销等价物是否充足等;

在写数据系统中,主要对写的数据(如“库存”)做一致性检查,最后在数据库层保证数据的最终准确性(如“库存”不能减为负数)。

性能优化

性能指标和影响因素

性能指标:QPS,响应时间

  1. 总QPS = (1000ms / 响应时间)* 线程数
  2. 响应时间:CPU执行时间+线程等待时间

真正影响性能的因素:CPU执行时间。因为CPU的执行真实消耗了服务器资源。

多线程

线程数不是越多越好,因为线程切换需要成本,每个线程也会耗费一定的内存

线程数配置

  1. 默认配置:线程数 = 2 * CPU 核数 + 1
  2. 线程数 = [(线程等待时间 + 线程 CPU 时间) / 线程 CPU 时间] × CPU 数量
  3. 通过性能测试来找到最佳配置

性能瓶颈

可能产生瓶颈的地方:CPU、内存、磁盘、网络

秒杀系统的瓶颈更多发生在CPU上。

可以通过CPU诊断工具,判断出请求中函数的CPU执行时间,有针对性地优化。

如何判断CPU是否是瓶颈:

看当 QPS 达到极限时,你的服务器的 CPU 使用率是不是超过了 95%,如果没有超过,那么表示 CPU 还有提升的空间,要么是有锁限制,要么是有过多的本地 I/O 等待发生。

优化手段

  1. 减少编码。字符串的IO操作需要将字符转为字节,消耗资源。可以将静态数据提前转换为字节,直接输出字节内容到页面。

  2. 减少序列化。减少RPC调用,将多个应用进行合并部署。

  3. Java优化。做静态化改造,将大部分请求和数据直接在Nginx服务器或web代理服务器上直接返回,Java层只处理少量的动态请求:

    1. 直接使用servlet,避免MVC框架的复杂处理逻辑。
    2. 直接输出流数据。
  4. 并发读优化。解决单点缓存瓶颈:使用应用层Local Cache,在秒杀系统单机上缓存商品相关数据。

    1. 静态数据:类似商品标题和描述,在秒杀开始前全量推送到秒杀机器上,缓存到秒杀结束。
    2. 动态数据:类似库存,采用被动失效缓存一段时间(几秒),失效后再去缓存拉取最新数据。

    数据不一致(超卖)问题?读场景允许一定的脏数据,在真正写数据的时候才会保证一致性。

  5. 其他手段。

    1. 减少数据;
    2. 数据分级,次要信息异步加载;
    3. 减少中间环节;
    4. 做好应用基线……

Servlet是 Java Web 应用的基础组件,直接与 HTTP 请求和响应交互,提供了底层的控制。这意味着开发者需要手动处理请求参数、路由等,负责数据的输入、输出和渲染视图的每一步工作。

性能稍高,因为 Servlet 是底层技术,少了许多框架的封装层,执行效率更高。高并发或性能要求特别高的场景下,直接使用 Servlet 可以减少资源占用。

减库存

减库存的几种方式

  1. 下单减库存。问题:恶意下单不付款,使商品无法正常售卖。
  2. 付款减库存。问题:库存超卖,买家下单成功数远大于库存数量,下单成功却无法付款,买家购物体验差。
  3. 预扣库存,下单时先预扣,在规定时间内不付款再释放库存。问题:没法完全解决恶意下单和库存超卖的现象。
    1. 恶意下单:标记恶意买家、给商品设置最大购买数量、重复下单不付款操作次数限制。
    2. 库存超卖:补货;付款时提示库存不足。

大型秒杀场景的常用策略

  1. 使用“下单减库存”策略,原因:
    1. 秒杀场景下,一般来说成功下单却不付款的情况较少。
    2. 下单减库存相比付款减库存、预扣库存在实现逻辑上更简单,性能上更好。
  2. 保证数据一致性(库存不为负数):
    1. 通过事务来判断,保证库存不为负数,否则回滚。
    2. 设置数据库字段为无符号整数,这样一旦库存为负数,SQL语句执行时就会报错。
    3. 使用CASE WHEN判断语句。

热点数据(库存)的优化

  1. 若减库存逻辑非常单一,可以使用缓存(如redis)完成。
  2. 若减库存逻辑复杂,或需要使用事务,则必须使用数据库。

由于 MySQL 存储数据的特点,同一数据在数据库里肯定是一行存储(MySQL),因此会有大量线程来竞争 InnoDB 行锁,而并发度越高时等待线程会越多,TPS(Transaction Per Second,即每秒处理的消息数)会下降,响应时间(RT)会上升,数据库的吞吐量就会严重受影响。

所以单个热点数据会影响整个数据库的性能。

解决方法:

  1. 应用层排队。按照商品维度设置队列顺序执行(控制单个商品占用数据库连接的数量)。
  2. 数据库层面排队。对mysql innodb做补丁,实现在数据库层面对单行记录做到排队。

兜底

高可用系统建设

阶段 内容
架构阶段 异地容灾,异步化,分组隔离,避免单点
编码阶段 限流保护,超时处理,异步线程,错误捕获
测试阶段 beta测试,自动化对比测试
发布阶段 分批发布,多版本发布
运行阶段 数据对账,自动降级,过载保护,实时监控报警
故障发生 快速恢复,故障定位

降级

  • 当系统的容量达到一定程度时,限制或者关闭系统的某些非核心功能,从而把有限的资源保留给更核心的业务。
  • 通过预案系统和开关系统实现降级。
  • 例子:在双 11 零点时,如果优惠券系统扛不住,可能会临时降级商品详情的优惠信息展示,把有限的系统资源用在保障交易系统正确展示优惠信息上,即保障用户真正下单时的价格是正确的。

限流

  • 客户端限流:在客户端设置阈值,限制请求的发出。难以设置合理的阈值。
  • 服务端限流:可以根据服务端性能设置出合理的阈值。需要额外处理无效的请求。

拒绝服务

  • 当系统负载达到一定阈值时,系统直接拒绝一切请求。
  • 例子:在最前端的 Nginx 上设置过载保护,当机器负载达到某个值时直接拒绝 HTTP 请求并返回 503 错误码,在 Java 层同样也可以设计过载保护。

总结

秒杀系统是为了高并发下保障服务稳定以及用户体验而设计的,该系统的构建主要围绕三个核心目标:高性能、一致性、高可用。

  1. 高性能数据动静分离热点发现和处理是应对高并发的关键手段。通过静态和动态分析提前预测热点商品,将其缓存至合适的位置,减轻服务器负担。同时,为减少服务器压力,系统设计了削峰策略,包括排队、答题、和分层过滤等方式来控制突发流量,确保关键请求能被优先处理。
  2. 一致性:减库存机制是保障数据一致性的关键之一。通过“下单减库存”的方式来实时更新库存,结合库存保护手段(如事务处理和无符号整数字段),可以防止库存变负数,并避免恶意下单对系统的冲击。
  3. 高可用性:为确保秒杀系统在高峰时段的稳定性,采用了异地容灾、限流、降级等措施,保障系统的核心业务。降级策略会在非核心功能负载过大时关闭,保留资源给最核心的交易业务,避免系统宕机。限流拒绝服务策略可有效防止系统过载,通过客户端和服务端双层限流,使秒杀系统在压力下仍能高效地服务用户。

总的来说,秒杀系统的构建是一个从架构、编码到实际运行的全链条过程,通过数据缓存、性能优化、降级容灾等手段应对秒杀场景中的高并发压力,保障系统的稳定性和用户体验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/832950.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【JetBrains CLion 2024软件下载与安装教程】

1、安装包 CLion2024: 链接:https://pan.quark.cn/s/ed93e8cb245e 提取码:fhwc CLion Pro 2021: 链接:https://pan.quark.cn/s/30927a3da509 提取码:1t2w CLion Pro 2018: 链接:https://pan.quark.cn/s/f3a7af5e8ca6 提取码:PW1E 2、安装教程(建议关闭杀毒软件) 1) …

团队项目Scrum冲刺-day2

一、每天举行站立式会议 站立式会议照片一张昨天已完成的工作成员 任务陈国金 用户模块的部分接口开发凌枫 登录页面陈卓恒 管理题目页面的部分代码谭立业 题目搜索页面的部分代码廖俊龙 接口测试曾平凡 前端页面测试曾俊涛 题目模块的部分接口开发薛秋昊 题目提交模块的部分接…

33 张高清大图,带你玩转 KubeSphere 4.1.2 部署与扩展组件安装

备受瞩目的 KubeSphere 4.1.2 已经正式官宣发布,该版本带来了一个重大优化:增加默认的扩展组件仓库。 这一优化改进,让采用全新的 KubeSphere LuBan 架构的 KubeSphere,真正实现了自由打造高度可扩展和可配置的云原生底座。 KubeSphere 用户仅需要在 K8s 之上,默认安装清爽…

cmu15545-数据访问方式:B+树(B+Tree)

目录基本概念基于磁盘的B+树查询与索引设计选择结点大小(Node Size)合并阈值(Merge Thredshold)变长键(Variable-length Keys)结点内部搜索(Intra-Node Search)优化手段Pointer SwizzlingBε-treesBulk InsertPrefix CompressionDeduplicationSuffix Truncation 基本概…

正向代理理解

正向代理(由客户端代理)

冲刺Day1

Day1 当天站立式会议照片姓名 学号 昨天已完成的工作 今天计划完成的工作 工作中遇到的困难林涛(组长) 3122004618 null 开发登录管理员api 如何进行password保密杨森 3122004629 null 后台文件上传开发 如何进行前后端文件上传协调钟礼骏 3122006504 null 查询家长感兴趣模块…

关于电线平方数(截面积)与功率之间关系的对比表格。该表格主要基于电流承载能力(导线的截面积)与相应的功率传输能力。

关于电线平方数(截面积)与功率之间关系的对比表格。该表格主要基于电流承载能力(导线的截面积)与相应的功率传输能力。电线截面积 (mm) 额定电流 (A) 适用功率 (W) (220V 电压) 适用功率 (W) (380V 电压)0.5 mm 5 A 1100 W 1900 W0.75 mm 8 A 1760 W 3040 W1.0 mm 10 A 220…

在线性坐标系中绘制对数函数图象

本文记述了用 Matplotlib 在线性坐标系中绘制对数函数图象的例子。 代码主体内容如下: ...def main():fig, ax = plt.subplots(figsize=(8,8)) #1ax = configure_axes(ax, Logarithmic Function, 8, 3, 1, 0.25, 1, 0.25) #2x = np.linspace(0.125, 8, 100) …

【JetBrains Rider 2024软件下载与安装教程】

1、安装包Rider2024: 链接:https://pan.quark.cn/s/f3b3360dccc0 提取码:Z8gA Rider-2023.3.2: 链接:https://pan.quark.cn/s/82b63a1e0df3 提取码:XdA8 2、安装教程(建议关闭杀毒软件) 1) 双击下载安装包exe文件安装,弹窗安装对话框2) 点击下一步3) …

推荐一个.NetCore开源的CMS项目,功能强大、扩展性强、支持插件的系统!

推荐一个基于.Net Core开发的开源CMS项目,该项目功能完善、涉及知识点比较多,不管是作为二次开发、还是学习都是不错的选择。01 项目简介 Cofoundry是基于.Net开发的、代码优先开发、具备可扩展且灵活的架构、简单易用的内容管理系统。02 项目框架 1、基于.Net 8开发。 2、数…