多级缓存设计实践

news2025/2/5 15:54:34

缓存是什么?

缓存技术是一种用于加速数据访问的优化策略。它通过将频繁访问的数据存储在高速存储介质(如内存)中,减少对慢速存储设备(如硬盘或远程服务器)的访问次数,从而提升系统的响应速度和性能。

缓存的基本原理是:当某个数据被请求时,系统首先检查缓存中是否已存储该数据。如果缓存中存在,则直接返回缓存中的数据,称为“缓存命中”;如果缓存中没有该数据,则从源数据存储(如数据库或远程服务器)中获取数据,并将其存入缓存,以便下次请求时使用。

缓存的常见类型:

  1. 内存缓存:将数据存储在内存中,常见的缓存系统有 Redis 和 Memcached。内存的访问速度远远高于硬盘,因此可以大幅提升性能。

  2. 磁盘缓存:将数据存储在硬盘或 SSD 中,相比内存访问较慢,但可以存储更大量的数据。适用于需要较大存储空间但对速度要求不如内存严格的场景。

  3. 浏览器缓存:网页浏览器会缓存静态资源(如图片、JavaScript 文件等)以减少重复请求,从而提高用户体验和加载速度。

  4. CDN缓存:内容分发网络(CDN)将静态内容缓存到靠近用户的边缘节点,以降低延迟,提高访问速度。

  5. 服务缓存:如Go的本地缓存
  6. MySQL缓存:change buffer 机制,查询缓存机制(已废弃)

性能比较:内存类大于磁盘类,客户端类大于服务端类,近的节点大于远的节点(存储介质&距离)

常见的缓存策略:

  1. LRU(Least Recently Used):当缓存空间不足时,优先淘汰最近最少使用的数据。(冷热数据)

  2. FIFO(First In, First Out):先进先出,最早加入缓存的数据会被优先移除。(新旧数据)

  3. TTL(Time To Live):每个缓存数据都有一个有效期,到期后会被自动清除或重新加载。(定时器机制)

  4. Write-through:每次对缓存进行修改时,同时将数据写入原始数据存储。(双写,保证数据一致性)

  5. Lazy Loading(懒加载):仅当需要时才加载数据到缓存中。(节省资源)

  6. Cache Invalidation(缓存失效):当数据源发生变化时,缓存中的数据需要被标记为无效或更新,以保持数据的一致性。(驱动更新)

示例:

Redis 提供了多种淘汰策略来处理内存达到上限时的情况。以下是 Redis 常见的淘汰策略:

  1. noeviction
    当内存不足时,Redis 不会淘汰任何数据,并且会返回错误。适用于不允许丢失数据的场景。

  2. allkeys-lru
    基于最少最近使用(LRU,Least Recently Used)算法来淘汰最不常用的键。当 Redis 达到内存限制时,会从所有的键中淘汰最少使用的键。

  3. volatile-lru
    只对设置了过期时间的键进行 LRU 淘汰。如果内存不足,Redis 会选择最久未使用的、设置了过期时间的键来删除。

  4. allkeys-random
    随机删除键,适用于在内存不足时,删除任意一个键。

  5. volatile-random
    随机删除设置了过期时间的键。它只删除有过期时间的键,不会影响没有过期时间的键。

  6. volatile-ttl
    根据过期时间(TTL,Time To Live)来淘汰键,选择即将过期的键进行删除。这种策略适用于缓存场景,删除那些快过期的键。

常见的缓存问题:

1. 缓存穿透

缓存穿透是指客户端请求的数据既不在缓存中,也不在数据库中,导致每次请求都直接访问数据库,绕过了缓存。

解决方案

  • 空缓存策略:对于不存在的数据,可以将其在缓存中设置一个空值(如 null 或特殊标记),并设置一个较短的过期时间。这样下次请求相同数据时,可以直接返回空缓存,避免每次都去数据库查询。
  • 缓存过滤:在请求数据前,进行数据验证和过滤(如验证用户输入),确保请求的数据是有效的,减少无效请求。

2. 缓存雪崩

缓存雪崩指的是缓存中的大量数据在同一时间过期,导致大量请求同时访问数据库,造成数据库压力剧增,甚至崩溃。

解决方案

  • 随机过期时间:设置缓存的过期时间时,加上随机偏差,避免多个缓存项在同一时刻过期。
  • 分布式缓存:将缓存分布到多个服务器上,避免单个缓存服务器故障导致整个缓存系统崩溃。
  • 提前加载缓存:根据访问量和数据的热点情况,提前将关键数据加载到缓存中,避免全量加载导致的瞬时压力。

3. 缓存击穿

缓存击穿是指缓存中某个热点数据过期或被删除后,有大量请求同时访问该数据,导致直接访问数据库,从而引发数据库压力过大。

解决方案

  • 加锁或队列机制:在缓存失效时,对该数据加锁或使用队列来保证同一时间只有一个请求去数据库查询并更新缓存,其他请求等待查询结果。
  • 缓存预热:可以在缓存失效前,提前加载或更新缓存,避免缓存失效后直接访问数据库。

4. 缓存一致性问题

缓存与数据库之间的数据可能会出现不一致的情况。例如,数据在数据库中更新了,但缓存没有及时更新,导致用户看到的数据是过期的。

解决方案

  • 缓存失效策略:在数据更新后,立即删除缓存中相应的条目。可以通过应用程序逻辑主动更新缓存,或者设置合适的过期时间。
  • 双写一致性:在对数据库进行修改时,同时修改缓存中的数据,确保缓存和数据库的数据一致性。
  • 延迟一致性:如果严格一致性要求不高,可以允许一定时间内缓存与数据库不一致,稍后通过后台任务同步缓存。

5. 缓存污染

缓存污染是指缓存中存入了错误、无效或不再使用的数据,这些数据会导致缓存效率下降,甚至对应用性能造成影响。

解决方案

  • 数据校验:在将数据写入缓存之前,进行有效性检查,确保缓存的数据是正确的。
  • 定期清理:定期扫描和清理缓存中的无效或过期数据,保持缓存的健康状态。
  • 合理设置缓存过期时间:缓存过期时间应根据数据的变化频率来合理设置,避免缓存存储过多过期或不常用的数据。

6. 缓存并发问题

当多个请求同时访问缓存中的同一数据时,可能会导致缓存更新的冲突,尤其是在高并发场景下,可能会造成缓存不一致或资源竞争。

解决方案

  • 使用锁机制:可以为缓存数据增加锁(如互斥锁),保证同一时间只有一个请求可以更新缓存,避免并发更新冲突。
  • 异步更新:通过异步方式更新缓存,避免长时间的同步阻塞。

7. 缓存击穿和过期

数据缓存的生命周期管理是一个复杂的问题,如果没有合理的策略,缓存中的数据可能在一段时间后过期,导致大量请求直接访问数据库。

解决方案

  • 永不过期的缓存:对于一些不容易发生变化的数据,可以设置为永不过期,避免频繁更新缓存。
  • 使用合适的缓存策略:比如定期刷新缓存、主动更新缓存等,确保缓存始终保持有效。

8. 内存溢出

当缓存数据过多,超出了缓存系统的内存限制时,可能会导致缓存系统发生内存溢出,影响系统的稳定性。

解决方案

  • 限制缓存大小:根据应用的实际需求,设置合适的缓存大小限制,避免缓存过多的数据。
  • LRU(最少最近使用)淘汰策略:对于不常使用的数据,可以采用 LRU 或其他淘汰策略来清理缓存,避免内存溢出。

9. 缓存穿透/渗透与数据泄露

在一些恶意攻击或错误请求的情况下,缓存可能会泄露敏感数据,特别是在没有加密或限制访问控制的情况下。

解决方案

  • 数据加密:对于缓存中的敏感数据进行加密存储,防止数据泄露。
  • 访问控制:根据不同用户权限设置缓存访问策略,防止不合法请求访问敏感数据。

10. 缓存更新延迟

在某些情况下,缓存更新的延迟可能会导致系统反应迟缓,特别是在高并发环境中。

解决方案

  • 异步更新缓存:对于非实时性要求非常高的场景,可以通过异步任务更新缓存,避免阻塞主流程。
  • 批量更新缓存:在数据有大批量变化时,可以采用批量更新策略,而不是频繁更新单条缓存数据。

缓存的优点:

  • 提高性能:通过减少对慢速存储的访问,缓存可以显著加快数据的读取速度。
  • 减轻服务器负担:减少对数据库或其他后端系统的请求,降低它们的负载。
  • 节省带宽:通过缓存远程内容(如网站资源或API响应),减少带宽消耗。

缓存的挑战:

  • 一致性问题:缓存中的数据可能与原始数据不同步,导致数据不一致。通常需要通过策略(如缓存失效、刷新机制)来解决这一问题。
  • 内存占用:缓存使用内存或磁盘存储,会占用一定的资源,需要合理规划和管理。
  • 缓存穿透:恶意用户可能直接绕过缓存,频繁访问源数据,从而导致源系统的压力增加。

为什么要设计多级缓存?什么是CPU的多级缓存?

CPU 多级缓存(Multi-level Cache,简称 L1/L2/L3 Cache)是为了提高 CPU 访问内存的速度而设计的一种缓存层次结构。由于直接从主内存读取数据的速度相对较慢,因此,现代 CPU 采用了多级缓存来加速数据访问,减少访问内存的延迟。CPU 多级缓存通常包括以下几层:

1. L1 缓存(一级缓存)

  • 位置:L1 缓存在 CPU 核心内,距离处理器最接近。
  • 速度:L1 缓存是所有缓存层中速度最快的,通常在几纳秒(ns)级别。
  • 容量:L1 缓存的容量较小,一般在 16KB 到 128KB 之间。
  • 用途:L1 缓存通常分为两个部分:
    • L1 数据缓存:存储数据。
    • L1 指令缓存:存储即将执行的指令。
  • 特点:L1 缓存是最小的,但也最快,主要存储当前正在处理的数据和指令。由于其速度快,L1 缓存的命中率对整体性能影响较大。

2. L2 缓存(二级缓存)

  • 位置:L2 缓存位于 CPU 核心内或与多个核心共享(这取决于 CPU 架构)。
  • 速度:L2 缓存的速度比 L1 缓存稍慢,但仍比主内存快,通常在 10 纳秒左右。
  • 容量:L2 缓存的容量比 L1 大,通常在 128KB 到几 MB 之间。
  • 用途:L2 缓存用于存储从 L1 缓存中淘汰的数据,或者那些 L1 缓存没有命中的数据。它在 L1 缓存和 L3 缓存之间起到了桥梁作用,缓解了 CPU 核心访问主内存时的瓶颈。
  • 特点:L2 缓存要比 L1 大,速度稍慢,但通常每个核心都拥有独立的 L2 缓存。

3. L3 缓存(三级缓存)

  • 位置:L3 缓存通常是多个 CPU 核心共享的缓存层级,它位于 L2 缓存之上,甚至可能在多核处理器中共享给所有核心。
  • 速度:L3 缓存的速度比 L1 和 L2 缓存慢,但仍比访问主内存快,通常在几十纳秒(ns)级别。
  • 容量:L3 缓存的容量最大,一般从几 MB 到几十 MB 不等,具体取决于处理器架构。
  • 用途:L3 缓存用于存储那些在 L1 和 L2 缓存中都未命中的数据,它起到了对多个核心的共享存储作用,帮助缓解访问主内存的压力。
  • 特点:L3 缓存是多个核心共享的,容量大但速度较慢。其设计目的是减少多个 CPU 核心之间的访问冲突和数据不一致。

4. 主内存(RAM)

当缓存(L1、L2、L3)都没有命中时,CPU 会访问主内存(RAM)。虽然主内存的存取速度比缓存慢得多(通常在几十到几百纳秒之间),但它的容量较大,能够存储更多的数据。

5. 缓存命中率和访问延迟

  • 缓存命中率:缓存命中率指的是 CPU 请求的数据在缓存中找到的概率。缓存命中率越高,CPU 能更快地从缓存中获取数据,性能表现越好。
  • 访问延迟:访问延迟是指从 CPU 发出请求到数据返回的时间。L1 缓存的访问延迟最短,而主内存的访问延迟最长。

多级缓存的设计目的

  1. 提高性能:通过层级化缓存,尽量减少 CPU 访问较慢的主内存的次数,从而提高整体计算性能。
  2. 平衡速度和容量:L1 缓存速度最快,但容量小;L3 缓存容量大,但速度较慢。通过层级缓存的设计,可以在速度和容量之间找到平衡。
  3. 减少内存带宽压力:多个级别的缓存减少了 CPU 对主内存的访问,降低了内存带宽的压力,提高了 CPU 处理能力。

多级缓存的业务实现

L1 :客户端缓存(SDK实现-Redis/服务缓存)

L2 :  服务端缓存(本地缓存)

L3:  第三方缓存(Redis)

1、在管理功能进行埋点,持久化DB数据到Redis,保证数据一致性

  • 数据双写 ,先写Redis,再写数据库,数据库失败,则回滚缓存数据(单条记录要加锁)
  • 数据检测脚本,监控redis 数据和数据库的一致性,晚上跑,自动更新修复数据

2、服务缓存- Go使用本地缓存,作为临时缓存挡住一部分请求

  • 缓存时间设置为 1 min ,配置到 Apollo,主要挡住突发流量以及热点数据流量
  • 降级处理,本地缓存失效,走Redis获取,再存储到本地缓存

3、SDK 获取时,在当前服务写缓存,缓存时间5秒

好处:

1、多级缓存机制,保证服务高可用

坏处:

1、增加维护成本

2、数据实时性变差(要看业务能否接受)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

状态模式S

状态模式(State Pattern)是行为设计模式的一种,它允许一个对象在其内部状态发生改变时改变其行为。这个对象被视为类型的有限状态机(Finite State Machine)。 在状态模式中,我们创建表示各种状态的对象和一…

数据结构 (23)并查集与等价类划分

一、并查集 并查集(Union-Find Set或Disjoint Set)是一种数据结构,用于处理一些不相交集合(disjoint sets)的合并及查询问题。它通常表示为森林,并用数组来实现(类似于二叉堆)。在并…

【Linux】开启你的Linux之旅:初学者指令指南

Linux相关知识点可以通过点击以下链接进行学习一起加油! 在 Linux 开发中,GDB 调试器和 Git 版本控制工具是开发者必备的利器。GDB 帮助快速定位代码问题,Git 则提供高效的版本管理与协作支持。本指南将简明介绍两者的核心功能与使用技巧&…

Python语法1

Python语法1 作者:王珂 邮箱:49186456qq.com 文章目录 Python语法1[TOC] 前言一、环境搭建1.1 安装Python解释器1.2 安装第三方包1.3 安装Pycharm1.4 虚拟环境 二、Python语法2.1 基础语法2.1.1 注释2.1.2 变量2.1.3 数据类型2.1.4 关键字和标识符 2.2…

普及组集训--图论最短路径

定义:表示顶点u到顶点v的一条边的权值(边权) 最短路径算法有常见的四种:floyd,dijkstra,Bellman-Ford,SPFA 不过Bellman-Ford并不常用,所以本文不提; 重点在于dijkstr…

蓝桥杯第 23 场 小白入门赛

一、前言 好久没打蓝桥杯官网上的比赛了,回来感受一下,这难度区分度还是挺大的 二、题目总览 三、具体题目 3.1 1. 三体时间【算法赛】 思路 额...签到题 我的代码 // Problem: 1. 三体时间【算法赛】 // Contest: Lanqiao - 第 23 场 小白入门赛 …

前缀和篇——繁星斗斗数字交织中,觅得效率明月辉光(1)

前言 在这片无边无际的数字海洋中,如何从中提取出有价值的讯息,成为了计算机科学中的一项重要课题。前缀和算法,作为一种巧妙的技术,恰如其名——通过计算序列中各个元素的前缀和,能够为我们提供一种高效的查询方式&a…

STM32 HAL库 + LM2904运算放大器 + ADC + VDO温度传感器:电路设计及代码实现

本文将详细介绍如何使用STM32F407的HAL库,实现通过单通道ADC采集VDO温度传感器的信号,并通过串口将采集到的温度值打印输出。具体流程包括:通过分压电阻将获得VDO温度传感器的分压电压,再利用运算放大器LM2904对信号进行放大&…

Python酷库之旅-第三方库Pandas(252)

目录 一、用法精讲 1191、pandas.tseries.offsets.BusinessMonthBegin.n属性 1191-1、语法 1191-2、参数 1191-3、功能 1191-4、返回值 1191-5、说明 1191-6、用法 1191-6-1、数据准备 1191-6-2、代码示例 1191-6-3、结果输出 1192、pandas.tseries.offsets.Busine…

【Linux服务器】CPU问题排查

概述 总体排查思路 总体观察,htop命令观察系统负载程度 检查CPU占用高的进程检查CPU硬件信息是否为问题根源从宏观到细节分析系统IO情况最后检查系统日志 排查思路 系统负载 通过htop命令查看系统负载,通过系统负载可以判断系统是否繁忙,主…

详解MyBatis之篇一

目录 MyBatis 定义 使用MyBatis操作数据库 创建项目 配置 演示 UserInfo.java UserInfoMapper UserInfoMapperTest 数据准备 自动生成测试类 运行结果 MyBatis 定义 MyBatis 是一个优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避…

编译器优化技术

方法内联 逃逸分析 公共子表达式消除 数据边界检查消除

汽车IVI中控开发入门及进阶(三十五):架构QML App Architecture Best Practices

在Qt/QML工程的架构中,架构很重要,虽然本身它有分层,比如QML调用资源文件(图片等)显示GUI界面,后面的CPP文件实现界面逻辑,但是这个分类还有点粗。在实际开发中,界面逻辑也就是基于类cpp的实现,也开始使用各种面向对象的设计模式,实现更加优秀的开发架构,这点尤其在…

本地Docker部署个人在线音乐平台Melody结合内网穿透远程访问听音乐

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

异常--C++

文章目录 一、异常的概念及使用1、异常的概念2、异常的抛出和捕获3、栈展开4、查找匹配的处理代码5、异常重新抛出6、异常安全问题7、异常规范 二、标准库的异常 一、异常的概念及使用 1、异常的概念 异常处理机制允许程序中独立开发的部分能够在运行时就出现的问题进行通信并…

字符串p型编码

字符串p型编码 C 语言实现C 实现Java 实现Python 实现 💐The Begin💐点点关注,收藏不迷路💐 给定一个完全由数字字符(‘0’,‘1’,‘2’,…,‘9’)构成的字符串str,请写出str的p型编码串。例如&…

UIlicious - 自动化端到端测试

在现代软件开发中,测试自动化已然成为产品交付质量的基石。而端到端测试(E2E),作为验证整个应用流畅运行的关键,常常是测试工作中最具挑战性的一环。这时,一款简单高效的自动化测试工具——UIlicious&#…

机器学习:机器学习项目的完整周期

建立一个有价值的机器学习系统时,需要考虑和计划哪些步骤? 以语音识别为例演示机器学习项目的全周期:机器学习项目的第一步是对项目进行范围划分,即决定什么是项目和你想做什么,然后是收集数据,所以决定需…

浪潮X86服务器NF5280、8480、5468、5270使用inter VROC Raid key给NVME磁盘做阵列

Inter VROC技术简介 Intel Virtual RAID on CPU (Intel VROC) 简单来说就是用CPU的PCIE通道给NVME硬盘做Raid 更多信息可以访问官方支持页面 Raid Key 授权,即VROC SKU 授权主要有用的有2个标准和高级,仅Raid1的授权我暂时没见过。 标准 VROCSTANMOD …

ROS基本框架2——在ROS开发中创建并使用自定义消息(C++版本)

ROS基本框架2——在ROS开发中创建并使用自定义消息(C++版本) code review! 参考笔记 1.ROS基本框架1——编写简单的发布者和订阅者(C++和Python版本) 2.ROS基本框架2——在ROS开发中创建并使用自定义消息(C++版本) 文章目录 ROS基本框架2——在ROS开发中创建并使用自定义…