【redis】使用redis作为缓存时所注意事项

缓存更新策略

在 Redis 缓存中,缓存的更新策略主要有**定期生成(定时更新)实时生成(即时更新)**两种方式。不同的策略适用于不同的业务场景,涉及性能、数据一致性和系统负载等方面的权衡。


1. 定期生成(定时更新)

是什么?

定期生成指的是按照固定的时间间隔,主动更新缓存,而不是在数据发生变化时立即更新。这种方式适用于数据变化不频繁、对实时性要求不高的场景。

优点:

降低数据库压力:缓存可以批量更新,避免频繁查询数据库。
提高查询性能:查询时直接读取缓存,响应速度快。
数据一致性较好(相对于长期不更新的缓存):定期更新可以保证数据不会长期过时。

缺点:

数据可能不够实时:在缓存下一次更新前,数据可能已经变化,但缓存仍然返回旧数据。
不适合高实时性业务:如果业务需要频繁变更数据,定期更新可能导致缓存数据滞后。
可能会引起短时流量冲击:如果所有缓存数据同时更新,可能会对数据库造成瞬间压力。

常见实现方式:

  • 定时任务更新缓存Time-based Refresh

    • 使用 Spring Task、Quartz、Crontab 等定时任务,每隔一段时间刷新缓存。
    • 例如,每 10 分钟更新一次缓存:
      @Scheduled(fixedRate = 600000) // 每 10 分钟执行一次
      public void updateCache() {// 查询数据库并更新缓存List<Data> dataList = databaseService.getData();redisTemplate.opsForValue().set("cache:data", dataList);
      }
      

  • 数据库变更时触发缓存更新Database-triggered Refresh

    • 监听 数据库变更事件(MySQL Binlog、PostgreSQL 触发器),检测到数据变化后批量刷新缓存。
  • 异步任务更新

    • 使用消息队列(Kafka、RabbitMQ)通知服务更新缓存,避免定时任务导致的瞬时数据库压力过大。
适用场景:

📌 统计数据、排行榜、热门商品列表等(更新频率较低,数据稍有延迟也无大问题)。
📌 日志分析、报表数据等(数据量大,但对实时性要求不高)。


2. 实时生成(即时更新)

是什么?

实时生成指的是数据发生变更时立即更新缓存,确保缓存数据始终是最新的。这种方式适用于对数据一致性要求高、变更较频繁的场景。

优点:

数据实时性高:缓存的数据始终与数据库保持一致,适用于高实时性需求的应用。
避免缓存不一致问题:数据库变更后立即同步缓存,减少数据不匹配的情况。

缺点:

更新成本高:每次数据变更都需要更新缓存,可能会导致数据库压力增大。
可能导致缓存频繁更新:对于高频变更的数据,频繁更新可能会导致 Redis 负载过重,甚至影响整体性能。
并发问题:多个并发请求可能会导致缓存不一致缓存击穿,需要加锁或使用双写策略。

常见实现方式:

  1. 数据库更新时主动更新缓存Write-through Strategy

    • 在 **数据更新(新增、修改、删除)**时,同时更新数据库和缓存
      public void updateData(Data data) {databaseService.updateData(data); // 更新数据库redisTemplate.opsForValue().set("cache:data:" + data.getId(), data); // 同步更新缓存
      }
      

    • 适用于数据变更不频繁,且一致性要求较高的场景。
  2. 缓存淘汰(Cache Eviction)

    • 在数据库更新后,删除缓存,让下一次查询时重新加载数据:
      public void updateData(Data data) {databaseService.updateData(data); // 更新数据库redisTemplate.delete("cache:data:" + data.getId()); // 删除缓存
      }
      

    • 适用于缓存数据不是热点,数据变更后不需要立即被查询的情况。
  3. 订阅数据库变更Event-based Strategy

    • 使用 消息队列(Kafka、RabbitMQ)Redis 订阅/发布机制,监听数据库变更事件,变更后更新缓存。
  4. 分布式锁(避免缓存并发写入问题)

    • 解决多个请求同时更新缓存导致数据不一致的问题:
      RLock lock = redissonClient.getLock("cache:lock:data:" + data.getId());
      try {if (lock.tryLock(5, TimeUnit.SECONDS)) {databaseService.updateData(data);redisTemplate.opsForValue().set("cache:data:" + data.getId(), data);}
      } finally {lock.unlock();
      }
      

    • 适用于高并发写入场景,防止缓存同时被多个请求覆盖。
适用场景:

📌 订单系统、支付系统、库存管理等(数据必须实时更新,不能有延迟)。
📌 直播、弹幕系统(数据实时变化,需要确保一致性)。


总结:定期生成 vs. 实时生成

策略定期生成(定时更新)实时生成(即时更新)
数据实时性低(有一定延迟)高(数据库更新即缓存更新)
数据库压力低(定期批量更新)高(频繁更新缓存)
缓存命中率高(查询时直接命中缓存)可能较低(某些情况需删除缓存)
适用场景排行榜、统计数据、报表等订单、库存、支付等高一致性业务

总结

  • 定期生成(定时更新) 适用于数据变化不频繁对实时性要求不高的场景,如排行榜、日志分析等。
  • 实时生成(即时更新) 适用于数据变化频繁对一致性要求高的场景,如支付、库存、订单管理等。
  • 在实际应用中,可以结合两种策略,例如:
    • 定期更新 + 变更触发更新:大部分数据定期刷新,关键数据实时更新。
    • 读时更新 + 写时淘汰:查询时自动更新缓存,写入时删除缓存,防止数据不一致。

合理选择缓存更新策略,可以有效提升系统性能,降低数据库压力,并保证数据的一致性。

Redis 作为缓存,存储空间有限,因此需要淘汰数据来保证新数据的存入。Redis 提供了多种缓存淘汰策略(Eviction Policy),用于决定哪些数据需要被删除。下面介绍几种常见的淘汰策略,包括它们的适用场景和优缺点。


缓存淘汰策略

1. 不淘汰策略

1.1 noeviction(拒绝写入)

概念:

当 Redis 内存占满时,不会删除任何已有数据,而是直接返回错误,拒绝新的写入请求。

适用场景:
  • 适用于严格不能丢数据的场景,如任务队列(消息队列)、金融交易等。
  • 适用于 Redis 作为纯数据存储而非缓存时。
优缺点:

数据不会被误删除,保证数据完整性。
可能导致写入失败,影响系统稳定性。


2. 基于 TTL(过期时间)的淘汰策略

2.1 volatile-lru(最近最少使用,TTL 限定)

概念:
  • 只淘汰**设置了过期时间(TTL)**的键。
  • 在这些键中,优先删除最近最少使用(LRU, Least Recently Used)的数据。
适用场景:
  • 适用于部分数据可丢弃的场景,比如 session、短期缓存数据。
  • 适用于需要自动过期控制,但仍希望尽可能保留热点数据的情况。
优缺点:

优先保留常用数据,减少缓存击穿的概率。
如果大部分 key 没有 TTL,可能导致 Redis 直接拒绝写入(相当于 noeviction)。


2.2 volatile-ttl(优先淘汰即将过期的键)

概念:
  • 只淘汰**设置了过期时间(TTL)**的键。
  • 其中剩余寿命最短的键优先被删除。
适用场景:
  • 适用于对数据有明确的生命周期需求的业务,如订单缓存、验证码缓存等。
优缺点:

优先删除即将过期的数据,保证短期缓存的更新。
可能误删仍然有价值的热点数据。


3. 基于数据访问频率的淘汰策略

3.1 allkeys-lru(全局最近最少使用)

概念:
  • 无视 TTL,从所有键中(包括没有设置 TTL 的键),优先淘汰最近最少使用的键。
适用场景:
  • 适用于热点数据更新频繁的场景,如推荐系统、排行榜、搜索结果缓存等。
优缺点:

可以确保常用数据长期保留,提高缓存命中率。
如果热点数据突然减少访问,可能会被错误淘汰。


3.2 allkeys-random(全局随机淘汰)

概念:
  • 无视 TTL,在所有 key 中随机删除某些数据。
适用场景:
  • 适用于缓存数据均匀访问,不需要特定优先级的场景。
优缺点:

简单高效,减少淘汰策略的计算开销。
不够智能,可能淘汰热点数据,降低缓存命中率。


4. 基于数据访问频次的淘汰策略

4.1 volatile-lfu(基于访问频率,TTL 限定)

概念:
  • 只淘汰设置了 TTL 的 key
  • 访问次数最少的键优先被删除(LFU, Least Frequently Used)。
适用场景:
  • 适用于需要根据访问次数保留数据的业务,如热点文章缓存、用户历史记录等。
优缺点:

能够长期保留高频访问数据,淘汰低频数据。
如果大部分数据没有 TTL,可能导致 Redis 拒绝写入(类似 noeviction)。


4.2 allkeys-lfu(全局最不常使用淘汰)

概念:
  • 无视 TTL,从所有键中优先淘汰访问次数最少的键
适用场景:
  • 适用于热点数据访问有明显差异的情况,如新闻热点推荐、热门产品缓存等。
优缺点:

能保留长期热点数据,提高缓存命中率。
短期热点数据可能无法及时替换,导致数据更新滞后。


总结

策略机制适用场景优点缺点
noeviction拒绝写入不能丢数据(消息队列、金融)数据安全容易写满导致错误
volatile-lru仅淘汰 TTL 数据,LRU需自动过期,保留热点数据减少缓存击穿仅适用于部分数据有 TTL
volatile-ttl仅淘汰 TTL 数据,剩余寿命短的优先订单缓存、验证码优先清理即将失效的缓存可能误删热点数据
allkeys-lru全局 LRU 淘汰访问频率高的缓存(推荐系统)提高缓存命中率可能误删突然冷却的热点数据
allkeys-random随机淘汰数据访问均匀的缓存计算开销小可能淘汰重要数据
volatile-lfu仅淘汰 TTL 数据,访问最少的优先需要根据访问频率保留数据长期热点数据保留仅适用于有 TTL 的 key
allkeys-lfu全局 LFU 淘汰热点明显的数据(新闻、直播)缓存命中率高短期热点更新慢

如何选择淘汰策略?

1. 数据不能丢失(消息队列、金融)

noeviction(拒绝写入)

2. 仅淘汰过期数据(业务数据自动失效)

volatile-lru(保留热点)
volatile-ttl(优先清理快过期数据)

3. 需要智能保留高频访问数据

allkeys-lru(最近最少使用淘汰)
allkeys-lfu(最少使用淘汰)

4. 访问数据均匀,不关心淘汰顺序

allkeys-random(随机删除)

5. 业务需要权衡 LRU 和 LFU

  • 短期热点多,选 LRU
  • 长期热点多,选 LFU

结论

  • 如果数据有 TTL,且希望优先淘汰冷数据,选 volatile-lru / volatile-lfu
  • 如果所有数据都可以被淘汰,选 allkeys-lru / allkeys-lfu
  • 如果只允许写满后拒绝写入,选 noeviction
  • 如果对淘汰规则无特别要求,选 allkeys-random

正确选择淘汰策略,可以有效提高缓存命中率,降低数据库压力,保障系统稳定性。

常见缓存问题

在 Redis 中,缓存预热、缓存穿透、缓存雪崩和缓存击穿是常见的缓存问题。下面分别描述它们的概念及解决方案:


1. 缓存预热(Cache Warming)

是什么?

缓存预热是指在系统启动或运行之前,提前将热点数据加载到缓存中,以减少数据库的查询压力,提高系统访问速度。

如何解决?
  • 手动加载:在服务启动时,手动将热点数据写入缓存。
  • 定时刷新:通过定时任务(如 Spring Task、Quartz 等)定期加载热点数据到缓存。
  • 数据变更同步:监听数据库更新(如 MySQL binlog、Redis 订阅发布机制),在数据变化时同步更新缓存。
  • 批量加载:使用 Redis 的 pipelinemset 命令批量写入缓存,提高加载效率。

2. 缓存穿透(Cache Penetration)

是什么?

缓存穿透指的是大量请求查询不存在的数据,导致每次请求都要查询数据库,缓存完全失效,给数据库带来巨大压力。

如何解决?
  • 缓存空值:如果查询的数据不存在,可以将空值(如 null{})存入缓存,并设置较短的过期时间,避免重复查询数据库。
  • 布隆过滤器(Bloom Filter):使用布隆过滤器提前判断某个 key 是否可能存在,如果一定不存在,则直接返回,不查询数据库。
  • 参数校验:在请求层对参数进行校验,避免无效请求进入系统。
  • 限流与黑名单:对异常请求 IP 进行封禁或限流,避免恶意攻击。

3. 缓存雪崩(Cache Avalanche)

是什么?

缓存雪崩指的是大量缓存同时失效,导致短时间内大量请求直接打到数据库,造成数据库压力激增,甚至宕机。

如何解决?
  • 缓存过期时间随机化:为缓存设置不同的过期时间,避免大量缓存同时失效,例如使用 TTL = 基础时间 ± 随机时间
  • 热点数据提前预加载:在缓存即将过期前,主动刷新缓存,保证热点数据始终可用。
  • 双层缓存:使用 Redis + 本地缓存(如 Caffeine、Guava Cache),降低对 Redis 的依赖。
  • 流量削峰
    • 限流:使用限流算法(如令牌桶、漏桶)限制访问速率。
    • 降级:当数据库压力过大时,返回默认值或降级处理。

4. 缓存击穿(Cache Breakdown)

是什么?

缓存击穿指的是某个热点 key 突然失效,导致大量并发请求直接打到数据库,造成数据库短时间内压力剧增。

如何解决?
  • 设置热点数据永不过期:对于热点数据,直接不设置过期时间,而是由业务逻辑主动更新缓存。
  • 互斥锁(分布式锁)
    • 当缓存失效时,多个请求只允许一个线程查询数据库并更新缓存,其他线程等待缓存更新完成后再读取。
    • 具体实现:使用 SETNX(Redis 分布式锁) 或 Redisson。
  • 提前刷新缓存
    • 通过异步线程提前更新即将过期的热点缓存,防止突然失效。
    • 例如:使用 Redis + 过期监听,在 key 即将过期前主动更新缓存。

总结

问题现象解决方案
缓存预热缓存刚启动时,没有数据手动加载、定时刷新、监听数据变更
缓存穿透查询的 key 在数据库中不存在,每次都查数据库缓存空值、布隆过滤器、参数校验、黑名单
缓存雪崩大量 key 同时失效,数据库压力激增过期时间随机化、双层缓存、限流、降级
缓存击穿某个热点 key 失效,大量请求打到数据库热点数据永不过期、分布式锁、提前刷新

这四个缓存问题都是分布式系统中必须重点关注的,合理的缓存策略可以有效提升系统的性能和稳定性。

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

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

相关文章

计算机网络:计算机网络的分类

按分布范围分类&#xff1a;广域网&#xff0c;城域网&#xff0c;局域网&#xff0c;个域网 按传输技术分类&#xff1a;广播式网络&#xff0c;点对点网络 按拓扑结构分类&#xff1a;总线型&#xff0c;环形&#xff0c;星形&#xff0c;网状 按传输介质分类&#xff1a;…

解决pip安装uv时下载速度慢

验证优化效果 方案 1&#xff1a;临时使用国内镜像源&#xff08;推荐&#xff09; pip install uv -i https://pypi.tuna.tsinghua.edu.cn/simple 速度提升&#xff1a;镜像源服务器位于国内&#xff0c;带宽充足&#xff0c;通常可达 1-10MB/s 支持源列表&#xff1a; # 清…

SpringCloud Alibaba——入门简介

一、是什么 &#xff08;1&#xff09;诞生 2018.10.31&#xff0c;Spring Cloud Alibaba 正式入驻了 Spring Cloud 官方孵化器&#xff0c;并在 Maven 中央库发布了第一个版本 &#xff08;2&#xff09;介绍 &#xff08;3&#xff09;&#xff1f;何为必须组件 二、能干嘛…

Python完全指南:从基础到实践的编程艺术

引言&#xff1a;数字时代的瑞士军刀 在人工智能与大数据浪潮中&#xff0c;Python如同编程世界的"瑞士军刀"&#xff0c;以其优雅的语法和强大的生态征服全球开发者。本文将从语言哲学到实战应用&#xff0c;为您展开Python编程的全景画卷&#xff0c;揭示这门语言…

Docker 运行 GPUStack 的详细教程

GPUStack GPUStack 是一个用于运行 AI 模型的开源 GPU 集群管理器。它具有广泛的硬件兼容性&#xff0c;支持多种品牌的 GPU&#xff0c;并能在 Apple MacBook、Windows PC 和 Linux 服务器上运行。GPUStack 支持各种 AI 模型&#xff0c;包括大型语言模型&#xff08;LLMs&am…

完整例子和调用关系qt OpenGL

项目结构 首先&#xff0c;你需要在 Qt 项目中创建一个类&#xff0c;继承自 QOpenGLWidget 来进行 OpenGL 渲染。文件结构如下&#xff1a; - main.cpp - MyOpenGLWidget.h - MyOpenGLWidget.cpp - vertex_shader.glsl - fragment_shader.glsl 1. main.cpp 这是 Qt 项目的入口…

VSCode 配置优化指南:打造极致高效的前端开发环境

VSCode 配置优化指南&#xff1a;打造极致高效的前端开发环境 一、基础环境配置&#xff1a;让开发更流畅 1. 性能优化设置 // settings.json {"files.autoSave": "afterDelay", // 自动保存&#xff08;延迟1秒&#xff09;"files.exclud…

源IP泄露后如何涅槃重生?高可用架构与自动化防御体系设计

一、架构层解决方案 1. 高防代理架构设计 推荐架构&#xff1a; 用户 → CDN&#xff08;缓存静态资源&#xff09; → 高防IP&#xff08;流量清洗&#xff09; → 源站集群&#xff08;真实IP隐藏&#xff09; ↑ Web应用防火墙&#xff08;WAF&#xff09; 实施要点&a…

【英伟达AI论文】多模态大型语言模型的高效长视频理解

摘要&#xff1a;近年来&#xff0c;基于视频的多模态大型语言模型&#xff08;Video-LLMs&#xff09;通过将视频处理为图像帧序列&#xff0c;显著提升了视频理解能力。然而&#xff0c;许多现有方法在视觉主干网络中独立处理各帧&#xff0c;缺乏显式的时序建模&#xff0c;…

无障碍阅读(Web Accessibility)NVDA打开朗读查看器后,enter键不生效的原因

用NVDA测试Web Accessibility时&#xff0c;打开朗读查看器&#xff0c;enter键会无效&#xff0c;而不打开测试器&#xff0c;就没有问题&#xff0c;很大原因是被应用的元素不是可聚焦的&#xff0c;解决方法尝试&#xff1a; 将标签改为可聚焦的语义化标签&#xff0c;如 b…

2Android中的AIDL是什么以及如何使用它

一、Android中的AIDL概述 AIDL&#xff08;Android Interface Definition Language&#xff09;是Android系统中用于定义和实现跨进程通信&#xff08;IPC&#xff09;接口的语言。它允许一个进程向另一个进程发送请求并获取响应&#xff0c;是Android中实现进程间通信的一种重…

Python绘制数据分析中经典的图形--列线图

Python绘制数据分析中经典的图形–列线图 列线图是数据分析中的经典图形&#xff0c;通过背后精妙的算法设计&#xff0c;展示线性模型&#xff08;logistic regression 和Cox&#xff09;中各个变量对于预测结果的总体贡献&#xff08;线段长短&#xff09;&#xff0c;另外&…

leetcode【面试经典150系列】(一)

目录 121.买卖股票最佳时机 题目描述 示例 算法分析 代码(python3) 122.买卖股票最佳时机II 题目描述 示例 算法分析 代码&#xff08;python3&#xff09; 55.跳跃游戏 题目描述 示例 算法分析 代码 45.跳跃游戏II 题目描述 示例 算法分析 代码 121.买卖股票…

为什么会出现redis数据库?redis是什么?

什么是 Redis? 为什么要用 Redis? 下面我将从 Redis 出现的背景、Redis 的解决方案个来回答。 1、Redis 出现的背景 互联网的应用越来越多&#xff0c;例如社交网络、电商、实时服务发展的十分迅速&#xff0c;这就导致了传统技术栈&#xff08;如关系型数据库&#xff09;…

Windows 11下Git Bash执行cURL脚本400问题、CMD/PowerShell不能执行多行文本等问题记录及解决方案

问题 在Postman里可成功执行的POST请求&#xff1a; 找到Postman的Code 因为cURL基本上算是行业标准&#xff0c;所以Postman默认选中cURL&#xff0c;支持切换不同的开发语言&#xff1a; 点击上图右上角的复制按钮&#xff0c;得到cURL脚本。 Windows 11家庭版&#xff…

Docker基础入门(一)

初识Docker 什么是Docker Docker是一个快速交付应用、运行应用的技术&#xff1a; 可以将程序及其依赖、运行环境一起打包为一个镜像&#xff0c;可以迁移到任意Linux操作系统运行时利用沙箱机制形成隔离容器&#xff0c;各个应用互不干扰启动、移除都可以通过一行命令完成&…

容器编排革命:从 Docker Run 到 Docker Compose 的进化之路20250309

容器编排革命&#xff1a;从 Docker Run 到 Docker Compose 的进化之路 一、容器化部署的范式转变 在 Docker 生态系统的演进中&#xff0c;容器编排正从“手动操作”走向“自动化管理”。根据 Docker 官方 2023 年开发者调查报告&#xff0c;78% 的开发者已采用 Docker Compo…

c++ 嵌入汇编的方式实现int型自增

x86/x86_64 实现 x86 平台上&#xff0c;使用 LOCK XADD 指令来实现原子自增&#xff1a; #include <iostream>inline int atomic_increment_x86(int* value) {int result;__asm__ __volatile__("lock xaddl %1, %0": "m"(*value), "r"(…

区块链与去中心化技术

区块链与去中心化技术 核心进展 区块链从加密货币&#xff08;如比特币&#xff09;扩展至智能合约和供应链管理。以太坊2.0引入分片技术提升交易吞吐量&#xff0c;而零知识证明&#xff08;ZKP&#xff09;增强了隐私保护15。企业级应用如IBM的Food Trust平台通过区块链追踪…

逐梦DBA:Linux环境下 MySQL 的卸载

1. 查看是否安装过MySQL&#xff0c;如果不存在&#xff0c;则不显示任何内容 rpm -qa | grep -i mysql # -i 忽略大小写 2. 查看MySQL服务状态 systemctl status mysqld.service 3. 关闭 mysql 服务 systemctl stop mysqld.service 4. 查看当前 mysql 卸载状况 rpm -qa…