如何才能更好地理解秒杀系统呢?
一个秒杀系统的架构,包括CDN,反向代理,session共享,由于分布式数据库我不熟,所以数据一致性那部分没有解决。
主要技术点:
(1)缓存
(2)独立秒杀系统、独立集群
(3)验证系统,防秒杀器
主要技术点:
(1)动静分离
(2)本地缓存
(3)热点隔离
权衡点:要想获得极致性能,必然会牺牲通用型、易用性等
动静分离
“动态数据”和“静态数据”的主要区别就是看页面中输出的数据是否和 URL、浏览者、时间、地域相关,以及是否含有 Cookie 等私密数据
第一,你应该把静态数据缓存到离用户最近的地方。
第二,静态化改造就是要直接缓存 HTTP 连接。
第三,让谁来缓存静态数据也很重要。(一般是web服务器来做,而不是应用服务器)
URL 唯一化;分离浏览者相关的因素;分离时间因素;异步化地域因素;去掉 Cookie
动态内容的处理通常有两种方案:ESI(Edge Side Includes)、CSI(Client Side Include)
Cache 分成若干组,是希望能达到命中率和访问热点的平衡。Hash 分组越少,缓存的命中率肯定就会越高,但短板是也会使单个商品集中在一个分组中,容易导致 Cache 被击穿,所以我们应该适当增加多个相同的分组,来平衡访问热点和命中率的问题。
不容易运维;浪费CPU
网卡瓶颈、丢失数据
CDN:失效问题、命中率问题、发布更新问题
二级cache是指cdn设置了多级回源机制,就是如果缓存没有命中再到二级缓存中去取,而不是直接回服务端来请求。本质是减少回源的请求量
二八原则:有针对性地处理好系统的“热点数据”
热点:热点操作(读操作、写操作)、热点数据(静态热点数据、动态热点数据)
热点发现:对于静态热点(人工标识、大数据统计计算),以及实时热点发现方案
热点处理:
(1)优化:缓存、LRU
(2)限制:hash分桶,避免相互影响
(3)隔离:从上到下三个层次,业务隔离、系统隔离、数据隔离
流量削峰
常见做法:
(1)排队-对发出来的请求进行缓冲(消息队列、文件缓存、内存队列、线程池加锁等)
(2)答题-少发请求(两个功效:防止秒杀器;延缓请求,将请求峰值按照时间分片-从1s延长到2~10s)
(3)分层过滤-不符合条件的请求进行过滤(交易性的写请求)
分层校验的目的是:在读系统中,尽量减少由于一致性校验带来的系统瓶颈,但是尽量将不影响性能的检查条件提前,如用户是否具有秒杀资格、商品状态是否正常、用户答题是否正确、秒杀是否已经结束、是否非法请求、营销等价物是否充足等;在写数据系统中,主要对写的数据(如“库存”)做一致性检查,最后在数据库层保证数据的最终准确性(如“库存”不能减为负数)。
极致优化
首先是“发现短板”,比如考虑以下因素的一些限制:光速(光速:C = 30 万千米 / 秒;光纤:V = C/1.5=20 万千米 / 秒,即数据传输是有物理距离的限制的)、网速(2017 年 11 月知名测速网站 Ookla 发布报告,全国平均上网带宽达到 61.24 Mbps,千兆带宽下 10KB 数据的极限 QPS 为 1.25 万 QPS=1000Mbps/8/10KB)、网络结构(交换机 / 网卡的限制)、TCP/IP、虚拟机(内存 /CPU/IO 等资源的限制)和应用本身的一些瓶颈等。
其次是减少数据。事实上,有两个地方特别影响性能,一是服务端在处理数据时不可避免地存在字符到字节的相互转化,二是 HTTP 请求时要做 Gzip 压缩,还有网络传输的耗时,这些都和数据大小密切相关。
再次,就是数据分级,也就是要保证首屏为先、重要信息为先,次要信息则异步加载,以这种方式提升用户获取数据的体验。
最后就是要减少中间环节,减少字符到字节的转换,增加预处理(提前做字符到字节的转换)去掉不需要的操作。
此外,要做好优化,你还需要做好应用基线,比如性能基线(何时性能突然下降)、成本基线(去年双 11 用了多少台机器)、链路基线(我们的系统发生了哪些变化),你可以通过这些基线持续关注系统的性能,做到在代码上提升编码质量,在业务上改掉不合理的调用,在架构和调用链路上不断的改进。
防超卖
减库存的三种时机:
(1)下单后
优点:体验好,不超买
不足:恶意下单
(2)支付后
优点:不会被人恶意刷单
不足:存在付款后超卖的情况
(3)预扣库存(为用户保留一段时间)
优点:一定程度上缓解上面的问题
不足:没有根治,需要结合风控策略来综合考虑
解决大并发读问题,可以采用 LocalCache(即在秒杀系统的单机上缓存商品相关的数据)和对数据进行分层过滤的方式。
像减库存这种大并发写无论如何还是避免不了,这也是秒杀场景下最为核心的一个技术难题
一般的电商系统,通常采用第三种减库存的方式;
而对于秒杀系统,我们更多的采用第一种方式。原因在于:
(1)秒杀系统的商品对库存都有比较严格的管控
(2)下单后不支付的概率比较小
秒杀商品和普通商品的减库存还是有些差异的,例如商品数量比较少,交易时间段也比较短,因此这里有一个大胆的假设,即能否把秒杀商品减库存直接放到缓存系统中实现,也就是直接在缓存中减库存或者在一个带有持久化功能的缓存系统(如 Redis)中完成呢?
应用层做排队。按照商品维度设置队列顺序执行,这样能减少同一台机器对数据库同一行记录进行操作的并发度,同时也能控制单个商品占用数据库连接的数量,防止热点商品占用太多的数据库连接。
数据库层做排队。应用层只能做到单机的排队,但是应用机器数本身很多,这种排队方式控制并发的能力仍然有限,所以如果能在数据库层做全局排队是最理想的。阿里的数据库团队开发了针对这种 MySQL 的 InnoDB 层上的补丁程序(patch),可以在数据库层上对单行记录做到并发排队。
在活动开始之前一段时间,把商品库存放在Redis中。
手段:通过Redis来抗,Lua脚本来完成CAS操作
https://www.yuque.com/chenboxue/kb/gmy24m
高可用建设
运行时:
体验降级:牺牲了一部分次要的功能和用户的体验效果
限流
拒绝服务,避免打死长时间无法恢复
熔断
网站的高可用建设是基础,可以说要深入到各个环节,更要长期规划并进行体系化建设,要在预防(建立常态的压力体系,例如上线前的单机压测到上线后的全链路压测)、管控(做好线上运行时的降级、限流和兜底保护)、监控(建立性能基线来记录性能的变化趋势以及线上机器的负载报警体系,发现问题及时预警)和恢复体系(遇到故障要及时止损,并提供快速的数据订正工具等)等这些地方加强建设,每一个环节可能都有很多事情要做。
设计难点
解决秒杀这种特定业务场景,可以使用 CDN 的边缘结点来扛流量,然后过滤用户请求(限流用户请求),来保护数据中心的系统,这样才让整个秒杀得以顺利进行。
高并发问题
限流:前端限流、后端限流
异步化:要确保进入队列的购买请求一定能处理成功!
防恶意请求
目的:防止被黑产盯上之后通过脚本来请求服务端
解决方案:动态获取秒杀地址