Redis核心技术与实战指南

目录

一、什么是Redis

二、Redis性能高的原因?

三、Redis的持久化方式及优缺点

四、Redis的淘汰策略及适用场景

五、redis核心数据类型有哪些

[1. String 类型(字符串)](#1. String 类型(字符串))

[2. Hash 类型(哈希表)](#2. Hash 类型(哈希表))

[3. List 类型(列表)](#3. List 类型(列表))

[4. Set 类型(集合)](#4. Set 类型(集合))

[5. ZSet 类型(有序集合)](#5. ZSet 类型(有序集合))

最佳实践总结

六、redis如何实现延迟队列

1、实现原理

2、核心代码示例(Java)

3、适用场景

替代方案

七、redis如何实现消息队列

[1. 基于 List 的阻塞队列(最常用)](#1. 基于 List 的阻塞队列(最常用))

[2. Pub/Sub 发布订阅模型(实时通知)](#2. Pub/Sub 发布订阅模型(实时通知))

[3. Stream 类型(高可靠性队列)](#3. Stream 类型(高可靠性队列))

[4. 消息队列的增强方案](#4. 消息队列的增强方案)

[5. 最佳实践与注意事项](#5. 最佳实践与注意事项)

[八、什么是 Redis 缓存穿透?如何解决?](#八、什么是 Redis 缓存穿透?如何解决?)

[九、什么是 Redis 缓存雪崩?它与缓存穿透有何区别?如何解决?](#九、什么是 Redis 缓存雪崩?它与缓存穿透有何区别?如何解决?)

十、什么是Redis缓存击穿

十一、雪崩、穿透、击穿的对比总结

十二、如何保证Redis和数据库的数据一致性?

[1. 核心问题定位](#1. 核心问题定位)

[2. 方案](#2. 方案)

[1). 基础方案:Cache Aside Pattern(旁路缓存模式)](#1). 基础方案:Cache Aside Pattern(旁路缓存模式))

[2). 高并发优化:延迟双删策略](#2). 高并发优化:延迟双删策略)

[3). 分布式系统方案:异步消息队列(MQ)](#3). 分布式系统方案:异步消息队列(MQ))

[4). 自动化方案:订阅Binlog实现最终一致](#4). 自动化方案:订阅Binlog实现最终一致)

5). 极端场景:分布式锁. 极端场景:分布式锁)


一、什么是Redis

Redis是一个开源的、基于内存的高性能Key-Value数据库,支持多种数据结构(字符串、列表、集合、有序集合、哈希等),提供持久化、事务、分布式锁等功能,每秒可处理超10万次读写操作。

二、Redis性能高的原因?

  • 纯内存操作:数据存储在内存中,读写速度极快。

  • 单线程模型:避免上下文切换和锁竞争,使用多路I/O复用(epoll)。

  • 高效数据结构:如跳表(SkipList)、压缩列表(ZipList)优化存储。

三、Redis的持久化方式及优缺点

  • RDB(快照)

    • 优点:文件紧凑,恢复速度快;主进程不影响性能(子进程写入)。

    • 缺点:可能丢失最后一次快照后的数据。

  • AOF(日志追加)

    • 优点:数据安全性高(可配置每秒或每条命令同步)。

    • 缺点:文件体积大,恢复速度慢。

  • 混合模式:结合RDB和AOF,平衡性能与安全性。

四、Redis的淘汰策略及适用场景

策略 说明
noeviction 内存不足时报错,适用于不允许数据丢失的场景
allkeys-lru 淘汰最近最少使用的Key,适用于热点数据场景
volatile-lru 仅淘汰过期集合中的最近最少使用Key,适用于有TTL的数据
allkeys-random 随机淘汰Key,适用于无明确热点数据的场景
volatile-ttl 优先淘汰存活时间(TTL)较短的Key,适用于需要快速释放内存的场景

五、redis核心数据类型有哪些

数据结构 底层实现 典型应用场景
String(字符串) 简单动态字符串(SDS) 缓存用户信息、计数器(如点赞数/访问量)、分布式锁、会话存储、限流控制
List(列表) 双向链表 + 压缩列表(ZipList)/ QuickList(Redis 3.2+) 消息队列、最新动态列表、任务队列、分页查询、实时日志流处理
Hash(哈希) 字典(哈希表)+ 压缩列表(ZipList)/ Listpack(新版) 存储对象属性(如用户信息)、购物车、好友关系、配置中心、实时统计
Set(集合) 整数集合(Intset)或哈希表(当元素为整数且数量少时用Intset,否则用哈希表) 去重(如用户ID去重)、共同好友计算、随机抽奖、权限控制、标签系统
Zset(有序集合) 跳跃表(Skiplist)+ 哈希表 排行榜(如游戏积分、热搜榜)、带权重的任务调度、地理位置排序、实时推荐系统

扩展:

1. String 类型(字符串)

核心命令SET(设置)、GET(获取)、INCR(递增)、DECR(递减)、EXPIRE(设置过期时间)、MSET(批量设置)、MGET(批量获取)
案例代码

java 复制代码
// 设置键值对(带1800秒过期时间)
jedis.setex("user:1001:session", 1800, "active"); // SETEX key seconds value:设置过期时间的字符串
String session = jedis.get("user:1001:session"); // GET key:获取值

// 文章浏览量计数器(原子递增)
long views = jedis.incr("article:1001:views"); // INCR key:值自增1,返回递增后结果(键不存在时初始化为0)
jedis.decr("product:1001:stock"); // DECR key:值自减1

// 批量设置配置项
jedis.mset("config:max_users", "100", "config:timeout", "30"); // MSET key value [key value ...]:一次性设置多个键值对
List<String> values = jedis.mget("config:max_users", "config:timeout"); // MGET key [key ...]:一次性获取多个值

2. Hash 类型(哈希表)

核心命令HSET(设置字段)、HGET(获取字段)、HGETALL(获取所有字段)、HINCRBY(字段递增)、HDEL(删除字段)
案例代码

java 复制代码
// 存储用户信息(对象属性)
jedis.hset("user:1001", "name", "Alice"); // HSET key field value:设置哈希表字段值
jedis.hset("user:1001", "age", "30");
String age = jedis.hget("user:1001", "age"); // HGET key field:获取字段值

// 获取用户所有属性
Map<String, String> user = jedis.hgetAll("user:1001"); // HGETALL key:返回所有字段和值(Map形式)

// 用户积分原子递增
jedis.hincrBy("user:1001", "points", 10); // HINCRBY key field increment:字段值按增量增加(整数)
jedis.hdel("user:1001", "temp_field"); // HDEL key field [field ...]:删除一个或多个字段

3. List 类型(列表)

核心命令LPUSH(左侧插入)、RPUSH(右侧插入)、LPOP(左侧弹出)、RPOP(右侧弹出)、LRANGE(范围查询)、BLPOP(阻塞左侧弹出)
案例代码

java 复制代码
// 消息队列(左侧入队,右侧出队)
jedis.lpush("task_queue", "Task1", "Task2"); // LPUSH key element [element ...]:左侧插入一个或多个元素
String task = jedis.rpop("task_queue"); // RPOP key:右侧弹出一个元素

// 实时日志(存储最新10条)
jedis.lpush("log_messages", "2023-12-10: Error: Disk full");
List<String> logs = jedis.lrange("log_messages", 0, 9); // LRANGE key start stop:获取指定范围的元素(0到9表示前10条)

// 阻塞队列(无数据时等待)
List<String> tasks = jedis.blpop(0, "task_queue"); // BLPOP key [key ...] timeout:阻塞式左侧弹出,0表示无限等待

4. Set 类型(集合)

核心命令SADD(添加元素)、SMEMBERS(获取所有元素)、SCARD(元素数量)、SISMEMBER(检查元素是否存在)、SDIFF(差集)、SINTER(交集)
案例代码

java 复制代码
// 用户标签管理
jedis.sadd("user:1001:tags", "VIP", "Tech", "Gamer"); // SADD key member [member ...]:添加一个或多个元素(去重)
Set<String> tags = jedis.smembers("user:1001:tags"); // SMEMBERS key:获取集合所有元素

// 社交推荐(共同好友)
Set<String> userFriends = jedis.smembers("user:1001:friends");
Set<String> commonFriends = jedis.sinter("user:1001:friends", "user:1002:friends"); // SINTER key [key ...]:交集(共同好友)

// 去重抽奖用户池
long count = jedis.scard("lottery_users"); // SCARD key:获取元素数量
boolean isExist = jedis.sismember("lottery_users", "user1"); // SISMEMBER key member:检查元素是否存在

5. ZSet 类型(有序集合)

核心命令ZADD(添加/更新)、ZRANGE(升序范围查询)、ZREVRANGE(降序范围查询)、ZREM(删除)、ZINCRBY(分数递增)、ZRANK(排名)
案例代码

java 复制代码
// 积分排行榜(升序排列)
jedis.zadd("leaderboard", 1500, "PlayerA"); // ZADD key [NX|XX] [GT|LT] [CH] [INCR] score member:添加成员及分数(可带选项)
jedis.zadd("leaderboard", 1200, "PlayerB");
Set<Tuple> top3 = jedis.zrangeWithScores("leaderboard", 0, 2); // ZRANGE key start stop [WITHSCORES]:升序获取指定范围的成员及分数

// 待办任务(按截止时间排序)
long now = System.currentTimeMillis();
jedis.zadd("tasks", now + 3600000, "Task1"); // 1小时后截止
Set<String> dueTasks = jedis.zrangeByScore("tasks", 0, System.currentTimeMillis()); // ZRANGEBYSCORE key min max:按分数范围查询

// 删除成员并获取排名
jedis.zrem("leaderboard", "PlayerB"); // ZREM key member [member ...]:删除一个或多个成员
Long rank = jedis.zrank("leaderboard", "PlayerA"); // ZRANK key member:获取成员的升序排名(从0开

最佳实践总结

  • 键设计 :采用 业务模块:实体ID:属性 的分层命名(如 user:1001:profile),避免冲突且便于批量操作。

  • 批量操作 :使用 MSET/MGET(String)、PIPELINE(多命令批量)减少网络延迟。

  • 过期时间 :对临时数据(如会话、缓存)设置 EXPIRE,避免内存泄漏。

  • 集群兼容 :在 Redis Cluster 中,通过 {hashTag} 确保同一实体的键落在同一哈希槽(如 order:{1001}:items)。

  • 错误处理 :检查命令返回值(如 INCR 返回新值,SETNX 返回是否成功),避免空指针异常。

六、redis如何实现延迟队列

核心原理

利用Redis的有序集合(Sorted Set,ZSET) ,将任务的执行时间戳 作为score,任务内容作为member。通过定时轮询事件触发获取并处理到期任务。

扩展

1、实现原理

Redis实现延迟队列的核心是有序集合(Sorted Set,ZSET)

  • 成员(member):存储任务标识(如任务ID或序列化后的任务内容)。

  • 分数(score):存储任务的执行时间戳(毫秒级)。

  • 排序机制:ZSET会根据score自动排序,最小score的任务排在队列最前。

  • 轮询机制:通过定时任务(如每秒一次)扫描ZSET,获取score小于等于当前时间的任务,执行后从ZSET中删除。

2、核心代码示例(Java)

java 复制代码
// 添加延迟任务
public void addDelayTask(String taskId, String taskContent, long delaySeconds) {
    long executeTime = System.currentTimeMillis() + delaySeconds * 1000;
    redisTemplate.opsForZSet().add("delay_queue", taskContent, executeTime);
}

// 轮询处理到期任务
public void processDelayTasks() {
    long now = System.currentTimeMillis();
    Set<String> tasks = redisTemplate.opsForZSet().rangeByScore("delay_queue", 0, now);
    if (tasks != null && !tasks.isEmpty()) {
        for (String task : tasks) {
            // 执行任务逻辑(如发送短信、取消订单等)
            System.out.println("Processing task: " + task);
            // 从ZSET中删除已处理的任务
            redisTemplate.opsForZSet().remove("delay_queue", task);
        }
    }
}

3、适用场景

  • 订单超时关闭(如15分钟未支付)。

  • 定时任务重试(如接口调用失败后延迟重试)。

  • 缓存预热、活动提醒等。

替代方案

  • 高可靠性需求:用RabbitMQ(死信队列)或RocketMQ(精确延迟级别)。

  • 大规模延迟消息:用Kafka(时间轮算法)。

七、redis如何实现消息队列

Redis 实现消息队列的核心方式有三种:基于 List 的阻塞队列(最常用)Pub/Sub 发布订阅模型 (实时通知)Stream 类型(高可靠性队列)。

方案 适用场景 优点 缺点
List 阻塞队列 简单任务、短期存储、高并发 简单高效、原子性 无ACK、单消费者限制
Pub/Sub 实时通知、广播、低延迟 零延迟、低开销 无持久化、消息易丢失
Stream 高可靠性、负载均衡、历史回溯 支持ACK、消费者组 性能开销较高
  • 简单场景:优先使用 List 阻塞队列(如日志处理、异步任务)。

  • 实时广播:使用 Pub/Sub(如在线状态更新、实时推送)。

  • 高可靠性要求:选择 Stream(如订单处理、金融交易)。

备注:用 Redis 做消息队列,优点是轻量易部署、性能高、开发简单,缺点是功能单一、可靠性保障弱;专业 MQ 优点是功能丰富、可靠性高、能应对复杂场景,缺点是部署运维复杂、性能开销大。

扩展

1. 基于 List 的阻塞队列(最常用)

原理

  • 使用 Redis 的 List 类型 ,通过 LPUSH(左端插入)和 RPOP(右端弹出)实现 FIFO 队列。

  • 阻塞版本BLPOP/BRPOP 可在队列为空时阻塞等待,避免 CPU 空转。

代码示例

java 复制代码
// 生产者:向队列左端插入任务
jedis.lpush("task_queue", "Task1");
jedis.lpush("task_queue", "Task2");

// 消费者:阻塞式右端弹出(最多等待10秒)
List<String> tasks = jedis.brpop(10, "task_queue");
System.out.println("处理任务: " + tasks.get(1)); // 输出 "Task1" 或 "Task2"

优点

  • 简单高效:单线程架构确保原子性,适合简单任务。

  • 持久化支持:可配置 RDB/AOF 持久化,避免重启后消息丢失。

  • 批量操作 :支持 LPUSH/RPOP 批量插入/弹出,减少网络开销。

缺点

  • 无消息确认:消费者崩溃可能导致消息丢失(需自行实现 ACK 机制)。

  • 单消费者限制 :默认不支持多消费者竞争(可通过 RPOPLPUSH 配合备份队列实现)。

2. Pub/Sub 发布订阅模型(实时通知)

原理

  • 发布者 向频道(Channel)发送消息,订阅者 实时接收。

  • 无持久化:消息仅在订阅时推送,断开连接后消息丢失。

代码示例

java 复制代码
// 订阅者
new Thread(() -> {
    JedisPubSub pubSub = new JedisPubSub() {
        @Override
        public void onMessage(String channel, String message) {
            System.out.println("收到消息: " + message);
        }
    };
    jedis.subscribe(pubSub, "news_channel");
}).start();

// 发布者
jedis.publish("news_channel", "重大新闻:Redis 6.0发布!");

适用场景

  • 实时广播(如在线状态通知、实时日志)。

  • 对消息可靠性要求不高的场景。

3. Stream 类型(高可靠性队列)

原理

  • Redis 5.0+ 引入的 对数结构,支持消息持久化、消费者组(Consumer Group)、消息确认(ACK)和历史消息回溯。

  • 核心概念

    • 消息ID :自动生成的递增ID(如 1630451234567-0)。

    • 消费者组:多个消费者共享队列,每条消息仅被组内一个消费者处理。

    • Pending列表:已发送但未确认的消息,支持重试和超时。

代码示例

java 复制代码
// 生产者:添加消息到Stream
jedis.xadd("order_stream", new StreamEntryID(), Map.of("item", "手机", "price", "3999"));

// 消费者组创建
jedis.xgroupCreate("order_stream", "order_group", new StreamEntryID(), true);

// 消费者:从组内读取消息
Map<StreamEntryID, Map<String, String>> messages = jedis.xreadGroup(
    "order_group", "consumer1",
    StreamEntryID.NEW_ENTRY, 1, 0, "order_stream"
);

// 处理消息后发送ACK
for (Entry<StreamEntryID, Map<String, String>> entry : messages.entrySet()) {
    jedis.xack("order_stream", "order_group", entry.getKey());
}

优点

  • 可靠性高:支持消息确认、重试和持久化。

  • 负载均衡:消费者组自动分配消息,避免重复处理。

  • 历史回溯:可查询任意ID之后的消息。

缺点

  • 性能开销:相比 List 略高,需权衡可靠性与性能。

4. 消息队列的增强方案

(1)死信队列与重试机制

  • 使用 RPOPLPUSH 将消息备份到处理队列的同时,移入备份队列。若处理失败,可将备份队列的消息重新放回主队列。

  • 示例:

    java 复制代码
    // 原子性转移消息到备份队列
    jedis.rpoplpush("task_queue", "backup_queue");

(2)延迟队列

  • 结合 ZSet 实现延迟消息:

    java 复制代码
    // 添加延迟任务(当前时间+10秒后执行)
    long delay = System.currentTimeMillis() + 10000;
    jedis.zadd("delay_queue", delay, "Task1");
    
    // 定时任务检查到期任务
    Set<String> dueTasks = jedis.zrangeByScore("delay_queue", 0, System.currentTimeMillis());

(3)分布式限流

  • 使用 List 配合 INCR 实现令牌桶限流:

    java 复制代码
    // 生成令牌
    jedis.incr("token_bucket");
    jedis.expire("token_bucket", 1); // 每秒重置

5. 最佳实践与注意事项

(1)键设计规范

  • 队列键名采用 业务:模块:队列 格式(如 mq:order:task),便于监控和管理。

  • 避免过长的键名,影响性能。

(2)持久化配置

  • 根据场景选择:

    • RDB:快照持久化,适合对实时性要求不高的场景。

    • AOF :日志追加,适合要求高可靠性的场景(可配置 appendfsync always)。

(3)监控与告警

  • 通过 Redis 的 INFO stats 监控队列长度、处理速率等指标:

    bash 复制代码
    INFO stats | grep keyspace_hits
  • 使用 RedisInsightPrometheus+Grafana 可视化监控。

(4)集群模式

  • 在 Redis Cluster 中,确保同一队列的键落在同一哈希槽(使用 {hashTag}):

    java 复制代码
    jedis.lpush("mq:{order}:task", "Task1"); // 确保order的键在同一槽位

(5)消费者幂等性

  • 通过消息唯一ID(如 Stream 的消息ID)或业务ID(如订单号)确保重复消息不重复处理。

八、什么是 Redis 缓存穿透?如何解决?

概念:缓存穿透指客户端请求的数据在缓存(Redis)和数据库中都不存在,导致每次请求都穿透缓存直达数据库,造成数据库压力过大(甚至宕机)。例如,恶意请求查询不存在的用户 ID(如id=-1)。

解决方案

  • 布隆过滤器:在缓存前添加布隆过滤器,提前过滤不存在的请求。布隆过滤器可快速判断数据是否可能存在,若不存在则直接返回,避免访问数据库。

  • 空值缓存:对查询结果为空的数据,在 Redis 中缓存空值(设置较短过期时间,如 5 分钟),防止相同请求重复穿透。

  • 接口校验:在 API 层对请求参数进行校验(如 ID 必须为正整数),过滤非法请求。

九、什么是 Redis缓存雪崩?它与缓存穿透有何区别?如何解决?

概念:缓存雪崩指大量缓存 key 在同一时间过期,或 Redis 服务宕机,导致所有请求瞬间直达数据库,造成数据库过载。

与缓存穿透的区别

  • 缓存穿透:请求的数据 "本身不存在",导致穿透(高频少量无效请求)。

  • 缓存雪崩:请求的数据 "存在但缓存失效",导致批量请求穿透(低频大量有效请求)。

解决方案

  • 过期时间随机化:为缓存 key 设置过期时间时添加随机值(如expire + Math.random()*1000),避免集中过期。

  • 多级缓存:增加本地缓存(如 Caffeine),减少对 Redis 的依赖,即使 Redis 宕机,本地缓存可临时承接部分请求。

  • 服务熔断 / 限流:使用 Sentinel 或 Hystrix 对数据库请求进行限流,超出阈值则拒绝请求,保护数据库。

  • Redis 集群:部署主从 + 哨兵或 Redis Cluster,避免单点故障导致 Redis 整体不可用。

十、什么是Redis缓存击穿

定义

某个热点Key在缓存中过期时,大量并发请求同时访问该Key,导致所有请求穿透缓存,直接查询数据库,造成数据库压力骤增。

核心特点

  • 针对单个热点Key:问题集中在某一个被高频访问的数据。

  • 并发请求集中:Key过期瞬间,大量请求同时到达。

  • 临时性:问题通常在缓存重建后缓解。

典型场景

电商促销时,某款热门商品的详情缓存过期,瞬间大量用户请求直接查询数据库。

解决方案

  • 互斥锁:重建缓存时加锁,确保只有一个请求访问数据库。

  • 逻辑过期:缓存过期后返回旧数据,后台异步更新。

  • 永不过期:对热点数据不设过期时间,定期后台刷新。

十一、雪崩、穿透、击穿的对比总结

问题类型 成因 影响范围 典型场景 核心解决方案
缓存击穿 单个热点Key过期,并发请求穿透 单个Key,临时性 热门商品详情缓存过期 互斥锁、逻辑过期、永不过期
缓存雪崩 大量Key同时过期或缓存服务崩溃 批量Key,系统性 统一过期时间导致批量失效 分散过期时间、多级缓存、限流降级
缓存穿透 查询不存在的数据,持续穿透 无数据,持续性 恶意攻击或错误参数查询不存在数据 布隆过滤器、缓存空值、接口限流

直观类比

  • 击穿:像"单点爆破"------一个热点Key失效导致局部崩溃。

  • 雪崩:像"连锁反应"------大量Key同时失效导致全面崩溃。

  • 穿透:像"无底洞"------查询不存在的数据,每次请求都直击数据库。

十二、如何保证Redis和数据库的数据一致性?

保证Redis和数据库一致性通常采用Cache Aside(旁路缓存)模式,即读缓存未命中时查数据库并写入缓存,写操作时先更新数据库再删除缓存。为解决删除缓存失败的问题,可以通过消息队列异步重试或监听Binlog触发更新。对于并发更新场景,可以使用分布式锁或版本号控制。此外,Redis集群本身通过主从复制和哨兵模式保证高可用,但需注意异步复制可能导致的短暂不一致。最终,应根据业务容忍度选择强一致性或最终一致性方案。

扩展

1. 核心问题定位

首先明确数据不一致的根源:Redis作为缓存层,与数据库(如MySQL)的更新操作存在时间差,导致并发场景下缓存与数据库数据不一致。常见场景包括:

  • 缓存击穿:热点数据过期后,大量请求直接穿透到数据库。

  • 脏数据:缓存更新失败或顺序错误,导致缓存与数据库数据不同步。

  • 主从同步延迟:数据库主从架构中,从库数据未及时同步,缓存回填旧数据。

2. 方案

旁路缓存模式是基础方案,读写流程简单直接;而其他方案主要针对高并发、分布式、强一致性等场景,对写流程进行了扩展或优化

1). 基础方案:Cache Aside Pattern(旁路缓存模式)
  • 操作流程

    • 读操作:先查缓存,未命中则查数据库,写入缓存后返回。

    • 写操作 :先更新数据库,再删除缓存(而非更新缓存,避免复杂计算)。

  • 优点:实现简单,适合大多数业务场景。

  • 缺点:极端并发下可能出现短暂不一致(如写后立即读)。

  • 适用场景

    • 普通业务(如商品详情页),对一致性要求不高,读多写少。
2). 高并发优化:延迟双删策略
  • 操作流程

    • 读操作:与旁路缓存一致。

    • 写操作 :先删除Redis缓存,再更新数据库,再休眠500ms(休眠时间需大于业务读操作耗时(如通过压测评估)),再次删除缓存。

  • 目的:覆盖第一次删除失败或读请求在休眠期间重建脏缓存的情况。

  • 适用场景

    • 高并发秒杀、热点数据频繁更新的场景(如库存扣减)。
3). 分布式系统方案:异步消息队列(MQ)
  • 操作流程

    • 读操作:与旁路缓存一致。

    • 写操作

      • 更新数据库。

      • 发送消息到Kafka/RabbitMQ。

      • 消费者异步删除缓存。

  • 优点

    • 解耦数据库与缓存操作,提高吞吐量。

    • MQ的重试机制保证消息可靠性。

  • 缺点:引入额外组件,增加系统复杂度。

  • 适用场景

    • 跨服务数据同步(如订单服务更新后通知库存服务删缓存)、分布式系统。
4). 自动化方案:订阅Binlog实现最终一致
  • 技术实现

    • 使用Canal等工具订阅数据库Binlog,解析变更事件。

    • 异步更新或删除缓存。

  • 优点

    • 彻底解耦,无需修改应用代码。

    • 适合高可用分布式系统。

  • 适用场景

    • 需要彻底解耦的复杂系统(如多数据源、多缓存集群)。
5). 极端场景:分布式锁
  • 操作流程

    • 写操作前获取分布式锁(如Redisson),确保同一时间只有一个线程更新数据库和缓存。
  • 优点:避免并发冲突。

  • 缺点:性能开销大,降低系统并发能力。

  • 适用场景

    • 金融交易、核心数据变更等强一致性要求场景。
相关推荐
book多得2 小时前
Redis 大 Key 问题:识别、危害与最优处理方案
java·redis·mybatis
Yeats_Liao2 小时前
时序数据库系列(八):InfluxDB配合Grafana可视化
数据库·后端·grafana·时序数据库
2401_837088502 小时前
缓存更新策略
缓存
就叫飞六吧3 小时前
MySQL不停机迁移完全指南
数据库·mysql
猎人everest3 小时前
Windows系统Redis(8.2.2)安装与配置完整教程
数据库·windows·redis
苦学编程的谢3 小时前
Redis_10_Zset
数据库·redis·缓存
q***42053 小时前
在Spring Boot项目中使用MySQL数据库
数据库·spring boot·mysql
我系真滴菜4 小时前
SQLiteStudio基本操作教程
数据库
CodeAmaz4 小时前
自定义限流方案(基于 Redis + 注解)
java·redis·限流·aop·自定义注解