秒杀 :千万别忘了预热这一步

👈👈👈 欢迎点赞收藏关注哟

首先分享之前的所有文章 >>>> 😜😜😜
文章合集 : 🎁 juejin.cn/post/694164...
Github : 👉 github.com/black-ant
CASE 备份 : 👉 gitee.com/antblack/ca...

一. 前言

这周一直在玩AI绘画,蛮好玩的,所以其他的就不深入了,主要走一篇秒杀的流程点。

预热是在整个秒杀环节中很容易忽视,但是非常重要的一环,千万不要小瞧这一步的作用

二. 为什么要预热

2.1 预热包含哪些内容

预热主要是对数据和应用的预热,主要包括2个大的板块 :

  • 数据预热 :主要是在工具层面进行预热,包括 MySQL 页缓存的预热, ES fileCache 的预热
  • 应用预热 :主要是对业务里面的高频数据进行缓存初始化,把这些缓存更新到缓存系统中

2.2 为什么要去预热这些数据?

原因一: 基于不同存储介质的性能差距

内存的速度是远大于磁盘的,哪怕固态存储,在读写速度上,内存也是遥遥领先。

部分组件例如 MySQL 会将数据存储到磁盘中,使用时加载到内存中进行处理。

java 复制代码
// 快多少 ? 
按照资料里面说的,内存大概会比 SSD 快 10~1000倍

// 小扩展 :为什么内存比磁盘快 ?
- 硬件的读写速度导致内存读写在基础层面就更快
- 内存不需要磁盘寻址,支持随机IO (主要针对于机械硬盘)
- CPU 在访问存储介质时,时可以直接访问到第一层存储介质 (内存,寄存器,高速缓存)
    - SSD所处的下一层是要通过内存中转的

原因二 :基于组件逻辑的回表方式

上面说原因一的时候提到了一点,一般存储到硬盘上的数据在处理的时候会放在内存里面 (当然Redis是直接内存中处理)。

如果在不预热的情况下,读取一个数据需要以下几个步骤 :

  • S1 : 查询内存缓存中是否有数据
  • S2 : 从磁盘中通过索引等手段查询到数据,将数据加载到内存中
  • S3 : 在内存中处理数据并且返回(内存中的数据暂时被作为缓存存在)
  • S4 : 查询当前数据后面的数据 ,如果在缓存中 (MySQL中一页一页获取数据)则直接返回,否则去磁盘继续执行 1-3步骤

这里面涉及到一个关键点 :以 MySQL 为主的组件通常是一页页的拉取数据,这是基于其数据存储方式的原因,所以连续读写的时候不需要再回存储进行查询了。

原因三 : 随机 IO 和 顺序 IO 带来的性能差距

有的人可能听过这,但是没有太过理解。顺序和随机带来的性能损耗是非常大的。

有很多数据结构为了使用顺序读写带来的优势,在底层结构上都会通过双向链表将连续数据串联起来。

如果是 SSD 则相对还好,如果是磁盘,则每一次随机读写都需要磁盘重新寻址,重新查找数据。

而数据预热在我看来就是把磁盘上的随机数据全部加载到内存中,形成一套虚拟的顺序数据,减少寻址和磁盘查询的时间

三. 预热的方案

3.1 应用层面的预热

应用层面的预热就比较简单了 ,主要是把热点数据筛选出来放在缓存中,不过可以考虑是 :缓存是可以分本地和远端的。

单独说这个是因为 : Redis 调用的耗时其实一点也不低,基本类型的调用都会花费 2-3ms , 而数据量越大,这个耗时就会越多。

简单算下, 哪怕平均耗时10秒 ,那么100万数据就得在这个上面花费1万秒,我们确实可以通过 Redis 的IO复用以及吞吐让这个1万秒均摊到不同的路上面,但是时间确实花出去了

👉 但是如果说用本地缓存呢 ?

我们提前把数据预热到本地内存中,这些数据本身不会发生变动(当然也可以通过通知等手段来更新这类变化)。

本地缓存的方案有很多,可以通过定时任务 + 时间轮来进行过期。可以通过软引用等方式来保证应用缓存不会影响整体堆大小。使用也很简单,没有更新的情况下用个基础Map就足够了。

  • 软引用(Soft Reference): 软引用用于描述还有用但非必须的对象。当 Java 虚拟机内存不足时,才会对这些对象进行回收。

👉 👉 这也是我们经常说到的二级缓存。

3.2 数据预热

数据预热就多了,但是根源就是让对应的数据源对数据进行缓存。

MySQL

MySQL 的数据预热主要是对 InnerDB 缓冲池进行预热 ,让在秒杀来临之前,将常用的数据加载到缓冲池中,以减少磁盘 I/O 操作,提高查询性能。

MySQL 预热可以不像 Redis 一样通过业务预执行的方式进行预热,可以直接通过 SQL 对全表进行预热 (全表量会稍大,要视情况而定)。

java 复制代码
select  count(*) from user;

// 补充知识点一 : innodb_buffer_pool 
- innodb_buffer_pool 是一个内存区域,用于缓存被频繁读取的数据和索引
- innodb_buffer_pool 中存储的是 InnerDB 的数据页,数据页本身也是为了减少磁盘读取
- innodb_buffer_pool_size 配置用于设置该空间的大小

// 问题和思考 :
- innodb_buffer_pool 是有大小限制的,一般也就几G的容量
- 如何才能更好的缓存需要的数据值得思考,一张 user 表肯定没办法全量缓存

// 数据没有得到预热的直接表现 : 
- 缓冲池占用低, 内存占用低
- 在日常使用中 , 内存占用可能30%都不到,不进行预热会导致使用率低

ElasticSearch

ES 其实预热的需求不大,因为本身就是基于内存操作。

而且ES主要针对事后查询,在我看来预热的场景不多。

但是效果是一样的,ElasticSearch 一样有查询缓存,相同的思路进行处理即可。

Redis 预热

Redis 预热在上面的业务处理中就已经提到了,一般情况下我们也是通过业务代码的形式去处理。

一般最简单的就是把相关流程预跑一下,其他的都视各自情况而定吧。

总结

预热这一步是整个秒杀或者高并发操作的前提,做完这一步后,秒杀的前置处理流程就基本上完成了。

关联文档 :

以下是整个秒杀系列涉及到的文章 :

秒杀 :用CDN把请求处理在服务器之外

秒杀 : 做一个完善的全链路日志实现方案有多简单

秒杀 :负载均衡--为什么他们开口就说百万并发

花20分钟白嫖一整套 DevOps 发布方案

再次白嫖 ,30分钟搭建自己的 DevOps + K8S 集群

随笔 : 不怎么优雅的 K8S 拉取 Docker 私服镜像流程

相关推荐
mghio1 小时前
Dubbo 中的集群容错
java·微服务·dubbo
Asthenia04121 小时前
Spring AOP 和 Aware:在Bean实例化后-调用BeanPostProcessor开始工作!在初始化方法执行之前!
后端
Asthenia04122 小时前
什么是消除直接左递归 - 编译原理解析
后端
Asthenia04122 小时前
什么是自上而下分析 - 编译原理剖析
后端
Asthenia04123 小时前
什么是语法分析 - 编译原理基础
后端
Asthenia04123 小时前
理解词法分析与LEX:编译器的守门人
后端
uhakadotcom3 小时前
视频直播与视频点播:基础知识与应用场景
后端·面试·架构
拉不动的猪3 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪3 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试